diff --git a/app/assets/images/pages/account/profile/sample_profile.png b/app/assets/images/pages/account/profile/sample_profile.png new file mode 100644 index 000000000..b61294854 Binary files /dev/null and b/app/assets/images/pages/account/profile/sample_profile.png differ diff --git a/app/assets/images/pages/account/profile/sample_profile_thumb.png b/app/assets/images/pages/account/profile/sample_profile_thumb.png new file mode 100644 index 000000000..bc1e63e13 Binary files /dev/null and b/app/assets/images/pages/account/profile/sample_profile_thumb.png differ diff --git a/app/lib/sprites/SpriteParser.coffee b/app/lib/sprites/SpriteParser.coffee index ce5b08f4b..3138bb47b 100644 --- a/app/lib/sprites/SpriteParser.coffee +++ b/app/lib/sprites/SpriteParser.coffee @@ -114,9 +114,11 @@ module.exports = class SpriteParser @animationRenamings[shortKey] = name else shortKey = name + if @thangType.animations[shortKey]? + shortKey = @animationName + ":" + name @thangType.animations[shortKey] = animation @animationLongKeys[longKey] = shortKey - @animationRenamings[name] = name + @animationRenamings[name] = shortKey return shortKey walk: (node, parent, fn) -> @@ -188,9 +190,8 @@ module.exports = class SpriteParser lastRect = bounds else if arg.type is 'Literal' and arg.value is null bounds = [0, 0, 1, 1] # Let's try this. - frameBounds.push bounds + frameBounds.push _.clone bounds else - console.log "Didn't have multiframe bounds for this movie clip!" frameBounds = [nominalBounds] # Subtract half of width/height parsed from lib.properties diff --git a/app/lib/storage.coffee b/app/lib/storage.coffee index 78ea56111..21e8d59a9 100644 --- a/app/lib/storage.coffee +++ b/app/lib/storage.coffee @@ -5,7 +5,7 @@ module.exports.load = (key) -> value = JSON.parse(s) return value catch SyntaxError - console.warning('error loading from storage', key) + console.warn('error loading from storage', key) return null module.exports.save = (key, value) -> diff --git a/app/lib/surface/Mark.coffee b/app/lib/surface/Mark.coffee index 8a42b3272..3d01a2ee5 100644 --- a/app/lib/surface/Mark.coffee +++ b/app/lib/surface/Mark.coffee @@ -93,6 +93,7 @@ module.exports = class Mark extends CocoClass @lastHeight = @sprite.thang.height buildShadow: -> + alpha = @sprite.thang?.alpha ? 1 width = (@sprite.thang?.width ? 0) + 0.5 height = (@sprite.thang?.height ? 0) + 0.5 longest = Math.max width, height @@ -103,7 +104,7 @@ module.exports = class Mark extends CocoClass height *= Camera.PPM * @camera.y2x # TODO: doesn't work with rotation @mark = new createjs.Shape() @mark.mouseEnabled = false - @mark.graphics.beginFill "black" + @mark.graphics.beginFill "rgba(0, 0, 0, #{alpha})" if @sprite.thang.shape in ['ellipsoid', 'disc'] @mark.graphics.drawEllipse 0, 0, width, height else diff --git a/app/locale/ar.coffee b/app/locale/ar.coffee index 500208cb5..3c650e49e 100644 --- a/app/locale/ar.coffee +++ b/app/locale/ar.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "العربية", englishDescription: "Arabi # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "العربية", englishDescription: "Arabi # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/bg.coffee b/app/locale/bg.coffee index d760b50a6..7ce8698c0 100644 --- a/app/locale/bg.coffee +++ b/app/locale/bg.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "български език", englishDescri # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "български език", englishDescri # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/ca.coffee b/app/locale/ca.coffee index bb30b9fa6..1d671de6f 100644 --- a/app/locale/ca.coffee +++ b/app/locale/ca.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "Català", englishDescription: "Catalan", tr # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "Català", englishDescription: "Catalan", tr # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/cs.coffee b/app/locale/cs.coffee index e164b62e1..8d3c43d49 100644 --- a/app/locale/cs.coffee +++ b/app/locale/cs.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "čeština", englishDescription: "Czech", tr # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: av_title: "Administrátorský pohled" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "čeština", englishDescription: "Czech", tr # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/da.coffee b/app/locale/da.coffee index 56d36167d..e81fa0955 100644 --- a/app/locale/da.coffee +++ b/app/locale/da.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/de-AT.coffee b/app/locale/de-AT.coffee new file mode 100644 index 000000000..5ef340fbc --- /dev/null +++ b/app/locale/de-AT.coffee @@ -0,0 +1,671 @@ +module.exports = nativeDescription: "Deutsch (Österreich)", englishDescription: "German (Austria)", translation: + common: + loading: "Lade..." +# saving: "Saving..." +# sending: "Sending..." +# send: "Send" +# cancel: "Cancel" +# save: "Save" +# publish: "Publish" +# create: "Create" +# delay_1_sec: "1 second" +# delay_3_sec: "3 seconds" +# delay_5_sec: "5 seconds" +# manual: "Manual" +# fork: "Fork" +# play: "Play" +# retry: "Retry" + +# units: +# second: "second" +# seconds: "seconds" +# minute: "minute" +# minutes: "minutes" +# hour: "hour" +# hours: "hours" + +# modal: +# close: "Close" +# okay: "Okay" + +# not_found: +# page_not_found: "Page not found" + +# nav: +# play: "Levels" +# editor: "Editor" +# blog: "Blog" +# forum: "Forum" +# admin: "Admin" +# home: "Home" +# contribute: "Contribute" +# legal: "Legal" +# about: "About" +# contact: "Contact" +# twitter_follow: "Follow" +# employers: "Employers" + +# versions: +# save_version_title: "Save New Version" +# new_major_version: "New Major Version" +# cla_prefix: "To save changes, first you must agree to our" +# cla_url: "CLA" +# cla_suffix: "." +# cla_agree: "I AGREE" + +# login: +# sign_up: "Create Account" +# log_in: "Log In" +# logging_in: "Logging In" +# log_out: "Log Out" +# recover: "recover account" + +# recover: +# recover_account_title: "Recover Account" +# send_password: "Send Recovery Password" + +# signup: +# create_account_title: "Create Account to Save Progress" +# description: "It's free. Just need a couple things and you'll be good to go:" +# email_announcements: "Receive announcements by email" +# coppa: "13+ or non-USA " +# coppa_why: "(Why?)" +# creating: "Creating Account..." +# sign_up: "Sign Up" +# log_in: "log in with password" +# social_signup: "Or, you can sign up through Facebook or G+:" + +# home: +# slogan: "Learn to Code JavaScript by Playing a Game" +# no_ie: "CodeCombat does not run in Internet Explorer 9 or older. Sorry!" +# no_mobile: "CodeCombat wasn't designed for mobile devices and may not work!" +# play: "Play" +# old_browser: "Uh oh, your browser is too old to run CodeCombat. Sorry!" +# old_browser_suffix: "You can try anyway, but it probably won't work." +# campaign: "Campaign" +# for_beginners: "For Beginners" +# multiplayer: "Multiplayer" +# for_developers: "For Developers" + +# play: +# choose_your_level: "Choose Your Level" +# adventurer_prefix: "You can jump to any level below, or discuss the levels on " +# adventurer_forum: "the Adventurer forum" +# adventurer_suffix: "." +# campaign_beginner: "Beginner Campaign" +# campaign_beginner_description: "... in which you learn the wizardry of programming." +# campaign_dev: "Random Harder Levels" +# campaign_dev_description: "... in which you learn the interface while doing something a little harder." +# campaign_multiplayer: "Multiplayer Arenas" +# campaign_multiplayer_description: "... in which you code head-to-head against other players." +# campaign_player_created: "Player-Created" +# campaign_player_created_description: "... in which you battle against the creativity of your fellow <a href=\"/contribute#artisan\">Artisan Wizards</a>." +# level_difficulty: "Difficulty: " +# play_as: "Play As" +# spectate: "Spectate" + +# contact: +# contact_us: "Contact CodeCombat" +# welcome: "Good to hear from you! Use this form to send us email. " +# contribute_prefix: "If you're interested in contributing, check out our " +# contribute_page: "contribute page" +# contribute_suffix: "!" +# forum_prefix: "For anything public, please try " +# forum_page: "our forum" +# forum_suffix: " instead." +# send: "Send Feedback" +# contact_candidate: "Contact Candidate" +# recruitment_reminder: "Use this form to reach out to candidates you are interested in interviewing. Remember that CodeCombat charges 18% of first-year salary. The fee is due upon hiring the employee and is refundable for 90 days if the employee does not remain employed. Part time, remote, and contract employees are free, as are interns." + + diplomat_suggestion: +# title: "Help translate CodeCombat!" +# sub_heading: "We need your language skills." + pitch_body: "Wir entwickeln CodeCombat in Englisch, aber wir haben Spieler in der ganzen Welt. Viele von ihnen wollen in Deutsch (Österreich) spielen, sprechen aber kein Englisch. Wenn Du also beide Sprachen beherrscht, melde Dich an um ein Diplomat zu werden und hilf die Website und die Levels zu Deutsch (Österreich) zu übersetzen." + missing_translations: "Solange wir nicht alles ins Deutsche (Österreich) übesetzt haben, siehst Du die englische Übersetzung, wo Deutsch (Österreich) leider noch nicht zur Verfügung steht." +# learn_more: "Learn more about being a Diplomat" +# subscribe_as_diplomat: "Subscribe as a Diplomat" + +# wizard_settings: +# title: "Wizard Settings" +# customize_avatar: "Customize Your Avatar" +# active: "Active" +# color: "Color" +# group: "Group" +# clothes: "Clothes" +# trim: "Trim" +# cloud: "Cloud" +# team: "Team" +# spell: "Spell" +# boots: "Boots" +# hue: "Hue" +# saturation: "Saturation" +# lightness: "Lightness" + +# account_settings: +# title: "Account Settings" +# not_logged_in: "Log in or create an account to change your settings." +# autosave: "Changes Save Automatically" +# me_tab: "Me" +# picture_tab: "Picture" +# wizard_tab: "Wizard" +# password_tab: "Password" +# emails_tab: "Emails" +# admin: "Admin" +# wizard_color: "Wizard Clothes Color" +# new_password: "New Password" +# new_password_verify: "Verify" +# email_subscriptions: "Email Subscriptions" +# email_announcements: "Announcements" +# email_notifications: "Notifications" +# email_notifications_description: "Get periodic notifications for your account." +# email_announcements_description: "Get emails on the latest news and developments at CodeCombat." +# contributor_emails: "Contributor Class Emails" +# contribute_prefix: "We're looking for people to join our party! Check out the " +# contribute_page: "contribute page" +# contribute_suffix: " to find out more." +# email_toggle: "Toggle All" +# error_saving: "Error Saving" +# saved: "Changes Saved" +# password_mismatch: "Password does not match." +# job_profile: "Job Profile" +# job_profile_approved: "Your job profile has been approved by CodeCombat. Employers will be able to see it until you either mark it inactive or it has not been changed for four weeks." +# job_profile_explanation: "Hi! Fill this out, and we will get in touch about finding you a software developer job." + +# account_profile: +# edit_settings: "Edit Settings" +# profile_for_prefix: "Profile for " +# profile_for_suffix: "" +# approved: "Approved" +# not_approved: "Not Approved" +# looking_for: "Looking for:" +# last_updated: "Last updated:" +# contact: "Contact" +# work_experience: "Work Experience" +# education: "Education" +# our_notes: "Our Notes" +# projects: "Projects" + +# employers: +# want_to_hire_our_players: "Want to hire expert CodeCombat players?" +# contact_george: "Contact George to see our candidates" +# candidates_count_prefix: "We currently have " +# candidates_count_many: "many" +# candidates_count_suffix: "highly skilled and vetted developers looking for work." +# candidate_name: "Name" +# candidate_location: "Location" +# candidate_looking_for: "Looking For" +# candidate_role: "Role" +# candidate_top_skills: "Top Skills" +# candidate_years_experience: "Yrs Exp" +# candidate_last_updated: "Last Updated" + +# play_level: +# level_load_error: "Level could not be loaded: " +# done: "Done" +# grid: "Grid" +# customize_wizard: "Customize Wizard" +# home: "Home" +# guide: "Guide" +# multiplayer: "Multiplayer" +# restart: "Restart" +# goals: "Goals" +# action_timeline: "Action Timeline" +# click_to_select: "Click on a unit to select it." +# reload_title: "Reload All Code?" +# reload_really: "Are you sure you want to reload this level back to the beginning?" +# reload_confirm: "Reload All" +# victory_title_prefix: "" +# victory_title_suffix: " Complete" +# victory_sign_up: "Sign Up to Save Progress" +# victory_sign_up_poke: "Want to save your code? Create a free account!" +# victory_rate_the_level: "Rate the level: " +# victory_rank_my_game: "Rank My Game" +# victory_ranking_game: "Submitting..." +# victory_return_to_ladder: "Return to Ladder" +# victory_play_next_level: "Play Next Level" +# victory_go_home: "Go Home" +# victory_review: "Tell us more!" +# victory_hour_of_code_done: "Are You Done?" +# victory_hour_of_code_done_yes: "Yes, I'm finished with my Hour of Code™!" +# multiplayer_title: "Multiplayer Settings" +# multiplayer_link_description: "Give this link to anyone to have them join you." +# multiplayer_hint_label: "Hint:" +# multiplayer_hint: " Click the link to select all, then press ⌘-C or Ctrl-C to copy the link." +# multiplayer_coming_soon: "More multiplayer features to come!" +# guide_title: "Guide" +# tome_minion_spells: "Your Minions' Spells" +# tome_read_only_spells: "Read-Only Spells" +# tome_other_units: "Other Units" +# tome_cast_button_castable: "Cast Spell" +# tome_cast_button_casting: "Casting" +# tome_cast_button_cast: "Spell Cast" +# tome_autocast_delay: "Autocast Delay" +# tome_select_spell: "Select a Spell" +# tome_select_a_thang: "Select Someone for " +# tome_available_spells: "Available Spells" +# hud_continue: "Continue (shift+space)" +# spell_saved: "Spell Saved" +# skip_tutorial: "Skip (esc)" +# editor_config: "Editor Config" +# editor_config_title: "Editor Configuration" +# editor_config_language_label: "Programming Language" +# editor_config_language_description: "Define the programming language you want to code in." +# editor_config_keybindings_label: "Key Bindings" +# editor_config_keybindings_default: "Default (Ace)" +# editor_config_keybindings_description: "Adds additional shortcuts known from the common editors." +# editor_config_invisibles_label: "Show Invisibles" +# editor_config_invisibles_description: "Displays invisibles such as spaces or tabs." +# editor_config_indentguides_label: "Show Indent Guides" +# editor_config_indentguides_description: "Displays vertical lines to see indentation better." +# editor_config_behaviors_label: "Smart Behaviors" +# editor_config_behaviors_description: "Autocompletes brackets, braces, and quotes." +# loading_ready: "Ready!" +# tip_insert_positions: "Shift+Click a point on the map to insert it into the spell editor." +# tip_toggle_play: "Toggle play/paused with Ctrl+P." +# tip_scrub_shortcut: "Ctrl+[ and Ctrl+] rewind and fast-forward." +# tip_guide_exists: "Click the guide at the top of the page for useful info." +# tip_open_source: "CodeCombat is 100% open source!" +# tip_beta_launch: "CodeCombat launched its beta in October, 2013." +# tip_js_beginning: "JavaScript is just the beginning." +# tip_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# think_solution: "Think of the solution, not the problem." +# tip_theory_practice: "In theory, there is no difference between theory and practice. But in practice, there is. - Yogi Berra" +# tip_error_free: "There are two ways to write error-free programs; only the third one works. - Alan Perlis" +# tip_debugging_program: "If debugging is the process of removing bugs, then programming must be the process of putting them in. - Edsger W. Dijkstra" +# tip_forums: "Head over to the forums and tell us what you think!" +# tip_baby_coders: "In the future, even babies will be Archmages." +# tip_morale_improves: "Loading will continue until morale improves." +# tip_all_species: "We believe in equal opportunities to learn programming for all species." +# tip_reticulating: "Reticulating spines." +# tip_harry: "Yer a Wizard, " +# tip_great_responsibility: "With great coding skill comes great debug responsibility." +# tip_munchkin: "If you don't eat your vegetables, a munchkin will come after you while you're asleep." +# tip_binary: "There are only 10 types of people in the world: those who understand binary, and those who don't." +# tip_commitment_yoda: "A programmer must have the deepest commitment, the most serious mind. ~ Yoda" +# tip_no_try: "Do. Or do not. There is no try. - Yoda" +# tip_patience: "Patience you must have, young Padawan. - Yoda" +# tip_documented_bug: "A documented bug is not a bug; it is a feature." +# tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" +# time_current: "Now:" +# time_total: "Max:" +# time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" + +# admin: +# av_title: "Admin Views" +# av_entities_sub_title: "Entities" +# av_entities_users_url: "Users" +# av_entities_active_instances_url: "Active Instances" +# av_other_sub_title: "Other" +# av_other_debug_base_url: "Base (for debugging base.jade)" +# u_title: "User List" +# lg_title: "Latest Games" +# clas: "CLAs" + +# editor: +# main_title: "CodeCombat Editors" +# main_description: "Build your own levels, campaigns, units and educational content. We provide all the tools you need!" +# article_title: "Article Editor" +# article_description: "Write articles that give players overviews of programming concepts which can be used across a variety of levels and campaigns." +# thang_title: "Thang Editor" +# thang_description: "Build units, defining their default logic, graphics and audio. Currently only supports importing Flash exported vector graphics." +# level_title: "Level Editor" +# level_description: "Includes the tools for scripting, uploading audio, and constructing custom logic to create all sorts of levels. Everything we use ourselves!" +# security_notice: "Many major features in these editors are not currently enabled by default. As we improve the security of these systems, they will be made generally available. If you'd like to use these features sooner, " +# contact_us: "contact us!" +# hipchat_prefix: "You can also find us in our" +# hipchat_url: "HipChat room." +# back: "Back" +# revert: "Revert" +# revert_models: "Revert Models" +# fork_title: "Fork New Version" +# fork_creating: "Creating Fork..." +# more: "More" +# wiki: "Wiki" +# live_chat: "Live Chat" +# level_some_options: "Some Options?" +# level_tab_thangs: "Thangs" +# level_tab_scripts: "Scripts" +# level_tab_settings: "Settings" +# level_tab_components: "Components" +# level_tab_systems: "Systems" +# level_tab_thangs_title: "Current Thangs" +# level_tab_thangs_all: "All" +# level_tab_thangs_conditions: "Starting Conditions" +# level_tab_thangs_add: "Add Thangs" +# delete: "Delete" +# duplicate: "Duplicate" +# level_settings_title: "Settings" +# level_component_tab_title: "Current Components" +# level_component_btn_new: "Create New Component" +# level_systems_tab_title: "Current Systems" +# level_systems_btn_new: "Create New System" +# level_systems_btn_add: "Add System" +# level_components_title: "Back to All Thangs" +# level_components_type: "Type" +# level_component_edit_title: "Edit Component" +# level_component_config_schema: "Config Schema" +# level_component_settings: "Settings" +# level_system_edit_title: "Edit System" +# create_system_title: "Create New System" +# new_component_title: "Create New Component" +# new_component_field_system: "System" +# new_article_title: "Create a New Article" +# new_thang_title: "Create a New Thang Type" +# new_level_title: "Create a New Level" +# article_search_title: "Search Articles Here" +# thang_search_title: "Search Thang Types Here" +# level_search_title: "Search Levels Here" +# signup_to_create: "Sign Up to Create a New Content" +# read_only_warning2: "Note: you can't save any edits here, because you're not logged in." + +# article: +# edit_btn_preview: "Preview" +# edit_article_title: "Edit Article" + +# general: +# and: "and" +# name: "Name" +# body: "Body" +# version: "Version" +# commit_msg: "Commit Message" +# version_history: "Version History" +# version_history_for: "Version History for: " +# result: "Result" +# results: "Results" +# description: "Description" +# or: "or" +# subject: "Subject" +# email: "Email" +# password: "Password" +# message: "Message" +# 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" + +# about: +# who_is_codecombat: "Who is CodeCombat?" +# why_codecombat: "Why CodeCombat?" +# who_description_prefix: "together started CodeCombat in 2013. We also created " +# who_description_suffix: "in 2008, growing it to the #1 web and iOS application for learning to write Chinese and Japanese characters." +# who_description_ending: "Now it's time to teach people to write code." +# why_paragraph_1: "When making Skritter, George didn't know how to program and was constantly frustrated by his inability to implement his ideas. Afterwards, he tried learning, but the lessons were too slow. His housemate, wanting to reskill and stop teaching, tried Codecademy, but \"got bored.\" Each week another friend started Codecademy, then dropped off. We realized it was the same problem we'd solved with Skritter: people learning a skill via slow, intensive lessons when what they need is fast, extensive practice. We know how to fix that." +# why_paragraph_2: "Need to learn to code? You don't need lessons. You need to write a lot of code and have a great time doing it." +# why_paragraph_3_prefix: "That's what programming is about. It's gotta be fun. Not fun like" +# why_paragraph_3_italic: "yay a badge" +# why_paragraph_3_center: "but fun like" +# why_paragraph_3_italic_caps: "NO MOM I HAVE TO FINISH THE LEVEL!" +# why_paragraph_3_suffix: "That's why CodeCombat is a multiplayer game, not a gamified lesson course. We won't stop until you can't stop--but this time, that's a good thing." +# why_paragraph_4: "If you're going to get addicted to some game, get addicted to this one and become one of the wizards of the tech age." +# why_ending: "And hey, it's free. " +# why_ending_url: "Start wizarding now!" +# george_description: "CEO, business guy, web designer, game designer, and champion of beginning programmers everywhere." +# scott_description: "Programmer extraordinaire, software architect, kitchen wizard, and master of finances. Scott is the reasonable one." +# nick_description: "Programming wizard, eccentric motivation mage, and upside-down experimenter. Nick can do anything and chooses to build CodeCombat." +# jeremy_description: "Customer support mage, usability tester, and community organizer; you've probably already spoken with Jeremy." +# michael_description: "Programmer, sys-admin, and undergrad technical wunderkind, Michael is the person keeping our servers online." +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" + +# legal: +# page_title: "Legal" +# opensource_intro: "CodeCombat is free to play and completely open source." +# opensource_description_prefix: "Check out " +# github_url: "our GitHub" +# opensource_description_center: "and help out if you like! CodeCombat is built on dozens of open source projects, and we love them. See " +# archmage_wiki_url: "our Archmage wiki" +# opensource_description_suffix: "for a list of the software that makes this game possible." +# practices_title: "Respectful Best Practices" +# practices_description: "These are our promises to you, the player, in slightly less legalese." +# privacy_title: "Privacy" +# privacy_description: "We will not sell any of your personal information. We intend to make money through recruitment eventually, but rest assured we will not distribute your personal information to interested companies without your explicit consent." +# security_title: "Security" +# security_description: "We strive to keep your personal information safe. As an open source project, our site is freely open to anyone to review and improve our security systems." +# email_title: "Email" +# email_description_prefix: "We will not inundate you with spam. Through" +# email_settings_url: "your email settings" +# email_description_suffix: "or through links in the emails we send, you can change your preferences and easily unsubscribe at any time." +# cost_title: "Cost" +# cost_description: "Currently, CodeCombat is 100% free! One of our main goals is to keep it that way, so that as many people can play as possible, regardless of place in life. If the sky darkens, we might have to charge subscriptions or for some content, but we'd rather not. With any luck, we'll be able to sustain the company with:" +# recruitment_title: "Recruitment" +# recruitment_description_prefix: "Here on CodeCombat, you're going to become a powerful wizard–not just in the game, but also in real life." +# url_hire_programmers: "No one can hire programmers fast enough" +# recruitment_description_suffix: "so once you've sharpened your skills and if you agree, we will demo your best coding accomplishments to the thousands of employers who are drooling for the chance to hire you. They pay us a little, they pay you" +# recruitment_description_italic: "a lot" +# recruitment_description_ending: "the site remains free and everybody's happy. That's the plan." +# copyrights_title: "Copyrights and Licenses" +# contributor_title: "Contributor License Agreement" +# contributor_description_prefix: "All contributions, both on the site and on our GitHub repository, are subject to our" +# cla_url: "CLA" +# contributor_description_suffix: "to which you should agree before contributing." +# code_title: "Code - MIT" +# code_description_prefix: "All code owned by CodeCombat or hosted on codecombat.com, both in the GitHub repository or in the codecombat.com database, is licensed under the" +# mit_license_url: "MIT license" +# code_description_suffix: "This includes all code in Systems and Components that are made available by CodeCombat for the purpose of creating levels." +# art_title: "Art/Music - Creative Commons " +# art_description_prefix: "All common content is available under the" +# cc_license_url: "Creative Commons Attribution 4.0 International License" +# art_description_suffix: "Common content is anything made generally available by CodeCombat for the purpose of creating Levels. This includes:" +# art_music: "Music" +# art_sound: "Sound" +# art_artwork: "Artwork" +# art_sprites: "Sprites" +# art_other: "Any and all other non-code creative works that are made available when creating Levels." +# art_access: "Currently there is no universal, easy system for fetching these assets. In general, fetch them from the URLs as used by the site, contact us for assistance, or help us in extending the site to make these assets more easily accessible." +# art_paragraph_1: "For attribution, please name and link to codecombat.com near where the source is used or where appropriate for the medium. For example:" +# use_list_1: "If used in a movie or another game, include codecombat.com in the credits." +# use_list_2: "If used on a website, include a link near the usage, for example underneath an image, or in a general attributions page where you might also mention other Creative Commons works and open source software being used on the site. Something that's already clearly referencing CodeCombat, such as a blog post mentioning CodeCombat, does not need some separate attribution." +# art_paragraph_2: "If the content being used is created not by CodeCombat but instead by a user of codecombat.com, attribute them instead, and follow attribution directions provided in that resource's description if there are any." +# rights_title: "Rights Reserved" +# rights_desc: "All rights are reserved for Levels themselves. This includes" +# rights_scripts: "Scripts" +# rights_unit: "Unit configuration" +# rights_description: "Description" +# rights_writings: "Writings" +# rights_media: "Media (sounds, music) and any other creative content made specifically for that Level and not made generally available when creating Levels." +# rights_clarification: "To clarify, anything that is made available in the Level Editor for the purpose of making levels is under CC, whereas the content created with the Level Editor or uploaded in the course of creation of Levels is not." +# nutshell_title: "In a Nutshell" +# nutshell_description: "Any resources we provide in the Level Editor are free to use as you like for creating Levels. But we reserve the right to restrict distribution of the Levels themselves (that are created on codecombat.com) so that they may be charged for in the future, if that's what ends up happening." +# canonical: "The English version of this document is the definitive, canonical version. If there are any discrepencies between translations, the English document takes precedence." + +# contribute: +# page_title: "Contributing" +# character_classes_title: "Character Classes" +# introduction_desc_intro: "We have high hopes for CodeCombat." +# introduction_desc_pref: "We want to be where programmers of all stripes come to learn and play together, introduce others to the wonderful world of coding, and reflect the best parts of the community. We can't and don't want to do that alone; what makes projects like GitHub, Stack Overflow and Linux great are the people who use them and build on them. To that end, " +# introduction_desc_github_url: "CodeCombat is totally open source" +# introduction_desc_suf: ", and we aim to provide as many ways as possible for you to take part and make this project as much yours as ours." +# introduction_desc_ending: "We hope you'll join our party!" +# introduction_desc_signature: "- Nick, George, Scott, Michael, Jeremy and Glen" +# alert_account_message_intro: "Hey there!" +# alert_account_message_pref: "To subscribe for class emails, you'll need to " +# alert_account_message_suf: "first." +# alert_account_message_create_url: "create an account" +# archmage_summary: "Interested in working on game graphics, user interface design, database and server organization, multiplayer networking, physics, sound, or game engine performance? Want to help build a game to help other people learn what you are good at? We have a lot to do and if you are an experienced programmer and want to develop for CodeCombat, this class is for you. We would love your help building the best programming game ever." +# archmage_introduction: "One of the best parts about building games is they synthesize so many different things. Graphics, sound, real-time networking, social networking, and of course many of the more common aspects of programming, from low-level database management, and server administration to user facing design and interface building. There's a lot to do, and if you're an experienced programmer with a hankering to really dive into the nitty-gritty of CodeCombat, this class might be for you. We would love to have your help building the best programming game ever." +# class_attributes: "Class Attributes" +# archmage_attribute_1_pref: "Knowledge in " +# archmage_attribute_1_suf: ", or a desire to learn. Most of our code is in this language. If you're a fan of Ruby or Python, you'll feel right at home. It's JavaScript, but with a nicer syntax." +# archmage_attribute_2: "Some experience in programming and personal initiative. We'll help you get oriented, but we can't spend much time training you." +# how_to_join: "How To Join" +# join_desc_1: "Anyone can help out! Just check out our " +# join_desc_2: "to get started, and check the box below to mark yourself as a brave Archmage and get the latest news by email. Want to chat about what to do or how to get more deeply involved? " +# join_desc_3: ", or find us in our " +# join_desc_4: "and we'll go from there!" +# join_url_email: "Email us" +# join_url_hipchat: "public HipChat room" +# more_about_archmage: "Learn More About Becoming an Archmage" +# archmage_subscribe_desc: "Get emails on new coding opportunities and announcements." +# artisan_summary_pref: "Want to design levels and expand CodeCombat's arsenal? People are playing through our content at a pace faster than we can build! Right now, our level editor is barebone, so be wary. Making levels will be a little challenging and buggy. If you have visions of campaigns spanning for-loops to" +# artisan_summary_suf: ", then this class is for you." +# artisan_introduction_pref: "We must construct additional levels! People be clamoring for more content, and we can only build so many ourselves. Right now your workstation is level one; our level editor is barely usable even by its creators, so be wary. If you have visions of campaigns spanning for-loops to" +# artisan_introduction_suf: ", then this class might be for you." +# artisan_attribute_1: "Any experience in building content like this would be nice, such as using Blizzard's level editors. But not required!" +# artisan_attribute_2: "A hankering to do a whole lot of testing and iteration. To make good levels, you need to take it to others and watch them play it, and be prepared to find a lot of things to fix." +# artisan_attribute_3: "For the time being, endurance en par with an Adventurer. Our Level Editor is super preliminary and frustrating to use. You have been warned!" +# artisan_join_desc: "Use the Level Editor in these steps, give or take:" +# artisan_join_step1: "Read the documentation." +# artisan_join_step2: "Create a new level and explore existing levels." +# artisan_join_step3: "Find us in our public HipChat room for help." +# artisan_join_step4: "Post your levels on the forum for feedback." +# more_about_artisan: "Learn More About Becoming an Artisan" +# artisan_subscribe_desc: "Get emails on level editor updates and announcements." +# adventurer_summary: "Let us be clear about your role: you are the tank. You are going to take heavy damage. We need people to try out brand-new levels and help identify how to make things better. The pain will be enormous; making good games is a long process and no one gets it right the first time. If you can endure and have a high constitution score, then this class is for you." +# adventurer_introduction: "Let's be clear about your role: you are the tank. You're going to take heavy damage. We need people to try out brand-new levels and help identify how to make things better. The pain will be enormous; making good games is a long process and no one gets it right the first time. If you can endure and have a high constitution score, then this class might be for you." +# adventurer_attribute_1: "A thirst for learning. You want to learn how to code and we want to teach you how to code. You'll probably be doing most of the teaching in this case, though." +# adventurer_attribute_2: "Charismatic. Be gentle but articulate about what needs improving, and offer suggestions on how to improve." +# adventurer_join_pref: "Either get together with (or recruit!) an Artisan and work with them, or check the box below to receive emails when there are new levels to test. We'll also be posting about levels to review on our networks like" +# adventurer_forum_url: "our forum" +# adventurer_join_suf: "so if you prefer to be notified those ways, sign up there!" +# more_about_adventurer: "Learn More About Becoming an Adventurer" +# adventurer_subscribe_desc: "Get emails when there are new levels to test." +# scribe_summary_pref: "CodeCombat is not just going to be a bunch of levels. It will also be a resource of programming knowledge that players can hook into. That way, each Artisan can link to a detailed article that for the player's edification: documentation akin to what the " +# scribe_summary_suf: " has built. If you enjoy explaining programming concepts, then this class is for you." +# scribe_introduction_pref: "CodeCombat isn't just going to be a bunch of levels. It will also include a resource for knowledge, a wiki of programming concepts that levels can hook into. That way rather than each Artisan having to describe in detail what a comparison operator is, they can simply link their level to the Article describing them that is already written for the player's edification. Something along the lines of what the " +# scribe_introduction_url_mozilla: "Mozilla Developer Network" +# scribe_introduction_suf: " has built. If your idea of fun is articulating the concepts of programming in Markdown form, then this class might be for you." +# scribe_attribute_1: "Skill in words is pretty much all you need. Not only grammar and spelling, but able to convey complicated ideas to others." +# contact_us_url: "Contact us" +# scribe_join_description: "tell us a little about yourself, your experience with programming and what sort of things you'd like to write about. We'll go from there!" +# more_about_scribe: "Learn More About Becoming a Scribe" +# scribe_subscribe_desc: "Get emails about article writing announcements." +# diplomat_summary: "There is a large interest in CodeCombat in other countries that do not speak English! We are looking for translators who are willing to spend their time translating the site's corpus of words so that CodeCombat is accessible across the world as soon as possible. If you'd like to help getting CodeCombat international, then this class is for you." +# diplomat_introduction_pref: "So, if there's one thing we learned from the " +# diplomat_launch_url: "launch in October" +# diplomat_introduction_suf: "it's that there is sizeable interest in CodeCombat in other countries! We're building a corps of translators eager to turn one set of words into another set of words to get CodeCombat as accessible across the world as possible. If you like getting sneak peeks at upcoming content and getting these levels to your fellow nationals ASAP, then this class might be for you." +# diplomat_attribute_1: "Fluency in English and the language you would like to translate to. When conveying complicated ideas, it's important to have a strong grasp in both!" +# diplomat_join_pref_github: "Find your language locale file " +# diplomat_github_url: "on GitHub" +# diplomat_join_suf_github: ", edit it online, and submit a pull request. Also, check this box below to keep up-to-date on new internationalization developments!" +# more_about_diplomat: "Learn More About Becoming a Diplomat" +# diplomat_subscribe_desc: "Get emails about i18n developments and levels to translate." +# ambassador_summary: "We are trying to build a community, and every community needs a support team when there are troubles. We have got chats, emails, and social networks so that our users can get acquainted with the game. If you want to help people get involved, have fun, and learn some programming, then this class is for you." +# ambassador_introduction: "This is a community we're building, and you are the connections. We've got Olark chats, emails, and social networks with lots of people to talk with and help get acquainted with the game and learn from. If you want to help people get involved and have fun, and get a good feel of the pulse of CodeCombat and where we're going, then this class might be for you." +# ambassador_attribute_1: "Communication skills. Be able to identify the problems players are having and help them solve them. Also, keep the rest of us informed about what players are saying, what they like and don't like and want more of!" +# ambassador_join_desc: "tell us a little about yourself, what you've done and what you'd be interested in doing. We'll go from there!" +# ambassador_join_note_strong: "Note" +# ambassador_join_note_desc: "One of our top priorities is to build multiplayer where players having difficulty solving levels can summon higher level wizards to help them. This will be a great way for ambassadors to do their thing. We'll keep you posted!" +# more_about_ambassador: "Learn More About Becoming an Ambassador" +# ambassador_subscribe_desc: "Get emails on support updates and multiplayer developments." +# counselor_summary: "None of the above roles fit what you are interested in? Do not worry, we are on the lookout for anybody who wants a hand in the development of CodeCombat! If you are interested in teaching, game development, open source management, or anything else that you think will be relevant to us, then this class is for you." +# counselor_introduction_1: "Do you have life experience? A different perspective on things that can help us decide how to shape CodeCombat? Of all these roles, this will probably take the least time, but individually you may make the most difference. We're on the lookout for wisened sages, particularly in areas like: teaching, game development, open source project management, technical recruiting, entrepreneurship, or design." +# counselor_introduction_2: "Or really anything that is relevant to the development of CodeCombat. If you have knowledge and want to share it to help grow this project, then this class might be for you." +# counselor_attribute_1: "Experience, in any of the areas above or something you think might be helpful." +# counselor_attribute_2: "A little bit of free time!" +# counselor_join_desc: "tell us a little about yourself, what you've done and what you'd be interested in doing. We'll put you in our contact list and be in touch when we could use advice (not too often)." +# more_about_counselor: "Learn More About Becoming a Counselor" +# changes_auto_save: "Changes are saved automatically when you toggle checkboxes." +# diligent_scribes: "Our Diligent Scribes:" +# powerful_archmages: "Our Powerful Archmages:" +# creative_artisans: "Our Creative Artisans:" +# brave_adventurers: "Our Brave Adventurers:" +# translating_diplomats: "Our Translating Diplomats:" +# helpful_ambassadors: "Our Helpful Ambassadors:" + +# classes: +# archmage_title: "Archmage" +# archmage_title_description: "(Coder)" +# artisan_title: "Artisan" +# artisan_title_description: "(Level Builder)" +# adventurer_title: "Adventurer" +# adventurer_title_description: "(Level Playtester)" +# scribe_title: "Scribe" +# scribe_title_description: "(Article Editor)" +# diplomat_title: "Diplomat" +# diplomat_title_description: "(Translator)" +# ambassador_title: "Ambassador" +# ambassador_title_description: "(Support)" +# counselor_title: "Counselor" +# counselor_title_description: "(Expert/Teacher)" + +# ladder: +# please_login: "Please log in first before playing a ladder game." +# my_matches: "My Matches" +# simulate: "Simulate" +# simulation_explanation: "By simulating games you can get your game ranked faster!" +# simulate_games: "Simulate Games!" +# simulate_all: "RESET AND SIMULATE GAMES" +# games_simulated_by: "Games simulated by you:" +# games_simulated_for: "Games simulated for you:" +# games_simulated: "Games simulated" +# games_played: "Games played" +# ratio: "Ratio" +# leaderboard: "Leaderboard" +# battle_as: "Battle as " +# summary_your: "Your " +# summary_matches: "Matches - " +# summary_wins: " Wins, " +# summary_losses: " Losses" +# rank_no_code: "No New Code to Rank" +# rank_my_game: "Rank My Game!" +# rank_submitting: "Submitting..." +# rank_submitted: "Submitted for Ranking" +# rank_failed: "Failed to Rank" +# rank_being_ranked: "Game Being Ranked" +# code_being_simulated: "Your new code is being simulated by other players for ranking. This will refresh as new matches come in." +# no_ranked_matches_pre: "No ranked matches for the " +# no_ranked_matches_post: " team! Play against some competitors and then come back here to get your game ranked." +# choose_opponent: "Choose an Opponent" +# tutorial_play: "Play Tutorial" +# tutorial_recommended: "Recommended if you've never played before" +# tutorial_skip: "Skip Tutorial" +# tutorial_not_sure: "Not sure what's going on?" +# tutorial_play_first: "Play the Tutorial first." +# simple_ai: "Simple AI" +# warmup: "Warmup" +# vs: "VS" + +# multiplayer_launch: +# introducing_dungeon_arena: "Introducing Dungeon Arena" +# new_way: "The new way to compete with code." +# to_battle: "To Battle, Developers!" +# modern_day_sorcerer: "You know how to code? That's badass. You're a modern-day sorcerer! Isn't about time that you used your magic coding powers to command your minions in epic combat? And we're not talking robots here." +# arenas_are_here: "CodeCombat head-to-head multiplayer arenas are here." +# ladder_explanation: "Choose your heroes, enchant your human or ogre armies, and climb your way over defeated fellow Wizards to reach the top of the ladders–then challenge your friends in our glorious, asynchronous multiplayer coding arenas. If you're feeling creative, you can even" +# fork_our_arenas: "fork our arenas" +# create_worlds: "and create your own worlds." +# javascript_rusty: "JavaScript a bit rusty? Don't worry; there's a" +# tutorial: "tutorial" +# new_to_programming: ". New to programming? Hit our beginner campaign to skill up." +# so_ready: "I Am So Ready for This" + +# loading_error: +# could_not_load: "Error loading from server" +# connection_failure: "Connection failed." +# unauthorized: "You need to be signed in. Do you have cookies disabled?" +# forbidden: "You do not have the permissions." +# not_found: "Not found." +# not_allowed: "Method not allowed." +# timeout: "Server timeout." +# conflict: "Resource conflict." +# bad_input: "Bad input." +# server_error: "Server error." +# unknown: "Unknown error." + +# resources: +# 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" +# patches: "Patches" +# model: "Model" diff --git a/app/locale/de-CH.coffee b/app/locale/de-CH.coffee new file mode 100644 index 000000000..3d241fcc3 --- /dev/null +++ b/app/locale/de-CH.coffee @@ -0,0 +1,671 @@ +module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "German (Switzerland)", translation: + common: + loading: "Lade..." + saving: "Spiichere..." + sending: "Sende..." + send: "G'sendet" + cancel: "Abbreche" + save: "Speichere" + publish: "Veröffentliche" + create: "Erstelle" + delay_1_sec: "1 sekunde" + delay_3_sec: "3 sekunde" + delay_5_sec: "5 sekunde" +# manual: "Manual" +# fork: "Fork" + play: "Spiele" + retry: "nomol versuche" + + units: + second: "sekunde" + seconds: "sekunde" + minute: "minute" + minutes: "minute" + hour: "stund" + hours: "stunde" + + modal: + close: "beende" + okay: "Okaz" + + not_found: + page_not_found: "Siite nöd gfunde" + + nav: +# play: "Levels" +# editor: "Editor" +# blog: "Blog" +# forum: "Forum" +# admin: "Admin" +# home: "Home" + contribute: "Spende" +# legal: "Legal" + about: "Über" + contact: "Kontakt" + twitter_follow: "Folge" + employers: "agschtelti" + +# versions: +# save_version_title: "Save New Version" +# new_major_version: "New Major Version" +# cla_prefix: "To save changes, first you must agree to our" +# cla_url: "CLA" +# cla_suffix: "." +# cla_agree: "I AGREE" + +# login: +# sign_up: "Create Account" +# log_in: "Log In" +# logging_in: "Logging In" +# log_out: "Log Out" +# recover: "recover account" + +# recover: +# recover_account_title: "Recover Account" +# send_password: "Send Recovery Password" + +# signup: +# create_account_title: "Create Account to Save Progress" +# description: "It's free. Just need a couple things and you'll be good to go:" +# email_announcements: "Receive announcements by email" +# coppa: "13+ or non-USA " +# coppa_why: "(Why?)" +# creating: "Creating Account..." +# sign_up: "Sign Up" +# log_in: "log in with password" +# social_signup: "Or, you can sign up through Facebook or G+:" + +# home: +# slogan: "Learn to Code JavaScript by Playing a Game" +# no_ie: "CodeCombat does not run in Internet Explorer 9 or older. Sorry!" +# no_mobile: "CodeCombat wasn't designed for mobile devices and may not work!" +# play: "Play" +# old_browser: "Uh oh, your browser is too old to run CodeCombat. Sorry!" +# old_browser_suffix: "You can try anyway, but it probably won't work." +# campaign: "Campaign" +# for_beginners: "For Beginners" +# multiplayer: "Multiplayer" +# for_developers: "For Developers" + +# play: +# choose_your_level: "Choose Your Level" +# adventurer_prefix: "You can jump to any level below, or discuss the levels on " +# adventurer_forum: "the Adventurer forum" +# adventurer_suffix: "." +# campaign_beginner: "Beginner Campaign" +# campaign_beginner_description: "... in which you learn the wizardry of programming." +# campaign_dev: "Random Harder Levels" +# campaign_dev_description: "... in which you learn the interface while doing something a little harder." +# campaign_multiplayer: "Multiplayer Arenas" +# campaign_multiplayer_description: "... in which you code head-to-head against other players." +# campaign_player_created: "Player-Created" +# campaign_player_created_description: "... in which you battle against the creativity of your fellow <a href=\"/contribute#artisan\">Artisan Wizards</a>." +# level_difficulty: "Difficulty: " +# play_as: "Play As" +# spectate: "Spectate" + +# contact: +# contact_us: "Contact CodeCombat" +# welcome: "Good to hear from you! Use this form to send us email. " +# contribute_prefix: "If you're interested in contributing, check out our " +# contribute_page: "contribute page" +# contribute_suffix: "!" +# forum_prefix: "For anything public, please try " +# forum_page: "our forum" +# forum_suffix: " instead." +# send: "Send Feedback" +# contact_candidate: "Contact Candidate" +# recruitment_reminder: "Use this form to reach out to candidates you are interested in interviewing. Remember that CodeCombat charges 18% of first-year salary. The fee is due upon hiring the employee and is refundable for 90 days if the employee does not remain employed. Part time, remote, and contract employees are free, as are interns." + + diplomat_suggestion: +# title: "Help translate CodeCombat!" +# sub_heading: "We need your language skills." + pitch_body: "We develop CodeCombat in English, but we already have players all over the world. Many of them want to play in Swiss German but don't speak English, so if you can speak both, please consider signing up to be a Diplomat and help translate both the CodeCombat website and all the levels into Swiss German." + missing_translations: "Until we can translate everything into Swiss German, you'll see generic German or English when Swiss German isn't available." +# learn_more: "Learn more about being a Diplomat" +# subscribe_as_diplomat: "Subscribe as a Diplomat" + +# wizard_settings: +# title: "Wizard Settings" +# customize_avatar: "Customize Your Avatar" +# active: "Active" +# color: "Color" +# group: "Group" +# clothes: "Clothes" +# trim: "Trim" +# cloud: "Cloud" +# team: "Team" +# spell: "Spell" +# boots: "Boots" +# hue: "Hue" +# saturation: "Saturation" +# lightness: "Lightness" + +# account_settings: +# title: "Account Settings" +# not_logged_in: "Log in or create an account to change your settings." +# autosave: "Changes Save Automatically" +# me_tab: "Me" +# picture_tab: "Picture" +# wizard_tab: "Wizard" +# password_tab: "Password" +# emails_tab: "Emails" +# admin: "Admin" +# wizard_color: "Wizard Clothes Color" +# new_password: "New Password" +# new_password_verify: "Verify" +# email_subscriptions: "Email Subscriptions" +# email_announcements: "Announcements" +# email_notifications: "Notifications" +# email_notifications_description: "Get periodic notifications for your account." +# email_announcements_description: "Get emails on the latest news and developments at CodeCombat." +# contributor_emails: "Contributor Class Emails" +# contribute_prefix: "We're looking for people to join our party! Check out the " +# contribute_page: "contribute page" +# contribute_suffix: " to find out more." +# email_toggle: "Toggle All" +# error_saving: "Error Saving" +# saved: "Changes Saved" +# password_mismatch: "Password does not match." +# job_profile: "Job Profile" +# job_profile_approved: "Your job profile has been approved by CodeCombat. Employers will be able to see it until you either mark it inactive or it has not been changed for four weeks." +# job_profile_explanation: "Hi! Fill this out, and we will get in touch about finding you a software developer job." + +# account_profile: +# edit_settings: "Edit Settings" +# profile_for_prefix: "Profile for " +# profile_for_suffix: "" +# approved: "Approved" +# not_approved: "Not Approved" +# looking_for: "Looking for:" +# last_updated: "Last updated:" +# contact: "Contact" +# work_experience: "Work Experience" +# education: "Education" +# our_notes: "Our Notes" +# projects: "Projects" + +# employers: +# want_to_hire_our_players: "Want to hire expert CodeCombat players?" +# contact_george: "Contact George to see our candidates" +# candidates_count_prefix: "We currently have " +# candidates_count_many: "many" +# candidates_count_suffix: "highly skilled and vetted developers looking for work." +# candidate_name: "Name" +# candidate_location: "Location" +# candidate_looking_for: "Looking For" +# candidate_role: "Role" +# candidate_top_skills: "Top Skills" +# candidate_years_experience: "Yrs Exp" +# candidate_last_updated: "Last Updated" + +# play_level: +# level_load_error: "Level could not be loaded: " +# done: "Done" +# grid: "Grid" +# customize_wizard: "Customize Wizard" +# home: "Home" +# guide: "Guide" +# multiplayer: "Multiplayer" +# restart: "Restart" +# goals: "Goals" +# action_timeline: "Action Timeline" +# click_to_select: "Click on a unit to select it." +# reload_title: "Reload All Code?" +# reload_really: "Are you sure you want to reload this level back to the beginning?" +# reload_confirm: "Reload All" +# victory_title_prefix: "" +# victory_title_suffix: " Complete" +# victory_sign_up: "Sign Up to Save Progress" +# victory_sign_up_poke: "Want to save your code? Create a free account!" +# victory_rate_the_level: "Rate the level: " +# victory_rank_my_game: "Rank My Game" +# victory_ranking_game: "Submitting..." +# victory_return_to_ladder: "Return to Ladder" +# victory_play_next_level: "Play Next Level" +# victory_go_home: "Go Home" +# victory_review: "Tell us more!" +# victory_hour_of_code_done: "Are You Done?" +# victory_hour_of_code_done_yes: "Yes, I'm finished with my Hour of Code™!" +# multiplayer_title: "Multiplayer Settings" +# multiplayer_link_description: "Give this link to anyone to have them join you." +# multiplayer_hint_label: "Hint:" +# multiplayer_hint: " Click the link to select all, then press ⌘-C or Ctrl-C to copy the link." +# multiplayer_coming_soon: "More multiplayer features to come!" +# guide_title: "Guide" +# tome_minion_spells: "Your Minions' Spells" +# tome_read_only_spells: "Read-Only Spells" +# tome_other_units: "Other Units" +# tome_cast_button_castable: "Cast Spell" +# tome_cast_button_casting: "Casting" +# tome_cast_button_cast: "Spell Cast" +# tome_autocast_delay: "Autocast Delay" +# tome_select_spell: "Select a Spell" +# tome_select_a_thang: "Select Someone for " +# tome_available_spells: "Available Spells" +# hud_continue: "Continue (shift+space)" +# spell_saved: "Spell Saved" +# skip_tutorial: "Skip (esc)" +# editor_config: "Editor Config" +# editor_config_title: "Editor Configuration" +# editor_config_language_label: "Programming Language" +# editor_config_language_description: "Define the programming language you want to code in." +# editor_config_keybindings_label: "Key Bindings" +# editor_config_keybindings_default: "Default (Ace)" +# editor_config_keybindings_description: "Adds additional shortcuts known from the common editors." +# editor_config_invisibles_label: "Show Invisibles" +# editor_config_invisibles_description: "Displays invisibles such as spaces or tabs." +# editor_config_indentguides_label: "Show Indent Guides" +# editor_config_indentguides_description: "Displays vertical lines to see indentation better." +# editor_config_behaviors_label: "Smart Behaviors" +# editor_config_behaviors_description: "Autocompletes brackets, braces, and quotes." +# loading_ready: "Ready!" +# tip_insert_positions: "Shift+Click a point on the map to insert it into the spell editor." +# tip_toggle_play: "Toggle play/paused with Ctrl+P." +# tip_scrub_shortcut: "Ctrl+[ and Ctrl+] rewind and fast-forward." +# tip_guide_exists: "Click the guide at the top of the page for useful info." +# tip_open_source: "CodeCombat is 100% open source!" +# tip_beta_launch: "CodeCombat launched its beta in October, 2013." +# tip_js_beginning: "JavaScript is just the beginning." +# tip_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." +# think_solution: "Think of the solution, not the problem." +# tip_theory_practice: "In theory, there is no difference between theory and practice. But in practice, there is. - Yogi Berra" +# tip_error_free: "There are two ways to write error-free programs; only the third one works. - Alan Perlis" +# tip_debugging_program: "If debugging is the process of removing bugs, then programming must be the process of putting them in. - Edsger W. Dijkstra" +# tip_forums: "Head over to the forums and tell us what you think!" +# tip_baby_coders: "In the future, even babies will be Archmages." +# tip_morale_improves: "Loading will continue until morale improves." +# tip_all_species: "We believe in equal opportunities to learn programming for all species." +# tip_reticulating: "Reticulating spines." +# tip_harry: "Yer a Wizard, " +# tip_great_responsibility: "With great coding skill comes great debug responsibility." +# tip_munchkin: "If you don't eat your vegetables, a munchkin will come after you while you're asleep." +# tip_binary: "There are only 10 types of people in the world: those who understand binary, and those who don't." +# tip_commitment_yoda: "A programmer must have the deepest commitment, the most serious mind. ~ Yoda" +# tip_no_try: "Do. Or do not. There is no try. - Yoda" +# tip_patience: "Patience you must have, young Padawan. - Yoda" +# tip_documented_bug: "A documented bug is not a bug; it is a feature." +# tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" +# time_current: "Now:" +# time_total: "Max:" +# time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" + +# admin: +# av_title: "Admin Views" +# av_entities_sub_title: "Entities" +# av_entities_users_url: "Users" +# av_entities_active_instances_url: "Active Instances" +# av_other_sub_title: "Other" +# av_other_debug_base_url: "Base (for debugging base.jade)" +# u_title: "User List" +# lg_title: "Latest Games" +# clas: "CLAs" + +# editor: +# main_title: "CodeCombat Editors" +# main_description: "Build your own levels, campaigns, units and educational content. We provide all the tools you need!" +# article_title: "Article Editor" +# article_description: "Write articles that give players overviews of programming concepts which can be used across a variety of levels and campaigns." +# thang_title: "Thang Editor" +# thang_description: "Build units, defining their default logic, graphics and audio. Currently only supports importing Flash exported vector graphics." +# level_title: "Level Editor" +# level_description: "Includes the tools for scripting, uploading audio, and constructing custom logic to create all sorts of levels. Everything we use ourselves!" +# security_notice: "Many major features in these editors are not currently enabled by default. As we improve the security of these systems, they will be made generally available. If you'd like to use these features sooner, " +# contact_us: "contact us!" +# hipchat_prefix: "You can also find us in our" +# hipchat_url: "HipChat room." +# back: "Back" +# revert: "Revert" +# revert_models: "Revert Models" +# fork_title: "Fork New Version" +# fork_creating: "Creating Fork..." +# more: "More" +# wiki: "Wiki" +# live_chat: "Live Chat" +# level_some_options: "Some Options?" +# level_tab_thangs: "Thangs" +# level_tab_scripts: "Scripts" +# level_tab_settings: "Settings" +# level_tab_components: "Components" +# level_tab_systems: "Systems" +# level_tab_thangs_title: "Current Thangs" +# level_tab_thangs_all: "All" +# level_tab_thangs_conditions: "Starting Conditions" +# level_tab_thangs_add: "Add Thangs" +# delete: "Delete" +# duplicate: "Duplicate" +# level_settings_title: "Settings" +# level_component_tab_title: "Current Components" +# level_component_btn_new: "Create New Component" +# level_systems_tab_title: "Current Systems" +# level_systems_btn_new: "Create New System" +# level_systems_btn_add: "Add System" +# level_components_title: "Back to All Thangs" +# level_components_type: "Type" +# level_component_edit_title: "Edit Component" +# level_component_config_schema: "Config Schema" +# level_component_settings: "Settings" +# level_system_edit_title: "Edit System" +# create_system_title: "Create New System" +# new_component_title: "Create New Component" +# new_component_field_system: "System" +# new_article_title: "Create a New Article" +# new_thang_title: "Create a New Thang Type" +# new_level_title: "Create a New Level" +# article_search_title: "Search Articles Here" +# thang_search_title: "Search Thang Types Here" +# level_search_title: "Search Levels Here" +# signup_to_create: "Sign Up to Create a New Content" +# read_only_warning2: "Note: you can't save any edits here, because you're not logged in." + +# article: +# edit_btn_preview: "Preview" +# edit_article_title: "Edit Article" + +# general: +# and: "and" +# name: "Name" +# body: "Body" +# version: "Version" +# commit_msg: "Commit Message" +# version_history: "Version History" +# version_history_for: "Version History for: " +# result: "Result" +# results: "Results" +# description: "Description" +# or: "or" +# subject: "Subject" +# email: "Email" +# password: "Password" +# message: "Message" +# 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" + +# about: +# who_is_codecombat: "Who is CodeCombat?" +# why_codecombat: "Why CodeCombat?" +# who_description_prefix: "together started CodeCombat in 2013. We also created " +# who_description_suffix: "in 2008, growing it to the #1 web and iOS application for learning to write Chinese and Japanese characters." +# who_description_ending: "Now it's time to teach people to write code." +# why_paragraph_1: "When making Skritter, George didn't know how to program and was constantly frustrated by his inability to implement his ideas. Afterwards, he tried learning, but the lessons were too slow. His housemate, wanting to reskill and stop teaching, tried Codecademy, but \"got bored.\" Each week another friend started Codecademy, then dropped off. We realized it was the same problem we'd solved with Skritter: people learning a skill via slow, intensive lessons when what they need is fast, extensive practice. We know how to fix that." +# why_paragraph_2: "Need to learn to code? You don't need lessons. You need to write a lot of code and have a great time doing it." +# why_paragraph_3_prefix: "That's what programming is about. It's gotta be fun. Not fun like" +# why_paragraph_3_italic: "yay a badge" +# why_paragraph_3_center: "but fun like" +# why_paragraph_3_italic_caps: "NO MOM I HAVE TO FINISH THE LEVEL!" +# why_paragraph_3_suffix: "That's why CodeCombat is a multiplayer game, not a gamified lesson course. We won't stop until you can't stop--but this time, that's a good thing." +# why_paragraph_4: "If you're going to get addicted to some game, get addicted to this one and become one of the wizards of the tech age." +# why_ending: "And hey, it's free. " +# why_ending_url: "Start wizarding now!" +# george_description: "CEO, business guy, web designer, game designer, and champion of beginning programmers everywhere." +# scott_description: "Programmer extraordinaire, software architect, kitchen wizard, and master of finances. Scott is the reasonable one." +# nick_description: "Programming wizard, eccentric motivation mage, and upside-down experimenter. Nick can do anything and chooses to build CodeCombat." +# jeremy_description: "Customer support mage, usability tester, and community organizer; you've probably already spoken with Jeremy." +# michael_description: "Programmer, sys-admin, and undergrad technical wunderkind, Michael is the person keeping our servers online." +# glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" + +# legal: +# page_title: "Legal" +# opensource_intro: "CodeCombat is free to play and completely open source." +# opensource_description_prefix: "Check out " +# github_url: "our GitHub" +# opensource_description_center: "and help out if you like! CodeCombat is built on dozens of open source projects, and we love them. See " +# archmage_wiki_url: "our Archmage wiki" +# opensource_description_suffix: "for a list of the software that makes this game possible." +# practices_title: "Respectful Best Practices" +# practices_description: "These are our promises to you, the player, in slightly less legalese." +# privacy_title: "Privacy" +# privacy_description: "We will not sell any of your personal information. We intend to make money through recruitment eventually, but rest assured we will not distribute your personal information to interested companies without your explicit consent." +# security_title: "Security" +# security_description: "We strive to keep your personal information safe. As an open source project, our site is freely open to anyone to review and improve our security systems." +# email_title: "Email" +# email_description_prefix: "We will not inundate you with spam. Through" +# email_settings_url: "your email settings" +# email_description_suffix: "or through links in the emails we send, you can change your preferences and easily unsubscribe at any time." +# cost_title: "Cost" +# cost_description: "Currently, CodeCombat is 100% free! One of our main goals is to keep it that way, so that as many people can play as possible, regardless of place in life. If the sky darkens, we might have to charge subscriptions or for some content, but we'd rather not. With any luck, we'll be able to sustain the company with:" +# recruitment_title: "Recruitment" +# recruitment_description_prefix: "Here on CodeCombat, you're going to become a powerful wizard–not just in the game, but also in real life." +# url_hire_programmers: "No one can hire programmers fast enough" +# recruitment_description_suffix: "so once you've sharpened your skills and if you agree, we will demo your best coding accomplishments to the thousands of employers who are drooling for the chance to hire you. They pay us a little, they pay you" +# recruitment_description_italic: "a lot" +# recruitment_description_ending: "the site remains free and everybody's happy. That's the plan." +# copyrights_title: "Copyrights and Licenses" +# contributor_title: "Contributor License Agreement" +# contributor_description_prefix: "All contributions, both on the site and on our GitHub repository, are subject to our" +# cla_url: "CLA" +# contributor_description_suffix: "to which you should agree before contributing." +# code_title: "Code - MIT" +# code_description_prefix: "All code owned by CodeCombat or hosted on codecombat.com, both in the GitHub repository or in the codecombat.com database, is licensed under the" +# mit_license_url: "MIT license" +# code_description_suffix: "This includes all code in Systems and Components that are made available by CodeCombat for the purpose of creating levels." +# art_title: "Art/Music - Creative Commons " +# art_description_prefix: "All common content is available under the" +# cc_license_url: "Creative Commons Attribution 4.0 International License" +# art_description_suffix: "Common content is anything made generally available by CodeCombat for the purpose of creating Levels. This includes:" +# art_music: "Music" +# art_sound: "Sound" +# art_artwork: "Artwork" +# art_sprites: "Sprites" +# art_other: "Any and all other non-code creative works that are made available when creating Levels." +# art_access: "Currently there is no universal, easy system for fetching these assets. In general, fetch them from the URLs as used by the site, contact us for assistance, or help us in extending the site to make these assets more easily accessible." +# art_paragraph_1: "For attribution, please name and link to codecombat.com near where the source is used or where appropriate for the medium. For example:" +# use_list_1: "If used in a movie or another game, include codecombat.com in the credits." +# use_list_2: "If used on a website, include a link near the usage, for example underneath an image, or in a general attributions page where you might also mention other Creative Commons works and open source software being used on the site. Something that's already clearly referencing CodeCombat, such as a blog post mentioning CodeCombat, does not need some separate attribution." +# art_paragraph_2: "If the content being used is created not by CodeCombat but instead by a user of codecombat.com, attribute them instead, and follow attribution directions provided in that resource's description if there are any." +# rights_title: "Rights Reserved" +# rights_desc: "All rights are reserved for Levels themselves. This includes" +# rights_scripts: "Scripts" +# rights_unit: "Unit configuration" +# rights_description: "Description" +# rights_writings: "Writings" +# rights_media: "Media (sounds, music) and any other creative content made specifically for that Level and not made generally available when creating Levels." +# rights_clarification: "To clarify, anything that is made available in the Level Editor for the purpose of making levels is under CC, whereas the content created with the Level Editor or uploaded in the course of creation of Levels is not." +# nutshell_title: "In a Nutshell" +# nutshell_description: "Any resources we provide in the Level Editor are free to use as you like for creating Levels. But we reserve the right to restrict distribution of the Levels themselves (that are created on codecombat.com) so that they may be charged for in the future, if that's what ends up happening." +# canonical: "The English version of this document is the definitive, canonical version. If there are any discrepencies between translations, the English document takes precedence." + +# contribute: +# page_title: "Contributing" +# character_classes_title: "Character Classes" +# introduction_desc_intro: "We have high hopes for CodeCombat." +# introduction_desc_pref: "We want to be where programmers of all stripes come to learn and play together, introduce others to the wonderful world of coding, and reflect the best parts of the community. We can't and don't want to do that alone; what makes projects like GitHub, Stack Overflow and Linux great are the people who use them and build on them. To that end, " +# introduction_desc_github_url: "CodeCombat is totally open source" +# introduction_desc_suf: ", and we aim to provide as many ways as possible for you to take part and make this project as much yours as ours." +# introduction_desc_ending: "We hope you'll join our party!" +# introduction_desc_signature: "- Nick, George, Scott, Michael, Jeremy and Glen" +# alert_account_message_intro: "Hey there!" +# alert_account_message_pref: "To subscribe for class emails, you'll need to " +# alert_account_message_suf: "first." +# alert_account_message_create_url: "create an account" +# archmage_summary: "Interested in working on game graphics, user interface design, database and server organization, multiplayer networking, physics, sound, or game engine performance? Want to help build a game to help other people learn what you are good at? We have a lot to do and if you are an experienced programmer and want to develop for CodeCombat, this class is for you. We would love your help building the best programming game ever." +# archmage_introduction: "One of the best parts about building games is they synthesize so many different things. Graphics, sound, real-time networking, social networking, and of course many of the more common aspects of programming, from low-level database management, and server administration to user facing design and interface building. There's a lot to do, and if you're an experienced programmer with a hankering to really dive into the nitty-gritty of CodeCombat, this class might be for you. We would love to have your help building the best programming game ever." +# class_attributes: "Class Attributes" +# archmage_attribute_1_pref: "Knowledge in " +# archmage_attribute_1_suf: ", or a desire to learn. Most of our code is in this language. If you're a fan of Ruby or Python, you'll feel right at home. It's JavaScript, but with a nicer syntax." +# archmage_attribute_2: "Some experience in programming and personal initiative. We'll help you get oriented, but we can't spend much time training you." +# how_to_join: "How To Join" +# join_desc_1: "Anyone can help out! Just check out our " +# join_desc_2: "to get started, and check the box below to mark yourself as a brave Archmage and get the latest news by email. Want to chat about what to do or how to get more deeply involved? " +# join_desc_3: ", or find us in our " +# join_desc_4: "and we'll go from there!" +# join_url_email: "Email us" +# join_url_hipchat: "public HipChat room" +# more_about_archmage: "Learn More About Becoming an Archmage" +# archmage_subscribe_desc: "Get emails on new coding opportunities and announcements." +# artisan_summary_pref: "Want to design levels and expand CodeCombat's arsenal? People are playing through our content at a pace faster than we can build! Right now, our level editor is barebone, so be wary. Making levels will be a little challenging and buggy. If you have visions of campaigns spanning for-loops to" +# artisan_summary_suf: ", then this class is for you." +# artisan_introduction_pref: "We must construct additional levels! People be clamoring for more content, and we can only build so many ourselves. Right now your workstation is level one; our level editor is barely usable even by its creators, so be wary. If you have visions of campaigns spanning for-loops to" +# artisan_introduction_suf: ", then this class might be for you." +# artisan_attribute_1: "Any experience in building content like this would be nice, such as using Blizzard's level editors. But not required!" +# artisan_attribute_2: "A hankering to do a whole lot of testing and iteration. To make good levels, you need to take it to others and watch them play it, and be prepared to find a lot of things to fix." +# artisan_attribute_3: "For the time being, endurance en par with an Adventurer. Our Level Editor is super preliminary and frustrating to use. You have been warned!" +# artisan_join_desc: "Use the Level Editor in these steps, give or take:" +# artisan_join_step1: "Read the documentation." +# artisan_join_step2: "Create a new level and explore existing levels." +# artisan_join_step3: "Find us in our public HipChat room for help." +# artisan_join_step4: "Post your levels on the forum for feedback." +# more_about_artisan: "Learn More About Becoming an Artisan" +# artisan_subscribe_desc: "Get emails on level editor updates and announcements." +# adventurer_summary: "Let us be clear about your role: you are the tank. You are going to take heavy damage. We need people to try out brand-new levels and help identify how to make things better. The pain will be enormous; making good games is a long process and no one gets it right the first time. If you can endure and have a high constitution score, then this class is for you." +# adventurer_introduction: "Let's be clear about your role: you are the tank. You're going to take heavy damage. We need people to try out brand-new levels and help identify how to make things better. The pain will be enormous; making good games is a long process and no one gets it right the first time. If you can endure and have a high constitution score, then this class might be for you." +# adventurer_attribute_1: "A thirst for learning. You want to learn how to code and we want to teach you how to code. You'll probably be doing most of the teaching in this case, though." +# adventurer_attribute_2: "Charismatic. Be gentle but articulate about what needs improving, and offer suggestions on how to improve." +# adventurer_join_pref: "Either get together with (or recruit!) an Artisan and work with them, or check the box below to receive emails when there are new levels to test. We'll also be posting about levels to review on our networks like" +# adventurer_forum_url: "our forum" +# adventurer_join_suf: "so if you prefer to be notified those ways, sign up there!" +# more_about_adventurer: "Learn More About Becoming an Adventurer" +# adventurer_subscribe_desc: "Get emails when there are new levels to test." +# scribe_summary_pref: "CodeCombat is not just going to be a bunch of levels. It will also be a resource of programming knowledge that players can hook into. That way, each Artisan can link to a detailed article that for the player's edification: documentation akin to what the " +# scribe_summary_suf: " has built. If you enjoy explaining programming concepts, then this class is for you." +# scribe_introduction_pref: "CodeCombat isn't just going to be a bunch of levels. It will also include a resource for knowledge, a wiki of programming concepts that levels can hook into. That way rather than each Artisan having to describe in detail what a comparison operator is, they can simply link their level to the Article describing them that is already written for the player's edification. Something along the lines of what the " +# scribe_introduction_url_mozilla: "Mozilla Developer Network" +# scribe_introduction_suf: " has built. If your idea of fun is articulating the concepts of programming in Markdown form, then this class might be for you." +# scribe_attribute_1: "Skill in words is pretty much all you need. Not only grammar and spelling, but able to convey complicated ideas to others." +# contact_us_url: "Contact us" +# scribe_join_description: "tell us a little about yourself, your experience with programming and what sort of things you'd like to write about. We'll go from there!" +# more_about_scribe: "Learn More About Becoming a Scribe" +# scribe_subscribe_desc: "Get emails about article writing announcements." +# diplomat_summary: "There is a large interest in CodeCombat in other countries that do not speak English! We are looking for translators who are willing to spend their time translating the site's corpus of words so that CodeCombat is accessible across the world as soon as possible. If you'd like to help getting CodeCombat international, then this class is for you." +# diplomat_introduction_pref: "So, if there's one thing we learned from the " +# diplomat_launch_url: "launch in October" +# diplomat_introduction_suf: "it's that there is sizeable interest in CodeCombat in other countries! We're building a corps of translators eager to turn one set of words into another set of words to get CodeCombat as accessible across the world as possible. If you like getting sneak peeks at upcoming content and getting these levels to your fellow nationals ASAP, then this class might be for you." +# diplomat_attribute_1: "Fluency in English and the language you would like to translate to. When conveying complicated ideas, it's important to have a strong grasp in both!" +# diplomat_join_pref_github: "Find your language locale file " +# diplomat_github_url: "on GitHub" +# diplomat_join_suf_github: ", edit it online, and submit a pull request. Also, check this box below to keep up-to-date on new internationalization developments!" +# more_about_diplomat: "Learn More About Becoming a Diplomat" +# diplomat_subscribe_desc: "Get emails about i18n developments and levels to translate." +# ambassador_summary: "We are trying to build a community, and every community needs a support team when there are troubles. We have got chats, emails, and social networks so that our users can get acquainted with the game. If you want to help people get involved, have fun, and learn some programming, then this class is for you." +# ambassador_introduction: "This is a community we're building, and you are the connections. We've got Olark chats, emails, and social networks with lots of people to talk with and help get acquainted with the game and learn from. If you want to help people get involved and have fun, and get a good feel of the pulse of CodeCombat and where we're going, then this class might be for you." +# ambassador_attribute_1: "Communication skills. Be able to identify the problems players are having and help them solve them. Also, keep the rest of us informed about what players are saying, what they like and don't like and want more of!" +# ambassador_join_desc: "tell us a little about yourself, what you've done and what you'd be interested in doing. We'll go from there!" +# ambassador_join_note_strong: "Note" +# ambassador_join_note_desc: "One of our top priorities is to build multiplayer where players having difficulty solving levels can summon higher level wizards to help them. This will be a great way for ambassadors to do their thing. We'll keep you posted!" +# more_about_ambassador: "Learn More About Becoming an Ambassador" +# ambassador_subscribe_desc: "Get emails on support updates and multiplayer developments." +# counselor_summary: "None of the above roles fit what you are interested in? Do not worry, we are on the lookout for anybody who wants a hand in the development of CodeCombat! If you are interested in teaching, game development, open source management, or anything else that you think will be relevant to us, then this class is for you." +# counselor_introduction_1: "Do you have life experience? A different perspective on things that can help us decide how to shape CodeCombat? Of all these roles, this will probably take the least time, but individually you may make the most difference. We're on the lookout for wisened sages, particularly in areas like: teaching, game development, open source project management, technical recruiting, entrepreneurship, or design." +# counselor_introduction_2: "Or really anything that is relevant to the development of CodeCombat. If you have knowledge and want to share it to help grow this project, then this class might be for you." +# counselor_attribute_1: "Experience, in any of the areas above or something you think might be helpful." +# counselor_attribute_2: "A little bit of free time!" +# counselor_join_desc: "tell us a little about yourself, what you've done and what you'd be interested in doing. We'll put you in our contact list and be in touch when we could use advice (not too often)." +# more_about_counselor: "Learn More About Becoming a Counselor" +# changes_auto_save: "Changes are saved automatically when you toggle checkboxes." +# diligent_scribes: "Our Diligent Scribes:" +# powerful_archmages: "Our Powerful Archmages:" +# creative_artisans: "Our Creative Artisans:" +# brave_adventurers: "Our Brave Adventurers:" +# translating_diplomats: "Our Translating Diplomats:" +# helpful_ambassadors: "Our Helpful Ambassadors:" + +# classes: +# archmage_title: "Archmage" +# archmage_title_description: "(Coder)" +# artisan_title: "Artisan" +# artisan_title_description: "(Level Builder)" +# adventurer_title: "Adventurer" +# adventurer_title_description: "(Level Playtester)" +# scribe_title: "Scribe" +# scribe_title_description: "(Article Editor)" +# diplomat_title: "Diplomat" +# diplomat_title_description: "(Translator)" +# ambassador_title: "Ambassador" +# ambassador_title_description: "(Support)" +# counselor_title: "Counselor" +# counselor_title_description: "(Expert/Teacher)" + +# ladder: +# please_login: "Please log in first before playing a ladder game." +# my_matches: "My Matches" +# simulate: "Simulate" +# simulation_explanation: "By simulating games you can get your game ranked faster!" +# simulate_games: "Simulate Games!" +# simulate_all: "RESET AND SIMULATE GAMES" +# games_simulated_by: "Games simulated by you:" +# games_simulated_for: "Games simulated for you:" +# games_simulated: "Games simulated" +# games_played: "Games played" +# ratio: "Ratio" +# leaderboard: "Leaderboard" +# battle_as: "Battle as " +# summary_your: "Your " +# summary_matches: "Matches - " +# summary_wins: " Wins, " +# summary_losses: " Losses" +# rank_no_code: "No New Code to Rank" +# rank_my_game: "Rank My Game!" +# rank_submitting: "Submitting..." +# rank_submitted: "Submitted for Ranking" +# rank_failed: "Failed to Rank" +# rank_being_ranked: "Game Being Ranked" +# code_being_simulated: "Your new code is being simulated by other players for ranking. This will refresh as new matches come in." +# no_ranked_matches_pre: "No ranked matches for the " +# no_ranked_matches_post: " team! Play against some competitors and then come back here to get your game ranked." +# choose_opponent: "Choose an Opponent" +# tutorial_play: "Play Tutorial" +# tutorial_recommended: "Recommended if you've never played before" +# tutorial_skip: "Skip Tutorial" +# tutorial_not_sure: "Not sure what's going on?" +# tutorial_play_first: "Play the Tutorial first." +# simple_ai: "Simple AI" +# warmup: "Warmup" +# vs: "VS" + +# multiplayer_launch: +# introducing_dungeon_arena: "Introducing Dungeon Arena" +# new_way: "The new way to compete with code." +# to_battle: "To Battle, Developers!" +# modern_day_sorcerer: "You know how to code? That's badass. You're a modern-day sorcerer! Isn't about time that you used your magic coding powers to command your minions in epic combat? And we're not talking robots here." +# arenas_are_here: "CodeCombat head-to-head multiplayer arenas are here." +# ladder_explanation: "Choose your heroes, enchant your human or ogre armies, and climb your way over defeated fellow Wizards to reach the top of the ladders–then challenge your friends in our glorious, asynchronous multiplayer coding arenas. If you're feeling creative, you can even" +# fork_our_arenas: "fork our arenas" +# create_worlds: "and create your own worlds." +# javascript_rusty: "JavaScript a bit rusty? Don't worry; there's a" +# tutorial: "tutorial" +# new_to_programming: ". New to programming? Hit our beginner campaign to skill up." +# so_ready: "I Am So Ready for This" + +# loading_error: +# could_not_load: "Error loading from server" +# connection_failure: "Connection failed." +# unauthorized: "You need to be signed in. Do you have cookies disabled?" +# forbidden: "You do not have the permissions." +# not_found: "Not found." +# not_allowed: "Method not allowed." +# timeout: "Server timeout." +# conflict: "Resource conflict." +# bad_input: "Bad input." +# server_error: "Server error." +# unknown: "Unknown error." + +# resources: +# 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" +# patches: "Patches" +# model: "Model" diff --git a/app/locale/de-DE.coffee b/app/locale/de-DE.coffee new file mode 100644 index 000000000..e159b5827 --- /dev/null +++ b/app/locale/de-DE.coffee @@ -0,0 +1,671 @@ +module.exports = nativeDescription: "Deutsch (Deutschland)", englishDescription: "German (Germany)", translation: + common: + loading: "Lade..." + saving: "Speichere..." + sending: "Übertrage..." +# send: "Send" + cancel: "Abbrechen" + save: "Speichern" +# publish: "Publish" +# create: "Create" + delay_1_sec: "1 Sekunde" + delay_3_sec: "3 Sekunden" + delay_5_sec: "5 Sekunden" + manual: "Manuell" +# fork: "Fork" + play: "Abspielen" +# retry: "Retry" + + units: + second: "Sekunde" + seconds: "Sekunden" + minute: "Minute" + minutes: "Minuten" + hour: "Stunde" + hours: "Stunden" + + modal: + close: "Schließen" + okay: "Okay" + + not_found: + page_not_found: "Seite nicht gefunden" + + nav: + play: "Spielen" + editor: "Editor" + blog: "Blog" + forum: "Forum" + admin: "Administration" + home: "Home" + contribute: "Helfen" + legal: "Rechtliches" + about: "Über" + contact: "Kontakt" + twitter_follow: "Twitter" + employers: "Mitarbeiter" + + versions: + save_version_title: "Neue Version speichern" + new_major_version: "Neue Hauptversion" + cla_prefix: "Damit Änderungen gespeichert werden können, musst du unsere Lizenzbedingungen (" + cla_url: "CLA" + cla_suffix: ") akzeptieren." + cla_agree: "Ich stimme zu" + + login: + sign_up: "Registrieren" + log_in: "Einloggen" +# logging_in: "Logging In" + log_out: "Ausloggen" + recover: "Account wiederherstellen" + + recover: + recover_account_title: "Account Wiederherstellung" + send_password: "Wiederherstellungskennwort senden" + + signup: + create_account_title: "Account anlegen, um Fortschritt zu speichern" + description: "Es ist kostenlos. Nur noch ein paar Dinge, dann kannst Du loslegen." + email_announcements: "Erhalte Benachrichtigungen per Email" + coppa: "Älter als 13 oder nicht aus den USA" + coppa_why: "(Warum?)" + creating: "Erzeuge Account..." + sign_up: "Neuen Account anlegen" + log_in: "mit Passwort einloggen" +# social_signup: "Or, you can sign up through Facebook or G+:" + + home: + slogan: "Lerne spielend JavaScript" + no_ie: "CodeCombat läuft nicht im IE8 oder älteren Browsern. Tut uns Leid!" + no_mobile: "CodeCombat ist nicht für Mobilgeräte optimiert und funktioniert möglicherweise nicht." + play: "Spielen" + old_browser: "Oh! Dein Browser ist zu alt für CodeCombat. Sorry!" + old_browser_suffix: "Du kannst es trotzdem versuchen, aber es wird wahrscheinlich nicht funktionieren." + campaign: "Kampagne" + for_beginners: "Für Anfänger" + multiplayer: "Mehrspieler" + for_developers: "Für Entwickler" + + play: + choose_your_level: "Wähle dein Level" + adventurer_prefix: "Du kannst zu jedem Level springen oder diskutiere die Level " + adventurer_forum: "im Abenteurerforum" + adventurer_suffix: "." + campaign_beginner: "Anfängerkampagne" + campaign_beginner_description: "... in der Du die Zauberei der Programmierung lernst." + campaign_dev: "Beliebiges schwierigeres Level" + campaign_dev_description: "... in welchem Du die Bedienung erlernst, indem Du etwas schwierigeres machst." + campaign_multiplayer: "Multiplayerarena" + campaign_multiplayer_description: "... in der Du Kopf-an-Kopf gegen andere Spieler programmierst." + campaign_player_created: "Von Spielern erstellt" + campaign_player_created_description: "... in welchem Du gegen die Kreativität eines <a href=\"/contribute#artisan\">Artisan Zauberers</a> kämpfst." + level_difficulty: "Schwierigkeit: " + play_as: "Spiele als " + spectate: "Zuschauen" + + contact: + contact_us: "Kontaktiere CodeCombat" + welcome: "Schön von Dir zu hören! Benutze dieses Formular um uns eine Email zu schicken." + contribute_prefix: "Wenn Du Interesse hast, uns zu unterstützen dann sieh dir die " + contribute_page: "Unterstützer Seite" + contribute_suffix: " an!" + forum_prefix: "Für alle öffentlichen Themen, benutze stattdessen " + forum_page: "unser Forum" + forum_suffix: "." + send: "Sende Feedback" +# contact_candidate: "Contact Candidate" +# recruitment_reminder: "Use this form to reach out to candidates you are interested in interviewing. Remember that CodeCombat charges 18% of first-year salary. The fee is due upon hiring the employee and is refundable for 90 days if the employee does not remain employed. Part time, remote, and contract employees are free, as are interns." + + diplomat_suggestion: + title: "Hilf CodeCombat zu übersetzen!" + sub_heading: "Wir brauchen Deine Sprachfähigkeiten." + pitch_body: "Wir entwickeln CodeCombat in Englisch, aber wir haben Spieler in der ganzen Welt. Viele von ihnen wollen in Deutsch spielen, sprechen aber kein Englisch. Wenn Du also beide Sprachen beherrscht, melde Dich an um ein Diplomat zu werden und hilf die Website und die Levels zu Deutsch zu übersetzen." + missing_translations: "Solange wir nicht alles ins Deutsche übesetzt haben, siehst Du die englische Übersetzung, wo Deutsch leider noch nicht zur Verfügung steht." + learn_more: "Finde heraus, wie Du ein Diplomat werden kannst" + subscribe_as_diplomat: "Schreibe dich als Diplomat ein" + + wizard_settings: + title: "Zauberer Einstellungen" + customize_avatar: "Individualisiere deinen Avatar" +# active: "Active" +# color: "Color" +# group: "Group" + clothes: "Kleidung" + trim: "Applikationen" + cloud: "Wolke" +# team: "Team" + spell: "Zauber" + boots: "Stiefel" + hue: "Farbton" + saturation: "Sättigung" + lightness: "Helligkeit" + + account_settings: + title: "Accounteinstellungen" + not_logged_in: "Logge Dich ein oder lege einen Account an, um deine Einstellungen ändern zu können." + autosave: "Sichere Änderungen automatisch" + me_tab: "Ich" + picture_tab: "Bild" + wizard_tab: "Zauberer" + password_tab: "Passwort" + emails_tab: "Emails" + admin: "Admin" + wizard_color: "Die Farbe der Kleidung des Zauberers" + new_password: "Neues Passwort" + new_password_verify: "Passwort verifizieren" + email_subscriptions: "Email Abonnements" + email_announcements: "Ankündigungen" + email_notifications: "Benachrichtigungen" + email_notifications_description: "Erhalte regelmäßig Benachrichtigungen zu deinem Account." + email_announcements_description: "Erhalte regelmäßig Ankündigungen zu deinem Account." + contributor_emails: "Unterstützer Email" + contribute_prefix: "Wir suchen nach Leuten, die mitmachen! Schau dir die" + contribute_page: "Unterstützer Seite" + contribute_suffix: " an um mehr zu erfahren." + email_toggle: "Alles wählen" + error_saving: "Fehler beim Speichern" + saved: "Änderungen gespeichert" + password_mismatch: "Passwörter stimmen nicht überein." +# job_profile: "Job Profile" +# job_profile_approved: "Your job profile has been approved by CodeCombat. Employers will be able to see it until you either mark it inactive or it has not been changed for four weeks." +# job_profile_explanation: "Hi! Fill this out, and we will get in touch about finding you a software developer job." + + account_profile: + edit_settings: "Einstellungen ändern" + profile_for_prefix: "Profil von " + profile_for_suffix: "" +# approved: "Approved" +# not_approved: "Not Approved" +# looking_for: "Looking for:" +# last_updated: "Last updated:" +# contact: "Contact" +# work_experience: "Work Experience" +# education: "Education" +# our_notes: "Our Notes" +# projects: "Projects" + +# employers: +# want_to_hire_our_players: "Want to hire expert CodeCombat players?" +# contact_george: "Contact George to see our candidates" +# candidates_count_prefix: "We currently have " +# candidates_count_many: "many" +# candidates_count_suffix: "highly skilled and vetted developers looking for work." +# candidate_name: "Name" +# candidate_location: "Location" +# candidate_looking_for: "Looking For" +# candidate_role: "Role" +# candidate_top_skills: "Top Skills" +# candidate_years_experience: "Yrs Exp" +# candidate_last_updated: "Last Updated" + + play_level: + level_load_error: "Level konnte nicht geladen werden: " + done: "Fertig" + grid: "Raster" + customize_wizard: "Bearbeite den Zauberer" + home: "Startseite" + guide: "Hilfe" + multiplayer: "Multiplayer" + restart: "Neustart" + goals: "Ziele" + action_timeline: "Aktionszeitstrahl" + click_to_select: "Klicke auf eine Einheit, um sie auszuwählen." + reload_title: "Gesamten Code neu laden?" + reload_really: "Bist Du sicher, dass Du das Level neu beginnen willst?" + reload_confirm: "Alles neu laden" + victory_title_prefix: "" + victory_title_suffix: " Abgeschlossen" + victory_sign_up: "Melde Dich an, um Fortschritte zu speichern" + victory_sign_up_poke: "Möchtest Du Neuigkeiten per Mail erhalten? Erstelle einen kostenlosen Account und wir halten Dich auf dem Laufenden." + victory_rate_the_level: "Bewerte das Level: " + victory_rank_my_game: "Werte mein Spiel" + victory_ranking_game: "Einreichen..." + victory_return_to_ladder: "Zurück zur Rangliste" + victory_play_next_level: "Spiel das nächste Level" + victory_go_home: "Geh auf die Startseite" + victory_review: "Erzähl uns davon!" + victory_hour_of_code_done: "Bist Du fertig?" + victory_hour_of_code_done_yes: "Ja, ich bin mit meiner Code-Stunde fertig!" + multiplayer_title: "Multiplayer Einstellungen" + multiplayer_link_description: "Gib diesen Link jedem, der mitmachen will." + multiplayer_hint_label: "Hinweis:" + multiplayer_hint: " Klick den Link, um alles auszuwählen, dann drück ⌘-C oder Strg-C um den Link zu kopieren." + multiplayer_coming_soon: "Mehr Multiplayerfeatures werden kommen!" + guide_title: "Anleitung" + tome_minion_spells: "Die Zaubersprüche Deiner Knechte" + tome_read_only_spells: "Nur-lesen Zauberspüche" + tome_other_units: "Andere Einheiten" + tome_cast_button_castable: "Führe aus" + tome_cast_button_casting: "Ausführen" + tome_cast_button_cast: "Zauberspuch ausführen" + tome_autocast_delay: "Verzögerung der automatischen Ausführung" + tome_select_spell: "Wähle einen Zauber" + tome_select_a_thang: "Wähle jemanden aus, um " + tome_available_spells: "Verfügbare Zauber" + hud_continue: "Weiter (drücke Shift + Leertaste)" + spell_saved: "Zauber gespeichert" + skip_tutorial: "Überspringen (Esc)" + editor_config: "Editor Einstellungen" + editor_config_title: "Editor Einstellungen" + editor_config_language_label: "Programmiersprache" + editor_config_language_description: "Bestimme die Programmiersprache in der du arbeiten möchtest." + editor_config_keybindings_label: "Tastenbelegung" + editor_config_keybindings_default: "Standard (Ace)" + editor_config_keybindings_description: "Fügt zusätzliche Tastenkombinationen, bekannt aus anderen Editoren, hinzu" + editor_config_invisibles_label: "Zeige unsichtbare Zeichen" + editor_config_invisibles_description: "Zeigt unsichtbare Zeichen wie Leertasten an." + editor_config_indentguides_label: "Zeige Einrückungshilfe" + editor_config_indentguides_description: "Zeigt vertikale Linien an um Einrückungen besser zu sehen." + editor_config_behaviors_label: "Intelligentes Verhalten" + editor_config_behaviors_description: "Vervollständigt automatisch Klammern und Anführungszeichen." + loading_ready: "Bereit!" + tip_insert_positions: "Halte 'Umschalt' gedrückt und klicke auf die Karte um die Koordinaten einzufügen." + tip_toggle_play: "Wechsel zwischen Play und Pause mit Strg+P." + tip_scrub_shortcut: "Spule vor und zurück mit Strg+[ und Strg+]" + tip_guide_exists: "Klicke auf die Anleitung am oberen Ende der Seite für nützliche Informationen" + tip_open_source: "CodeCombat ist 100% quelloffen!" + tip_beta_launch: "CodeCombat startete seine Beta im Oktober 2013." + tip_js_beginning: "JavaScript ist nur der Anfang." + tip_autocast_setting: "Ändere die Einstellungen für das automatische Ausführen über das Zahnrad neben dem Ausführen Knopf" + think_solution: "Denke über die Lösung nach, nicht über das Problem." + tip_theory_practice: "In der Theorie gibt es keinen Unterschied zwischen Theorie und Praxis. In der Praxis schon. - Yogi Berra" + tip_error_free: "Es gibt zwei Wege fehlerfreie Programme zu schreiben; nur der Dritte funktioniert. - Alan Perlis" + tip_debugging_program: "Wenn Debugging der Prozess zum Fehler entfernen ist, dann muss Programmieren der Prozess sein Fehler zu machen. - Edsger W. Dijkstra" + tip_forums: "Gehe zum Forum und sage uns was du denkst!" + tip_baby_coders: "In der Zukunft werden sogar Babies Erzmagier sein." + tip_morale_improves: "Das Laden wird weiter gehen bis die Stimmung sich verbessert." + tip_all_species: "Wir glauben an gleiche Chancen für alle Arten Programmieren zu lernen." +# tip_reticulating: "Reticulating spines." + tip_harry: "Du bist ein Zauberer, " + tip_great_responsibility: "Mit großen Programmierfähigkeiten kommt große Verantwortung." + tip_munchkin: "Wenn du dein Gemüse nicht isst, besucht dich ein Zwerg während du schläfst." + tip_binary: "Es gibt auf der Welt nur 10 Arten von Menschen: die, welche Binär verstehen und die, welche nicht." + tip_commitment_yoda: "Ein Programmier muss die größte Hingabe haben, den ernstesten Verstand. ~ Yoda" + tip_no_try: "Tu. Oder tu nicht. Es gibt kein Versuchen. - Yoda" + tip_patience: "Geduld du musst haben, junger Padawan. - Yoda" + tip_documented_bug: "Ein dokumentierter Fehler ist kein Fehler; er ist ein Merkmal." + tip_impossible: "Es wirkt immer unmöglich bis es vollbracht ist. - Nelson Mandela" + tip_talk_is_cheap: "Reden ist billig. Zeig mir den Code. - Linus Torvalds" + tip_first_language: "Das schwierigste, das du jemals lernen wirst, ist die erste Programmiersprache. - Alan Kay" + time_current: "Aktuell" + time_total: "Total" + time_goto: "Gehe zu" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" + + admin: + av_title: "Administrator Übersicht" + av_entities_sub_title: "Entitäten" + av_entities_users_url: "Benutzer" + av_entities_active_instances_url: "Aktive Instanzen" + av_other_sub_title: "Sonstige" +# av_other_debug_base_url: "Base (for debugging base.jade)" + u_title: "Benutzerliste" + lg_title: "Letzte Spiele" +# clas: "CLAs" + + editor: + main_title: "CodeCombat Editoren" + main_description: "Entwerfe deine eigenen Level, Kampagnen, Einheiten und Lernmaterial. Wir stellen alle Werkzeuge zur Verfügung, die Du dafür benötigst!" + article_title: "Artikel Editor" + article_description: "Schreiben Sie Artikel, die anderen Spieler einen Überblick über Programmierkonzepte geben und in einer Vielzahl von Ebenen und Kampagnen genutzt werden können." +# thang_title: "Thang Editor" + thang_description: "Entwerfe Einheiten, definiere ihre Standardlogik, Grafiken und Töne. Zurzeit werden nur Flash Vektorgrafiken unterstützt." + level_title: "Level Editor" + level_description: "Beinhaltet die Werkzeuge zum Scripten, Hochladen von Tönen und zur Konstruktion eigener Logik, damit jedes erdenkliches Level erstellt werden kann. Genau die Sachen, die wir selber benutzen!" + security_notice: "Viele Hauptfunktionen der Editoren sind standardmäßig noch nicht aktiviert. Sobald die Sicherheit dieser Systeme gewährleistet ist, werden sie generell freigeschaltet. Falls Du diese Funktionen früher nutzen möchtest, " + contact_us: "setze dich mit uns in Verbindung!" + hipchat_prefix: "Besuche uns auch in unserem" + hipchat_url: "HipChat room." +# back: "Back" + revert: "Zurücksetzen" + revert_models: "Models zurücksetzen." +# fork_title: "Fork New Version" +# fork_creating: "Creating Fork..." +# more: "More" +# wiki: "Wiki" +# live_chat: "Live Chat" + level_some_options: "Einige Einstellungsmöglichkeiten?" + level_tab_thangs: "Thangs" + level_tab_scripts: "Skripte" + level_tab_settings: "Einstellungen" + level_tab_components: "Komponenten" + level_tab_systems: "Systeme" + level_tab_thangs_title: "Aktuelle Thangs" +# level_tab_thangs_all: "All" + level_tab_thangs_conditions: "Startbedingungen" + level_tab_thangs_add: "Thangs hinzufügen" +# delete: "Delete" +# duplicate: "Duplicate" + level_settings_title: "Einstellungen" + level_component_tab_title: "Aktuelle Komponenten" + level_component_btn_new: "neue Komponente erstellen" + level_systems_tab_title: "Aktuelle Systeme" + level_systems_btn_new: "neues System erstellen" + level_systems_btn_add: "System hinzufügen" + level_components_title: "Zurück zu allen Thangs" + level_components_type: "Typ" + level_component_edit_title: "Komponente bearbeiten" + level_component_config_schema: "Konfigurationsschema" + level_component_settings: "Einstellungen" + level_system_edit_title: "System bearbeiten" + create_system_title: "neues System erstellen" + new_component_title: "Neue Komponente erstellen" + new_component_field_system: "System" + new_article_title: "Erstelle einen neuen Artikel" +# new_thang_title: "Create a New Thang Type" + new_level_title: "Erstelle ein neues Level" +# article_search_title: "Search Articles Here" +# thang_search_title: "Search Thang Types Here" +# level_search_title: "Search Levels Here" +# signup_to_create: "Sign Up to Create a New Content" +# read_only_warning2: "Note: you can't save any edits here, because you're not logged in." + + article: + edit_btn_preview: "Vorschau" + edit_article_title: "Artikel bearbeiten" + + general: + and: "und" + name: "Name" + body: "Inhalt" + version: "Version" + commit_msg: "Commit Nachricht" +# version_history: "Version History" + version_history_for: "Versionsgeschichte für: " + result: "Ergebnis" + results: "Ergebnisse" + description: "Beschreibung" + or: "oder" +# subject: "Subject" + email: "Email" + password: "Passwort" + message: "Nachricht" + code: "Code" + ladder: "Rangliste" + when: "Wann" + opponent: "Gegner" + rank: "Rang" + score: "Punktzahl" + win: "Sieg" + loss: "Niederlage" + tie: "Unentschieden" + easy: "Einfach" + medium: "Mittel" + hard: "Schwer" +# player: "Player" + + about: + who_is_codecombat: "Wer ist CodeCombat?" + why_codecombat: "Warum CodeCombat?" + who_description_prefix: "gründeten CodeCombat im Jahre 2013 zusammen. Wir entwickelten außerdem " + who_description_suffix: ", die meist benutzte (#1) Web and iOS Applikation 2008 zum Lernen des Schreibens von chinesischen und japanischen Schriftzeichen." + who_description_ending: "Nun ist es an der Zeit, den Leuten das Programmieren beizubringen." + why_paragraph_1: "Als er Skritter machte, wusste George nicht wie man programmiert und war permanent darüber frustriert, dass er seine Ideen nicht umsetzen konnte. Danach versuchte er es zu lernen, aber das ging ihm zu langsam. Sein Mitbewohner versuchte Codecademy, als er sich umorientierte und aufhörte zu lehren, aber \"langweilte sich\". Jede Woche begann ein neuer Freund mit Codecademy und ließ es dann wieder bleiben. Wir erkannten, dass es das gleiche Problem war, welches wir mit Skritter gelöst hatten: Leute lernen eine Fähigkeit mittels langsamer, intersiver Lerneinheiten, wobei sie schnelle, umfassende Übung bräuchten. Wir kennen Abhilfe." + why_paragraph_2: "Programmieren lernen? Du brauchst keine Stunden. Du musst einen Haufen Code schreiben und dabei Spaß haben." + why_paragraph_3_prefix: "Darum geht's beim Programmieren. Es soll Spaß machen. Nicht so einen Spaß wie" + why_paragraph_3_italic: "jau, 'ne Plakette" + why_paragraph_3_center: "sondern Spaß wie" + why_paragraph_3_italic_caps: "NEIN MUTTI ICH MUSS NOCH DEN LEVEL BEENDEN !" + why_paragraph_3_suffix: "Deshalb ist CodeCombat ein Multiplayerspiel und kein spielähnlicher Kurs. Wir werden nicht aufhören bis du nicht mehr aufhören kannst -- nur diesmal ist das eine gute Sache." + why_paragraph_4: "Wenn dich Spiele süchtig machen, dass lass dich von diesem süchtig machen und werde ein Zauberer des Technologiezeitalters." + why_ending: "Und hey, es kostet nichts. " + why_ending_url: "Beginne jetzt zu zaubern!" + george_description: "CEO, Businesstyp, Web Designer, Game Designer und Champion der Programmieranfänger überall." + scott_description: "Außergewöhnlicher Programmierer, Softwarearchitekt, Küchenzauberer und Finanzmeister. Scott ist der Vernünftige." + nick_description: "Programmierzauberer, exzentrischer Motivationskünstler und Auf-den-Kopf-stell-Experimentierer. Nick könnte alles mögliche tun und entschied CodeCombat zu bauen." + jeremy_description: "Kundendienstmagier, Usability Tester und Community-Organisator. Wahrscheinlich hast du schon mit Jeremy gesprochen." + michael_description: "Programmierer, Systemadministrator und studentisch technisches Wunderkind, Michael hält unsere Server am Laufen." + glen_description: "Programmier und leidenschaftlicher Spieleentwickler mit der Motivation die Welt, durch das Entwickeln von Sachen die zählen, zu einem besseren Platz zu machen. Das Wort 'unmöglich' kann nicht in seinem Wortschatz gefunden werden. Neue Fähigkeiten zu lernen ist seine Leidenschaft!" + + legal: + page_title: "Rechtliches" + opensource_intro: "CodeCombat ist Free-to-Play und vollständig Open Source." + opensource_description_prefix: "Schau dir " + github_url: "unsere GitHub-Seite" + opensource_description_center: " an und mach mit wenn Du möchtest! CodeCombat baut auf duzenden Open Source Projekten auf, und wir lieben sie. Schau dir die Liste in " + archmage_wiki_url: "unserem Erzmagier-Wiki" + opensource_description_suffix: " an, welche Software dieses Spiel möglich macht." + practices_title: "Best Practices" + practices_description: "Dies sind unsere Versprechen an dich, den Spieler, in weniger Fachchinesisch." + privacy_title: "Datenschutz" + privacy_description: "Wir werden deine persönlichen Daten nicht verkaufen. Letztenendes beabsichtigen wir, durch Vermittlung von Jobs zu verdienen, aber sei versichert, dass wir nicht deine persönlichen Daten ohne deine ausdrückliche Einwilligung interessierten Firmen zur Verfügung stellen werden." + security_title: "Datensicherheit" + security_description: "Wir streben an, deine persönlichen Daten sicher zu verwahren. Als Open Source Projekt ist unsere Site frei zugänglich für jedermann, auch um unsere Sicherheitsmaßnahmen in Augenschein zu nehmen und zu verbessern." + email_title: "Email" + email_description_prefix: "Wir werden dich nicht mit Spam überschwemmen. Mittels" + email_settings_url: "deiner Emaileinstellungen" + email_description_suffix: "oder durch von uns gesendete Links kannst du jederzeit deine Einstellungen ändern und Abonnements kündigen." + cost_title: "Kosten" + cost_description: "CodeCombat ist zur Zeit 100% kostenlos! Eines unserer Hauptziele ist, es dabei zu belassen, so dass es so viele Leute wie möglich spielen können, unabhängig davon in welcher Lebenssituation sie sich befinden. Falls dunkle Wolken aufziehen, könnten wir manche Inhalte im Rahmen eines Abonnements anbieten, aber lieber nicht. Mit etwas Glück können wir die Firma erhalten durch:" + recruitment_title: "Recruiting" + recruitment_description_prefix: "Hier bei CodeCombat kannst du ein mächtiger Zauberer werden, nicht nur im Spiel, sondern auch in der Realität." + url_hire_programmers: "Niemand kann schnell genug Programmierer einstellen." + recruitment_description_suffix: "So wenn du deine Fähigkeiten entwickelt hast und zustimmst, werden wir deine besten Leistungen den tausenden Arbeitgebern demonstrieren, welche nur auf die Gelegentheit warten, dich einzustellen. Sie bezahlen uns ein bisschen, und sie bezahlen dir " + recruitment_description_italic: "jede Menge" + recruitment_description_ending: ", die Seite bleibt kostenlos und jeder ist glücklich. So der Plan." +# copyrights_title: "Copyrights and Licenses" +# contributor_title: "Contributor License Agreement" +# contributor_description_prefix: "All contributions, both on the site and on our GitHub repository, are subject to our" +# cla_url: "CLA" +# contributor_description_suffix: "to which you should agree before contributing." +# code_title: "Code - MIT" +# code_description_prefix: "All code owned by CodeCombat or hosted on codecombat.com, both in the GitHub repository or in the codecombat.com database, is licensed under the" +# mit_license_url: "MIT license" +# code_description_suffix: "This includes all code in Systems and Components that are made available by CodeCombat for the purpose of creating levels." +# art_title: "Art/Music - Creative Commons " +# art_description_prefix: "All common content is available under the" +# cc_license_url: "Creative Commons Attribution 4.0 International License" +# art_description_suffix: "Common content is anything made generally available by CodeCombat for the purpose of creating Levels. This includes:" +# art_music: "Music" +# art_sound: "Sound" +# art_artwork: "Artwork" +# art_sprites: "Sprites" +# art_other: "Any and all other non-code creative works that are made available when creating Levels." +# art_access: "Currently there is no universal, easy system for fetching these assets. In general, fetch them from the URLs as used by the site, contact us for assistance, or help us in extending the site to make these assets more easily accessible." +# art_paragraph_1: "For attribution, please name and link to codecombat.com near where the source is used or where appropriate for the medium. For example:" +# use_list_1: "If used in a movie or another game, include codecombat.com in the credits." +# use_list_2: "If used on a website, include a link near the usage, for example underneath an image, or in a general attributions page where you might also mention other Creative Commons works and open source software being used on the site. Something that's already clearly referencing CodeCombat, such as a blog post mentioning CodeCombat, does not need some separate attribution." +# art_paragraph_2: "If the content being used is created not by CodeCombat but instead by a user of codecombat.com, attribute them instead, and follow attribution directions provided in that resource's description if there are any." +# rights_title: "Rights Reserved" +# rights_desc: "All rights are reserved for Levels themselves. This includes" +# rights_scripts: "Scripts" +# rights_unit: "Unit configuration" +# rights_description: "Description" +# rights_writings: "Writings" +# rights_media: "Media (sounds, music) and any other creative content made specifically for that Level and not made generally available when creating Levels." +# rights_clarification: "To clarify, anything that is made available in the Level Editor for the purpose of making levels is under CC, whereas the content created with the Level Editor or uploaded in the course of creation of Levels is not." +# nutshell_title: "In a Nutshell" +# nutshell_description: "Any resources we provide in the Level Editor are free to use as you like for creating Levels. But we reserve the right to restrict distribution of the Levels themselves (that are created on codecombat.com) so that they may be charged for in the future, if that's what ends up happening." +# canonical: "The English version of this document is the definitive, canonical version. If there are any discrepencies between translations, the English document takes precedence." + +# contribute: +# page_title: "Contributing" +# character_classes_title: "Character Classes" +# introduction_desc_intro: "We have high hopes for CodeCombat." +# introduction_desc_pref: "We want to be where programmers of all stripes come to learn and play together, introduce others to the wonderful world of coding, and reflect the best parts of the community. We can't and don't want to do that alone; what makes projects like GitHub, Stack Overflow and Linux great are the people who use them and build on them. To that end, " +# introduction_desc_github_url: "CodeCombat is totally open source" +# introduction_desc_suf: ", and we aim to provide as many ways as possible for you to take part and make this project as much yours as ours." +# introduction_desc_ending: "We hope you'll join our party!" +# introduction_desc_signature: "- Nick, George, Scott, Michael, Jeremy and Glen" +# alert_account_message_intro: "Hey there!" +# alert_account_message_pref: "To subscribe for class emails, you'll need to " +# alert_account_message_suf: "first." +# alert_account_message_create_url: "create an account" +# archmage_summary: "Interested in working on game graphics, user interface design, database and server organization, multiplayer networking, physics, sound, or game engine performance? Want to help build a game to help other people learn what you are good at? We have a lot to do and if you are an experienced programmer and want to develop for CodeCombat, this class is for you. We would love your help building the best programming game ever." +# archmage_introduction: "One of the best parts about building games is they synthesize so many different things. Graphics, sound, real-time networking, social networking, and of course many of the more common aspects of programming, from low-level database management, and server administration to user facing design and interface building. There's a lot to do, and if you're an experienced programmer with a hankering to really dive into the nitty-gritty of CodeCombat, this class might be for you. We would love to have your help building the best programming game ever." +# class_attributes: "Class Attributes" +# archmage_attribute_1_pref: "Knowledge in " +# archmage_attribute_1_suf: ", or a desire to learn. Most of our code is in this language. If you're a fan of Ruby or Python, you'll feel right at home. It's JavaScript, but with a nicer syntax." +# archmage_attribute_2: "Some experience in programming and personal initiative. We'll help you get oriented, but we can't spend much time training you." +# how_to_join: "How To Join" +# join_desc_1: "Anyone can help out! Just check out our " +# join_desc_2: "to get started, and check the box below to mark yourself as a brave Archmage and get the latest news by email. Want to chat about what to do or how to get more deeply involved? " +# join_desc_3: ", or find us in our " +# join_desc_4: "and we'll go from there!" +# join_url_email: "Email us" +# join_url_hipchat: "public HipChat room" +# more_about_archmage: "Learn More About Becoming an Archmage" +# archmage_subscribe_desc: "Get emails on new coding opportunities and announcements." +# artisan_summary_pref: "Want to design levels and expand CodeCombat's arsenal? People are playing through our content at a pace faster than we can build! Right now, our level editor is barebone, so be wary. Making levels will be a little challenging and buggy. If you have visions of campaigns spanning for-loops to" +# artisan_summary_suf: ", then this class is for you." +# artisan_introduction_pref: "We must construct additional levels! People be clamoring for more content, and we can only build so many ourselves. Right now your workstation is level one; our level editor is barely usable even by its creators, so be wary. If you have visions of campaigns spanning for-loops to" +# artisan_introduction_suf: ", then this class might be for you." +# artisan_attribute_1: "Any experience in building content like this would be nice, such as using Blizzard's level editors. But not required!" +# artisan_attribute_2: "A hankering to do a whole lot of testing and iteration. To make good levels, you need to take it to others and watch them play it, and be prepared to find a lot of things to fix." +# artisan_attribute_3: "For the time being, endurance en par with an Adventurer. Our Level Editor is super preliminary and frustrating to use. You have been warned!" +# artisan_join_desc: "Use the Level Editor in these steps, give or take:" +# artisan_join_step1: "Read the documentation." +# artisan_join_step2: "Create a new level and explore existing levels." +# artisan_join_step3: "Find us in our public HipChat room for help." +# artisan_join_step4: "Post your levels on the forum for feedback." +# more_about_artisan: "Learn More About Becoming an Artisan" +# artisan_subscribe_desc: "Get emails on level editor updates and announcements." +# adventurer_summary: "Let us be clear about your role: you are the tank. You are going to take heavy damage. We need people to try out brand-new levels and help identify how to make things better. The pain will be enormous; making good games is a long process and no one gets it right the first time. If you can endure and have a high constitution score, then this class is for you." +# adventurer_introduction: "Let's be clear about your role: you are the tank. You're going to take heavy damage. We need people to try out brand-new levels and help identify how to make things better. The pain will be enormous; making good games is a long process and no one gets it right the first time. If you can endure and have a high constitution score, then this class might be for you." +# adventurer_attribute_1: "A thirst for learning. You want to learn how to code and we want to teach you how to code. You'll probably be doing most of the teaching in this case, though." +# adventurer_attribute_2: "Charismatic. Be gentle but articulate about what needs improving, and offer suggestions on how to improve." +# adventurer_join_pref: "Either get together with (or recruit!) an Artisan and work with them, or check the box below to receive emails when there are new levels to test. We'll also be posting about levels to review on our networks like" +# adventurer_forum_url: "our forum" +# adventurer_join_suf: "so if you prefer to be notified those ways, sign up there!" +# more_about_adventurer: "Learn More About Becoming an Adventurer" +# adventurer_subscribe_desc: "Get emails when there are new levels to test." +# scribe_summary_pref: "CodeCombat is not just going to be a bunch of levels. It will also be a resource of programming knowledge that players can hook into. That way, each Artisan can link to a detailed article that for the player's edification: documentation akin to what the " +# scribe_summary_suf: " has built. If you enjoy explaining programming concepts, then this class is for you." +# scribe_introduction_pref: "CodeCombat isn't just going to be a bunch of levels. It will also include a resource for knowledge, a wiki of programming concepts that levels can hook into. That way rather than each Artisan having to describe in detail what a comparison operator is, they can simply link their level to the Article describing them that is already written for the player's edification. Something along the lines of what the " +# scribe_introduction_url_mozilla: "Mozilla Developer Network" +# scribe_introduction_suf: " has built. If your idea of fun is articulating the concepts of programming in Markdown form, then this class might be for you." +# scribe_attribute_1: "Skill in words is pretty much all you need. Not only grammar and spelling, but able to convey complicated ideas to others." +# contact_us_url: "Contact us" +# scribe_join_description: "tell us a little about yourself, your experience with programming and what sort of things you'd like to write about. We'll go from there!" +# more_about_scribe: "Learn More About Becoming a Scribe" +# scribe_subscribe_desc: "Get emails about article writing announcements." +# diplomat_summary: "There is a large interest in CodeCombat in other countries that do not speak English! We are looking for translators who are willing to spend their time translating the site's corpus of words so that CodeCombat is accessible across the world as soon as possible. If you'd like to help getting CodeCombat international, then this class is for you." +# diplomat_introduction_pref: "So, if there's one thing we learned from the " +# diplomat_launch_url: "launch in October" +# diplomat_introduction_suf: "it's that there is sizeable interest in CodeCombat in other countries! We're building a corps of translators eager to turn one set of words into another set of words to get CodeCombat as accessible across the world as possible. If you like getting sneak peeks at upcoming content and getting these levels to your fellow nationals ASAP, then this class might be for you." +# diplomat_attribute_1: "Fluency in English and the language you would like to translate to. When conveying complicated ideas, it's important to have a strong grasp in both!" +# diplomat_join_pref_github: "Find your language locale file " +# diplomat_github_url: "on GitHub" +# diplomat_join_suf_github: ", edit it online, and submit a pull request. Also, check this box below to keep up-to-date on new internationalization developments!" +# more_about_diplomat: "Learn More About Becoming a Diplomat" +# diplomat_subscribe_desc: "Get emails about i18n developments and levels to translate." +# ambassador_summary: "We are trying to build a community, and every community needs a support team when there are troubles. We have got chats, emails, and social networks so that our users can get acquainted with the game. If you want to help people get involved, have fun, and learn some programming, then this class is for you." +# ambassador_introduction: "This is a community we're building, and you are the connections. We've got Olark chats, emails, and social networks with lots of people to talk with and help get acquainted with the game and learn from. If you want to help people get involved and have fun, and get a good feel of the pulse of CodeCombat and where we're going, then this class might be for you." +# ambassador_attribute_1: "Communication skills. Be able to identify the problems players are having and help them solve them. Also, keep the rest of us informed about what players are saying, what they like and don't like and want more of!" +# ambassador_join_desc: "tell us a little about yourself, what you've done and what you'd be interested in doing. We'll go from there!" +# ambassador_join_note_strong: "Note" +# ambassador_join_note_desc: "One of our top priorities is to build multiplayer where players having difficulty solving levels can summon higher level wizards to help them. This will be a great way for ambassadors to do their thing. We'll keep you posted!" +# more_about_ambassador: "Learn More About Becoming an Ambassador" +# ambassador_subscribe_desc: "Get emails on support updates and multiplayer developments." +# counselor_summary: "None of the above roles fit what you are interested in? Do not worry, we are on the lookout for anybody who wants a hand in the development of CodeCombat! If you are interested in teaching, game development, open source management, or anything else that you think will be relevant to us, then this class is for you." +# counselor_introduction_1: "Do you have life experience? A different perspective on things that can help us decide how to shape CodeCombat? Of all these roles, this will probably take the least time, but individually you may make the most difference. We're on the lookout for wisened sages, particularly in areas like: teaching, game development, open source project management, technical recruiting, entrepreneurship, or design." +# counselor_introduction_2: "Or really anything that is relevant to the development of CodeCombat. If you have knowledge and want to share it to help grow this project, then this class might be for you." +# counselor_attribute_1: "Experience, in any of the areas above or something you think might be helpful." +# counselor_attribute_2: "A little bit of free time!" +# counselor_join_desc: "tell us a little about yourself, what you've done and what you'd be interested in doing. We'll put you in our contact list and be in touch when we could use advice (not too often)." +# more_about_counselor: "Learn More About Becoming a Counselor" +# changes_auto_save: "Changes are saved automatically when you toggle checkboxes." +# diligent_scribes: "Our Diligent Scribes:" +# powerful_archmages: "Our Powerful Archmages:" +# creative_artisans: "Our Creative Artisans:" +# brave_adventurers: "Our Brave Adventurers:" +# translating_diplomats: "Our Translating Diplomats:" +# helpful_ambassadors: "Our Helpful Ambassadors:" + + classes: + archmage_title: "Erzmagier" + archmage_title_description: "(Programmierer)" + artisan_title: "Handwerker" + artisan_title_description: "(Level Entwickler)" + adventurer_title: "Abenteurer" + adventurer_title_description: "(Level Spieltester)" + scribe_title: "Schreiber" + scribe_title_description: "(Artikel Editor)" + diplomat_title: "Diplomat" + diplomat_title_description: "(Übersetzer)" + ambassador_title: "Botschafter" + ambassador_title_description: "(Support)" + counselor_title: "Berater" + counselor_title_description: "(Experte/Lehrer)" + + ladder: + please_login: "Bitte logge dich zunächst ein, bevor du ein Ladder-Game spielst." + my_matches: "Meine Matches" + simulate: "Simuliere" +# simulation_explanation: "By simulating games you can get your game ranked faster!" +# simulate_games: "Simulate Games!" +# simulate_all: "RESET AND SIMULATE GAMES" +# games_simulated_by: "Games simulated by you:" +# games_simulated_for: "Games simulated for you:" +# games_simulated: "Games simulated" +# games_played: "Games played" +# ratio: "Ratio" +# leaderboard: "Leaderboard" +# battle_as: "Battle as " +# summary_your: "Your " +# summary_matches: "Matches - " +# summary_wins: " Wins, " +# summary_losses: " Losses" +# rank_no_code: "No New Code to Rank" +# rank_my_game: "Rank My Game!" +# rank_submitting: "Submitting..." +# rank_submitted: "Submitted for Ranking" +# rank_failed: "Failed to Rank" +# rank_being_ranked: "Game Being Ranked" +# code_being_simulated: "Your new code is being simulated by other players for ranking. This will refresh as new matches come in." +# no_ranked_matches_pre: "No ranked matches for the " +# no_ranked_matches_post: " team! Play against some competitors and then come back here to get your game ranked." + choose_opponent: "Wähle einen Gegner" + tutorial_play: "Spiele Tutorial" + tutorial_recommended: "Empfohlen, wenn du noch nie zuvor gespielt hast." + tutorial_skip: "Überspringe Tutorial" +# tutorial_not_sure: "Not sure what's going on?" + tutorial_play_first: "Spiele zuerst das Tutorial." + simple_ai: "Einfache KI" + warmup: "Aufwärmen" + vs: "VS" + +# multiplayer_launch: +# introducing_dungeon_arena: "Introducing Dungeon Arena" +# new_way: "The new way to compete with code." +# to_battle: "To Battle, Developers!" +# modern_day_sorcerer: "You know how to code? That's badass. You're a modern-day sorcerer! Isn't about time that you used your magic coding powers to command your minions in epic combat? And we're not talking robots here." +# arenas_are_here: "CodeCombat head-to-head multiplayer arenas are here." +# ladder_explanation: "Choose your heroes, enchant your human or ogre armies, and climb your way over defeated fellow Wizards to reach the top of the ladders–then challenge your friends in our glorious, asynchronous multiplayer coding arenas. If you're feeling creative, you can even" +# fork_our_arenas: "fork our arenas" +# create_worlds: "and create your own worlds." +# javascript_rusty: "JavaScript a bit rusty? Don't worry; there's a" +# tutorial: "tutorial" +# new_to_programming: ". New to programming? Hit our beginner campaign to skill up." +# so_ready: "I Am So Ready for This" + +# loading_error: +# could_not_load: "Error loading from server" +# connection_failure: "Connection failed." +# unauthorized: "You need to be signed in. Do you have cookies disabled?" +# forbidden: "You do not have the permissions." +# not_found: "Not found." +# not_allowed: "Method not allowed." +# timeout: "Server timeout." +# conflict: "Resource conflict." +# bad_input: "Bad input." +# server_error: "Server error." +# unknown: "Unknown error." + +# resources: +# 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" +# patches: "Patches" +# model: "Model" diff --git a/app/locale/de.coffee b/app/locale/de.coffee index a2730973a..b663a249b 100644 --- a/app/locale/de.coffee +++ b/app/locale/de.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "Deutsch", englishDescription: "German", tra time_current: "Aktuell" time_total: "Total" time_goto: "Gehe zu" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: av_title: "Administrator Übersicht" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "Deutsch", englishDescription: "German", tra # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/el.coffee b/app/locale/el.coffee index 8b6696716..a67a3bfdb 100644 --- a/app/locale/el.coffee +++ b/app/locale/el.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "ελληνικά", englishDescription: "Gre # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "ελληνικά", englishDescription: "Gre # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/en-AU.coffee b/app/locale/en-AU.coffee index c6379eb82..a5ff9b044 100644 --- a/app/locale/en-AU.coffee +++ b/app/locale/en-AU.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "English (AU)", englishDescription: "English # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "English (AU)", englishDescription: "English # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/en-GB.coffee b/app/locale/en-GB.coffee index 39378ba4f..0ae817a19 100644 --- a/app/locale/en-GB.coffee +++ b/app/locale/en-GB.coffee @@ -125,11 +125,11 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # learn_more: "Learn more about being a Diplomat" # subscribe_as_diplomat: "Subscribe as a Diplomat" -# wizard_settings: + wizard_settings: # title: "Wizard Settings" -# customize_avatar: "Customize Your Avatar" + customize_avatar: "Customise Your Avatar" # active: "Active" -# color: "Color" + color: "Colour" # group: "Group" # clothes: "Clothes" # trim: "Trim" @@ -141,7 +141,7 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # saturation: "Saturation" # lightness: "Lightness" -# account_settings: + account_settings: # title: "Account Settings" # not_logged_in: "Log in or create an account to change your settings." # autosave: "Changes Save Automatically" @@ -151,7 +151,7 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # password_tab: "Password" # emails_tab: "Emails" # admin: "Admin" -# wizard_color: "Wizard Clothes Color" + wizard_color: "Wizard Clothes Colour" # new_password: "New Password" # new_password_verify: "Verify" # email_subscriptions: "Email Subscriptions" @@ -199,11 +199,11 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # candidate_years_experience: "Yrs Exp" # candidate_last_updated: "Last Updated" -# play_level: + play_level: # level_load_error: "Level could not be loaded: " # done: "Done" # grid: "Grid" -# customize_wizard: "Customize Wizard" + customize_wizard: "Customise Wizard" # home: "Home" # guide: "Guide" # multiplayer: "Multiplayer" @@ -257,7 +257,7 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # editor_config_invisibles_description: "Displays invisibles such as spaces or tabs." # editor_config_indentguides_label: "Show Indent Guides" # editor_config_indentguides_description: "Displays vertical lines to see indentation better." -# editor_config_behaviors_label: "Smart Behaviors" + editor_config_behaviors_label: "Smart Behaviours" # editor_config_behaviors_description: "Autocompletes brackets, braces, and quotes." # loading_ready: "Ready!" # tip_insert_positions: "Shift+Click a point on the map to insert it into the spell editor." @@ -291,6 +291,9 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -394,13 +397,13 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # hard: "Hard" # player: "Player" -# about: + about: # who_is_codecombat: "Who is CodeCombat?" # why_codecombat: "Why CodeCombat?" # who_description_prefix: "together started CodeCombat in 2013. We also created " # who_description_suffix: "in 2008, growing it to the #1 web and iOS application for learning to write Chinese and Japanese characters." # who_description_ending: "Now it's time to teach people to write code." -# why_paragraph_1: "When making Skritter, George didn't know how to program and was constantly frustrated by his inability to implement his ideas. Afterwards, he tried learning, but the lessons were too slow. His housemate, wanting to reskill and stop teaching, tried Codecademy, but \"got bored.\" Each week another friend started Codecademy, then dropped off. We realized it was the same problem we'd solved with Skritter: people learning a skill via slow, intensive lessons when what they need is fast, extensive practice. We know how to fix that." + why_paragraph_1: "When making Skritter, George didn't know how to program and was constantly frustrated by his inability to implement his ideas. Afterwards, he tried learning, but the lessons were too slow. His housemate, wanting to reskill and stop teaching, tried Codecademy, but \"got bored.\" Each week another friend started Codecademy, then dropped off. We realised it was the same problem we'd solved with Skritter: people learning a skill via slow, intensive lessons when what they need is fast, extensive practice. We know how to fix that." # why_paragraph_2: "Need to learn to code? You don't need lessons. You need to write a lot of code and have a great time doing it." # why_paragraph_3_prefix: "That's what programming is about. It's gotta be fun. Not fun like" # why_paragraph_3_italic: "yay a badge" @@ -413,11 +416,11 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # george_description: "CEO, business guy, web designer, game designer, and champion of beginning programmers everywhere." # scott_description: "Programmer extraordinaire, software architect, kitchen wizard, and master of finances. Scott is the reasonable one." # nick_description: "Programming wizard, eccentric motivation mage, and upside-down experimenter. Nick can do anything and chooses to build CodeCombat." -# jeremy_description: "Customer support mage, usability tester, and community organizer; you've probably already spoken with Jeremy." + jeremy_description: "Customer support mage, usability tester, and community organiser; you've probably already spoken with Jeremy." # michael_description: "Programmer, sys-admin, and undergrad technical wunderkind, Michael is the person keeping our servers online." # glen_description: "Programmer and passionate game developer, with the motivation to make this world a better place, by developing things that matter. The word impossible can't be found in his dictionary. Learning new skills is his joy!" -# legal: + legal: # page_title: "Legal" # opensource_intro: "CodeCombat is free to play and completely open source." # opensource_description_prefix: "Check out " @@ -443,18 +446,18 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # recruitment_description_suffix: "so once you've sharpened your skills and if you agree, we will demo your best coding accomplishments to the thousands of employers who are drooling for the chance to hire you. They pay us a little, they pay you" # recruitment_description_italic: "a lot" # recruitment_description_ending: "the site remains free and everybody's happy. That's the plan." -# copyrights_title: "Copyrights and Licenses" -# contributor_title: "Contributor License Agreement" + copyrights_title: "Copyrights and Licences" + contributor_title: "Contributor Licence Agreement" # contributor_description_prefix: "All contributions, both on the site and on our GitHub repository, are subject to our" # cla_url: "CLA" # contributor_description_suffix: "to which you should agree before contributing." # code_title: "Code - MIT" # code_description_prefix: "All code owned by CodeCombat or hosted on codecombat.com, both in the GitHub repository or in the codecombat.com database, is licensed under the" -# mit_license_url: "MIT license" + mit_license_url: "MIT licence" # code_description_suffix: "This includes all code in Systems and Components that are made available by CodeCombat for the purpose of creating levels." # art_title: "Art/Music - Creative Commons " # art_description_prefix: "All common content is available under the" -# cc_license_url: "Creative Commons Attribution 4.0 International License" + cc_license_url: "Creative Commons Attribution 4.0 International Licence" # art_description_suffix: "Common content is anything made generally available by CodeCombat for the purpose of creating Levels. This includes:" # art_music: "Music" # art_sound: "Sound" @@ -478,7 +481,7 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # nutshell_description: "Any resources we provide in the Level Editor are free to use as you like for creating Levels. But we reserve the right to restrict distribution of the Levels themselves (that are created on codecombat.com) so that they may be charged for in the future, if that's what ends up happening." # canonical: "The English version of this document is the definitive, canonical version. If there are any discrepencies between translations, the English document takes precedence." -# contribute: + contribute: # page_title: "Contributing" # character_classes_title: "Character Classes" # introduction_desc_intro: "We have high hopes for CodeCombat." @@ -491,8 +494,8 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # alert_account_message_pref: "To subscribe for class emails, you'll need to " # alert_account_message_suf: "first." # alert_account_message_create_url: "create an account" -# archmage_summary: "Interested in working on game graphics, user interface design, database and server organization, multiplayer networking, physics, sound, or game engine performance? Want to help build a game to help other people learn what you are good at? We have a lot to do and if you are an experienced programmer and want to develop for CodeCombat, this class is for you. We would love your help building the best programming game ever." -# archmage_introduction: "One of the best parts about building games is they synthesize so many different things. Graphics, sound, real-time networking, social networking, and of course many of the more common aspects of programming, from low-level database management, and server administration to user facing design and interface building. There's a lot to do, and if you're an experienced programmer with a hankering to really dive into the nitty-gritty of CodeCombat, this class might be for you. We would love to have your help building the best programming game ever." + archmage_summary: "Interested in working on game graphics, user interface design, database and server organisation, multiplayer networking, physics, sound, or game engine performance? Want to help build a game to help other people learn what you are good at? We have a lot to do and if you are an experienced programmer and want to develop for CodeCombat, this class is for you. We would love your help building the best programming game ever." + archmage_introduction: "One of the best parts about building games is they synthesise so many different things. Graphics, sound, real-time networking, social networking, and of course many of the more common aspects of programming, from low-level database management, and server administration to user facing design and interface building. There's a lot to do, and if you're an experienced programmer with a hankering to really dive into the nitty-gritty of CodeCombat, this class might be for you. We would love to have your help building the best programming game ever." # class_attributes: "Class Attributes" # archmage_attribute_1_pref: "Knowledge in " # archmage_attribute_1_suf: ", or a desire to learn. Most of our code is in this language. If you're a fan of Ruby or Python, you'll feel right at home. It's JavaScript, but with a nicer syntax." @@ -546,7 +549,7 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # diplomat_attribute_1: "Fluency in English and the language you would like to translate to. When conveying complicated ideas, it's important to have a strong grasp in both!" # diplomat_join_pref_github: "Find your language locale file " # diplomat_github_url: "on GitHub" -# diplomat_join_suf_github: ", edit it online, and submit a pull request. Also, check this box below to keep up-to-date on new internationalization developments!" + diplomat_join_suf_github: ", edit it online, and submit a pull request. Also, check this box below to keep up-to-date on new internationalisation developments!" # more_about_diplomat: "Learn More About Becoming a Diplomat" # diplomat_subscribe_desc: "Get emails about i18n developments and levels to translate." # ambassador_summary: "We are trying to build a community, and every community needs a support team when there are troubles. We have got chats, emails, and social networks so that our users can get acquainted with the game. If you want to help people get involved, have fun, and learn some programming, then this class is for you." @@ -563,7 +566,7 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # counselor_attribute_1: "Experience, in any of the areas above or something you think might be helpful." # counselor_attribute_2: "A little bit of free time!" # counselor_join_desc: "tell us a little about yourself, what you've done and what you'd be interested in doing. We'll put you in our contact list and be in touch when we could use advice (not too often)." -# more_about_counselor: "Learn More About Becoming a Counselor" + more_about_counselor: "Learn More About Becoming a Counsellor" # changes_auto_save: "Changes are saved automatically when you toggle checkboxes." # diligent_scribes: "Our Diligent Scribes:" # powerful_archmages: "Our Powerful Archmages:" @@ -572,7 +575,7 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # translating_diplomats: "Our Translating Diplomats:" # helpful_ambassadors: "Our Helpful Ambassadors:" -# classes: + classes: # archmage_title: "Archmage" # archmage_title_description: "(Coder)" # artisan_title: "Artisan" @@ -585,7 +588,7 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # diplomat_title_description: "(Translator)" # ambassador_title: "Ambassador" # ambassador_title_description: "(Support)" -# counselor_title: "Counselor" + counselor_title: "Counsellor" # counselor_title_description: "(Expert/Teacher)" # ladder: @@ -665,3 +668,4 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/en-US.coffee b/app/locale/en-US.coffee index 07ad6a251..4d5b615fe 100644 --- a/app/locale/en-US.coffee +++ b/app/locale/en-US.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "English (US)", englishDescription: "English # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "English (US)", englishDescription: "English # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/en.coffee b/app/locale/en.coffee index 1fc298454..4696d8dae 100644 --- a/app/locale/en.coffee +++ b/app/locale/en.coffee @@ -15,6 +15,9 @@ fork: "Fork" play: "Play" retry: "Retry" + watch: "Watch" + unwatch: "Unwatch" + submit_patch: "Submit Patch" units: second: "second" @@ -36,6 +39,7 @@ editor: "Editor" blog: "Blog" forum: "Forum" + account: "Account" admin: "Admin" home: "Home" contribute: "Contribute" @@ -170,6 +174,8 @@ job_profile: "Job Profile" job_profile_approved: "Your job profile has been approved by CodeCombat. Employers will be able to see it until you either mark it inactive or it has not been changed for four weeks." job_profile_explanation: "Hi! Fill this out, and we will get in touch about finding you a software developer job." + sample_profile: "See a sample profile" + view_profile: "View Your Profile" account_profile: edit_settings: "Edit Settings" @@ -306,6 +312,13 @@ lg_title: "Latest Games" clas: "CLAs" + community: + level_editor: "Level Editor" + main_title: "CodeCombat Community" + facebook: "Facebook" + twitter: "Twitter" + gplus: "Google+" + editor: main_title: "CodeCombat Editors" main_description: "Build your own levels, campaigns, units and educational content. We provide all the tools you need!" @@ -315,8 +328,8 @@ thang_description: "Build units, defining their default logic, graphics and audio. Currently only supports importing Flash exported vector graphics." level_title: "Level Editor" level_description: "Includes the tools for scripting, uploading audio, and constructing custom logic to create all sorts of levels. Everything we use ourselves!" - security_notice: "Many major features in these editors are not currently enabled by default. As we improve the security of these systems, they will be made generally available. If you'd like to use these features sooner, " - contact_us: "contact us!" + got_questions: "Questions about using the CodeCombat editors?" + contact_us: "Contact us!" hipchat_prefix: "You can also find us in our" hipchat_url: "HipChat room." back: "Back" @@ -668,3 +681,4 @@ user_schema: "User Schema" user_profile: "User Profile" patches: "Patches" + model: "Model" diff --git a/app/locale/es-419.coffee b/app/locale/es-419.coffee index 5b5070ad5..fedde9aa0 100644 --- a/app/locale/es-419.coffee +++ b/app/locale/es-419.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "español (América Latina)", englishDescrip # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "español (América Latina)", englishDescrip # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/es-ES.coffee b/app/locale/es-ES.coffee index d4245240d..730d883ea 100644 --- a/app/locale/es-ES.coffee +++ b/app/locale/es-ES.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/es.coffee b/app/locale/es.coffee index 70a12c764..cce4b4c11 100644 --- a/app/locale/es.coffee +++ b/app/locale/es.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "español", englishDescription: "Spanish", t # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "español", englishDescription: "Spanish", t # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/fa.coffee b/app/locale/fa.coffee index e80520b20..54373a554 100644 --- a/app/locale/fa.coffee +++ b/app/locale/fa.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "فارسی", englishDescription: "Persian", # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "فارسی", englishDescription: "Persian", # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/fi.coffee b/app/locale/fi.coffee index 749f530f0..487f11fd2 100644 --- a/app/locale/fi.coffee +++ b/app/locale/fi.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "suomi", englishDescription: "Finnish", tran # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "suomi", englishDescription: "Finnish", tran # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/fr.coffee b/app/locale/fr.coffee index 4d9d24b36..ad8d03579 100644 --- a/app/locale/fr.coffee +++ b/app/locale/fr.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "français", englishDescription: "French", t # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: av_title: "Vues d'administrateurs" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "français", englishDescription: "French", t # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/he.coffee b/app/locale/he.coffee index 5d35048c8..129a2544c 100644 --- a/app/locale/he.coffee +++ b/app/locale/he.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/hi.coffee b/app/locale/hi.coffee index d0bab3a62..5238b7fd8 100644 --- a/app/locale/hi.coffee +++ b/app/locale/hi.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "मानक हिन्दी", englishDe # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "मानक हिन्दी", englishDe # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/hu.coffee b/app/locale/hu.coffee index 3c4e4f26d..7d23e8ede 100644 --- a/app/locale/hu.coffee +++ b/app/locale/hu.coffee @@ -128,9 +128,9 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t wizard_settings: title: "Varázsló beállításai" customize_avatar: "Állítsd be az Avatarod!" -# active: "Active" -# color: "Color" -# group: "Group" + active: "Aktív" + color: "Szín" + group: "Csoport" clothes: "Öltözetek" # trim: "Trim" cloud: "Felhő" @@ -156,7 +156,7 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t new_password_verify: "Új jelszó megismétlése" email_subscriptions: "Hírlevél feliratkozások" email_announcements: "Bejelentések" -# email_notifications: "Notifications" + email_notifications: "Értesítések" # email_notifications_description: "Get periodic notifications for your account." email_announcements_description: "Szeretnél levelet kapni a legújabb fejlesztéseinkről?" contributor_emails: "Hozzájárulóknak szóló levelek" @@ -167,37 +167,37 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t error_saving: "Hiba a mentés során" saved: "Változtatások elmentve" password_mismatch: "A jelszavak nem egyeznek." -# job_profile: "Job Profile" -# job_profile_approved: "Your job profile has been approved by CodeCombat. Employers will be able to see it until you either mark it inactive or it has not been changed for four weeks." -# job_profile_explanation: "Hi! Fill this out, and we will get in touch about finding you a software developer job." + job_profile: "Munkaköri leírás" + job_profile_approved: "Munkaköri leírásodat a Codecombat jóváhagyta. Munkaadók mindaddig láthatják, amíg meg nem jelölöd inaktíként, vagy négy hétig,ha addig nem kerül megváltoztatásra." + job_profile_explanation: "Szió! Töltsd ki ezt és majd kapcsolatba lépünk veled és keresünk neked egy szoftware fejlesztői állást." account_profile: edit_settings: "Beállítások szerkesztése" # profile_for_prefix: "Profile for " # profile_for_suffix: "" -# approved: "Approved" -# not_approved: "Not Approved" -# looking_for: "Looking for:" -# last_updated: "Last updated:" -# contact: "Contact" -# work_experience: "Work Experience" -# education: "Education" + approved: "Jóváhagyva" + not_approved: "Nincs jóváhagyva" + looking_for: "Keres:" + last_updated: "Legutóbb napra-készre hozva:" + contact: "Kapcsolat" + work_experience: "Munkatapasztalat" + education: "Végzettség" # our_notes: "Our Notes" -# projects: "Projects" + projects: "Projektek" -# employers: -# want_to_hire_our_players: "Want to hire expert CodeCombat players?" -# contact_george: "Contact George to see our candidates" -# candidates_count_prefix: "We currently have " -# candidates_count_many: "many" -# candidates_count_suffix: "highly skilled and vetted developers looking for work." -# candidate_name: "Name" + munkaadók: + want_to_hire_our_players: "Akarsz szakértő CodeCombat játékosokat alkalmazni?" + contact_george: "Vedd fel a kapcsolatot George-dzsal, hogy megtekinthesd jelöltjeinket" + candidates_count_prefix: "Pillanatnyilag van" + candidates_count_many: "sok" + candidates_count_suffix: "magasan képzett és ellenőrzött fejlesztő, aki munkát keres." + candidate_name: "Név" # candidate_location: "Location" -# candidate_looking_for: "Looking For" -# candidate_role: "Role" + candidate_looking_for: "Keres" + candidate_role: "Szerep" # candidate_top_skills: "Top Skills" # candidate_years_experience: "Yrs Exp" -# candidate_last_updated: "Last Updated" + candidate_last_updated: "Legutóbb napra-készre hozva" play_level: level_load_error: "A pályát nem sikerült betölteni: " @@ -291,6 +291,9 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/id.coffee b/app/locale/id.coffee index cd3042d6b..638a78899 100644 --- a/app/locale/id.coffee +++ b/app/locale/id.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "Bahasa Indonesia", englishDescription: "Ind # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "Bahasa Indonesia", englishDescription: "Ind # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/it.coffee b/app/locale/it.coffee index ff6d6538f..cca118653 100644 --- a/app/locale/it.coffee +++ b/app/locale/it.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: av_title: "Vista amministratore" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/ja.coffee b/app/locale/ja.coffee index ae1f09f82..c8d4e74ce 100644 --- a/app/locale/ja.coffee +++ b/app/locale/ja.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "日本語", englishDescription: "Japanese", # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: av_title: "管理画面" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "日本語", englishDescription: "Japanese", # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/ko.coffee b/app/locale/ko.coffee index 14ff1c91a..40ad69d68 100644 --- a/app/locale/ko.coffee +++ b/app/locale/ko.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: av_title: "관리자 뷰" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/locale.coffee b/app/locale/locale.coffee index 7d0865c68..caa16b0ce 100644 --- a/app/locale/locale.coffee +++ b/app/locale/locale.coffee @@ -10,6 +10,9 @@ module.exports = 'en-AU': require './en-AU' # English (AU), English (AU) ru: require './ru' # русский язык, Russian de: require './de' # Deutsch, German + 'de-DE': require './de-DE' # Deutsch (Deutschland), German (Germany) + 'de-AT': require './de-AT' # Deutsch (Österreich), German (Austria) + 'de-CH': require './de-CH' # Deutsch (Schweiz), German (Switzerland) es: require './es' # español, Spanish 'es-419': require './es-419' # español (América Latina), Spanish (Latin America) 'es-ES': require './es-ES' # español (ES), Spanish (Spain) diff --git a/app/locale/lt.coffee b/app/locale/lt.coffee index 7adb4bcff..62e2868a0 100644 --- a/app/locale/lt.coffee +++ b/app/locale/lt.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/ms.coffee b/app/locale/ms.coffee index 939ff25ce..0afee741e 100644 --- a/app/locale/ms.coffee +++ b/app/locale/ms.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "Bahasa Melayu", englishDescription: "Bahasa # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "Bahasa Melayu", englishDescription: "Bahasa # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/nb.coffee b/app/locale/nb.coffee index 81d8d0a50..3a2d4b38a 100644 --- a/app/locale/nb.coffee +++ b/app/locale/nb.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "Norsk Bokmål", englishDescription: "Norweg # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "Norsk Bokmål", englishDescription: "Norweg # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/nl-BE.coffee b/app/locale/nl-BE.coffee index 1044f496b..1649435d6 100644 --- a/app/locale/nl-BE.coffee +++ b/app/locale/nl-BE.coffee @@ -169,7 +169,7 @@ module.exports = nativeDescription: "Nederlands (België)", englishDescription: password_mismatch: "Het wachtwoord komt niet overeen." job_profile: "Job Profiel" job_profile_approved: "Jouw job profiel werd goedgekeurd door CodeCombat. Werkgevers zullen het kunnen bekijken totdat je het inactief zet of als er geen verandering in komt voor vier weken." - job_profile_explanation: "Hey! Vul dit in en we zullen je contacteren om je een job als softwareontwikkelaar te helpen vinden." + job_profile_explanation: "Hey! Vul dit in en we zullen je contacteren om je een job als softwareontwikkelaar te helpen vinden." account_profile: edit_settings: "Instellingen Aanpassen" @@ -291,6 +291,9 @@ module.exports = nativeDescription: "Nederlands (België)", englishDescription: time_current: "Nu:" time_total: "Maximum:" time_goto: "Ga naar:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: av_title: "Administrator panels" @@ -357,7 +360,7 @@ module.exports = nativeDescription: "Nederlands (België)", englishDescription: article_search_title: "Zoek Artikels Hier" thang_search_title: "Zoek Thang Types Hier" level_search_title: "Zoek Levels Hier" - signup_to_create: "Registreer je om nieuwe content te maken" + signup_to_create: "Registreer je om nieuwe content te maken" # read_only_warning2: "Note: you can't save any edits here, because you're not logged in." article: @@ -665,3 +668,4 @@ module.exports = nativeDescription: "Nederlands (België)", englishDescription: user_schema: "Gebruikersschema" user_profile: "Gebruikersprofiel" # patches: "Patches" +# model: "Model" diff --git a/app/locale/nl-NL.coffee b/app/locale/nl-NL.coffee index 7d6010f42..4a2f4a1af 100644 --- a/app/locale/nl-NL.coffee +++ b/app/locale/nl-NL.coffee @@ -169,7 +169,7 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription password_mismatch: "Het wachtwoord komt niet overeen." job_profile: "Job Profiel" job_profile_approved: "Jouw job profiel werd goedgekeurd door CodeCombat. Werkgevers zullen het kunnen bekijken totdat je het inactief zet of als er geen verandering in komt voor vier weken." - job_profile_explanation: "Hey! Vul dit in en we zullen je contacteren om je een job als softwareontwikkelaar te helpen vinden." + job_profile_explanation: "Hey! Vul dit in en we zullen je contacteren om je een job als softwareontwikkelaar te helpen vinden." account_profile: edit_settings: "Instellingen Aanpassen" @@ -291,6 +291,9 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription time_current: "Nu:" time_total: "Maximum:" time_goto: "Ga naar:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: av_title: "Administrator panels" @@ -357,8 +360,8 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription article_search_title: "Zoek Artikels Hier" thang_search_title: "Zoek Thang Types Hier" level_search_title: "Zoek Levels Hier" - signup_to_create: "Registreer je om nieuwe content te maken" - read_only_warning: "Herinnering: Je kunt hier geen aanpassingen opslaan, want je bent niet ingelogd als administrator." + signup_to_create: "Registreer je om nieuwe content te maken" +# read_only_warning2: "Note: you can't save any edits here, because you're not logged in." article: edit_btn_preview: "Voorbeeld" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription user_schema: "Gebruikersschema" user_profile: "Gebruikersprofiel" # patches: "Patches" +# model: "Model" diff --git a/app/locale/nl.coffee b/app/locale/nl.coffee index 74b2764fe..5641a26fe 100644 --- a/app/locale/nl.coffee +++ b/app/locale/nl.coffee @@ -169,7 +169,7 @@ module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", t password_mismatch: "Het wachtwoord komt niet overeen." job_profile: "Job Profiel" job_profile_approved: "Jouw job profiel werd goedgekeurd door CodeCombat. Werkgevers zullen het kunnen bekijken totdat je het inactief zet of als er geen verandering in komt voor vier weken." - job_profile_explanation: "Hey! Vul dit in en we zullen je contacteren om je een job als softwareontwikkelaar te helpen vinden." + job_profile_explanation: "Hey! Vul dit in en we zullen je contacteren om je een job als softwareontwikkelaar te helpen vinden." account_profile: edit_settings: "Instellingen Aanpassen" @@ -291,6 +291,9 @@ module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", t time_current: "Nu:" time_total: "Maximum:" time_goto: "Ga naar:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: av_title: "Administrator panels" @@ -357,7 +360,7 @@ module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", t article_search_title: "Zoek Artikels Hier" thang_search_title: "Zoek Thang Types Hier" level_search_title: "Zoek Levels Hier" - signup_to_create: "Registreer je om nieuwe content te maken" + signup_to_create: "Registreer je om nieuwe content te maken" # read_only_warning2: "Note: you can't save any edits here, because you're not logged in." article: @@ -665,3 +668,4 @@ module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", t user_schema: "Gebruikersschema" user_profile: "Gebruikersprofiel" # patches: "Patches" +# model: "Model" diff --git a/app/locale/nn.coffee b/app/locale/nn.coffee index 4727bb0fb..80805c946 100644 --- a/app/locale/nn.coffee +++ b/app/locale/nn.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "Norwegian Nynorsk", englishDescription: "No # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "Norwegian Nynorsk", englishDescription: "No # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/no.coffee b/app/locale/no.coffee index ea1d96f30..fffbd449b 100644 --- a/app/locale/no.coffee +++ b/app/locale/no.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/pl.coffee b/app/locale/pl.coffee index 0f7a43299..bfe258c77 100644 --- a/app/locale/pl.coffee +++ b/app/locale/pl.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "język polski", englishDescription: "Polish # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: av_title: "Panel administracyjny" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "język polski", englishDescription: "Polish # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/pt-BR.coffee b/app/locale/pt-BR.coffee index f94918ab1..83d592fc9 100644 --- a/app/locale/pt-BR.coffee +++ b/app/locale/pt-BR.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "português do Brasil", englishDescription: # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: av_title: "Visualização de Administrador" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "português do Brasil", englishDescription: # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/pt-PT.coffee b/app/locale/pt-PT.coffee index 0d6efb57b..4692e2279 100644 --- a/app/locale/pt-PT.coffee +++ b/app/locale/pt-PT.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "Português europeu", englishDescription: "P # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: av_title: "Visualizações de Admin" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "Português europeu", englishDescription: "P # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/pt.coffee b/app/locale/pt.coffee index f073b3194..ace10e931 100644 --- a/app/locale/pt.coffee +++ b/app/locale/pt.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "português", englishDescription: "Portugues # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "português", englishDescription: "Portugues # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/ro.coffee b/app/locale/ro.coffee index 197846873..d11bf98f4 100644 --- a/app/locale/ro.coffee +++ b/app/locale/ro.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: av_title: "Admin vede" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/ru.coffee b/app/locale/ru.coffee index 2503bc31d..092f25d41 100644 --- a/app/locale/ru.coffee +++ b/app/locale/ru.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi time_current: "Текущее:" time_total: "Максимальное:" time_goto: "Перейти на:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: av_title: "Админ панель" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi user_schema: "Пользовательская Schema" user_profile: "Пользовательский профиль" # patches: "Patches" +# model: "Model" diff --git a/app/locale/sk.coffee b/app/locale/sk.coffee index c914496f6..543ab000a 100644 --- a/app/locale/sk.coffee +++ b/app/locale/sk.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/sl.coffee b/app/locale/sl.coffee index 441443097..6614a51ef 100644 --- a/app/locale/sl.coffee +++ b/app/locale/sl.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "slovenščina", englishDescription: "Sloven # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "slovenščina", englishDescription: "Sloven # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/sr.coffee b/app/locale/sr.coffee index c22596704..b19c7db87 100644 --- a/app/locale/sr.coffee +++ b/app/locale/sr.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/sv.coffee b/app/locale/sv.coffee index e8d709347..4ef8fc4bf 100644 --- a/app/locale/sv.coffee +++ b/app/locale/sv.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "Svenska", englishDescription: "Swedish", tr # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: av_title: "Administratörsvyer" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "Svenska", englishDescription: "Swedish", tr # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/th.coffee b/app/locale/th.coffee index 8a28e38cb..a4884c40b 100644 --- a/app/locale/th.coffee +++ b/app/locale/th.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "ไทย", englishDescription: "Thai", tra # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "ไทย", englishDescription: "Thai", tra # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/tr.coffee b/app/locale/tr.coffee index e29079e8d..81fe200f2 100644 --- a/app/locale/tr.coffee +++ b/app/locale/tr.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "Türkçe", englishDescription: "Turkish", t time_current: "Şimdi:" time_total: "Max:" time_goto: "Git:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: av_title: "Yönetici Görünümleri" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "Türkçe", englishDescription: "Turkish", t # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/uk.coffee b/app/locale/uk.coffee index 5972444cd..e99eef979 100644 --- a/app/locale/uk.coffee +++ b/app/locale/uk.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "українська мова", englishDesc # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "українська мова", englishDesc # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/ur.coffee b/app/locale/ur.coffee index 3ba0fe235..2f7ab791d 100644 --- a/app/locale/ur.coffee +++ b/app/locale/ur.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "اُردُو", englishDescription: "Urdu", # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "اُردُو", englishDescription: "Urdu", # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/vi.coffee b/app/locale/vi.coffee index b4a4e1fba..dd5991ab0 100644 --- a/app/locale/vi.coffee +++ b/app/locale/vi.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/zh-HANS.coffee b/app/locale/zh-HANS.coffee index c4c515d7e..313b790ed 100644 --- a/app/locale/zh-HANS.coffee +++ b/app/locale/zh-HANS.coffee @@ -73,7 +73,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese creating: "账户创建中……" sign_up: "注册" log_in: "登录" -# social_signup: "Or, you can sign up through Facebook or G+:" + social_signup: "或者,你可以通过Facebook或G+注册:" home: slogan: "通过游戏学习 Javascript" @@ -114,7 +114,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese forum_page: "我们的论坛" forum_suffix: "" send: "反馈意见" -# contact_candidate: "Contact Candidate" + contact_candidate: "联系参选人" # recruitment_reminder: "Use this form to reach out to candidates you are interested in interviewing. Remember that CodeCombat charges 18% of first-year salary. The fee is due upon hiring the employee and is refundable for 90 days if the employee does not remain employed. Part time, remote, and contract employees are free, as are interns." diplomat_suggestion: @@ -128,13 +128,13 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese wizard_settings: title: "设置向导" customize_avatar: "设置你的头像" -# active: "Active" -# color: "Color" -# group: "Group" + active: "启用" + color: "颜色" + group: "类别" clothes: "衣服" trim: "条纹" cloud: "云" -# team: "Team" + team: "队伍" spell: "魔法球" boots: "鞋子" hue: "颜色" @@ -177,27 +177,27 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese profile_for_suffix: "" # approved: "Approved" # not_approved: "Not Approved" -# looking_for: "Looking for:" -# last_updated: "Last updated:" -# contact: "Contact" -# work_experience: "Work Experience" -# education: "Education" + looking_for: "寻找" + last_updated: "最后一次更新:" + contact: "联系" + work_experience: "工作经验" + education: "教育程度" # our_notes: "Our Notes" -# projects: "Projects" + projects: "项目" # employers: -# want_to_hire_our_players: "Want to hire expert CodeCombat players?" + want_to_hire_our_players: "想要雇用CodeCombat上的专业玩家?" # contact_george: "Contact George to see our candidates" -# candidates_count_prefix: "We currently have " -# candidates_count_many: "many" + candidates_count_prefix: "我们当前有 " + candidates_count_many: "很多" # candidates_count_suffix: "highly skilled and vetted developers looking for work." -# candidate_name: "Name" -# candidate_location: "Location" -# candidate_looking_for: "Looking For" -# candidate_role: "Role" -# candidate_top_skills: "Top Skills" -# candidate_years_experience: "Yrs Exp" -# candidate_last_updated: "Last Updated" + candidate_name: "姓名" + candidate_location: "地点" + candidate_looking_for: "寻找" + candidate_role: "角色" + candidate_top_skills: "高级技能" + candidate_years_experience: "多年工作经验" + candidate_last_updated: "最后一次更新" play_level: level_load_error: "关卡不能载入: " @@ -250,17 +250,17 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese editor_config_title: "编辑器配置" editor_config_language_label: "编程语言" editor_config_language_description: "请输入你想写的编程语言." -# editor_config_keybindings_label: "Key Bindings" -# editor_config_keybindings_default: "Default (Ace)" + editor_config_keybindings_label: "按键设置s" + editor_config_keybindings_default: "默认 (Ace)" # editor_config_keybindings_description: "Adds additional shortcuts known from the common editors." -# editor_config_invisibles_label: "Show Invisibles" -# editor_config_invisibles_description: "Displays invisibles such as spaces or tabs." -# editor_config_indentguides_label: "Show Indent Guides" -# editor_config_indentguides_description: "Displays vertical lines to see indentation better." + editor_config_invisibles_label: "显示隐藏的" + editor_config_invisibles_description: "显示诸如空格或TAB键。" + editor_config_indentguides_label: "显示缩进提示" + editor_config_indentguides_description: "显示一条竖线以使缩进更明显。" # editor_config_behaviors_label: "Smart Behaviors" # editor_config_behaviors_description: "Autocompletes brackets, braces, and quotes." loading_ready: "载入完成!" -# tip_insert_positions: "Shift+Click a point on the map to insert it into the spell editor." + tip_insert_positions: "使用Shift+左键来插入拼写编辑器。" tip_toggle_play: "用 Ctrl+P 来暂停或继续" tip_scrub_shortcut: "用 Ctrl+[ 和 Ctrl+] 来倒退和快进." tip_guide_exists: "点击页面上方的指南, 可以获得更多有用信息." @@ -285,12 +285,15 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese tip_no_try: "做. 或是不做. 这世上不存在'尝试'这种东西. - 尤达大师" # tip_patience: "Patience you must have, young Padawan. - Yoda" tip_documented_bug: "一个写在文档里的漏洞不算漏洞, 那是个功能." - tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" + tip_impossible: "在事情未完成之前,一切都看似不可能. - 纳尔逊·曼德拉" tip_talk_is_cheap: "多说无用, 亮出你的代码. - Linus Torvalds" # tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" time_current: "现在:" time_total: "最大:" time_goto: "跳到:" + infinite_loop_try_again: "请重试" + infinite_loop_reset_level: "重置等级" + infinite_loop_comment_out: "为我的代码添加注释" admin: av_title: "管理员视图" @@ -358,7 +361,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese thang_search_title: "在这里搜索物品类型" level_search_title: "在这里搜索关卡" signup_to_create: "注册之后就可以创建一个新的关卡" -# read_only_warning2: "Note: you can't save any edits here, because you're not logged in." + read_only_warning2: "提示:你不能保存任何编辑,因为你没有登陆" article: edit_btn_preview: "预览" @@ -370,13 +373,13 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese body: "正文" version: "版本" commit_msg: "提交信息" -# version_history: "Version History" + version_history: "版本历史" version_history_for: "版本历史: " result: "结果" results: "结果" description: "描述" or: "或" -# subject: "Subject" + subject: "主题" email: "邮件" password: "密码" message: "信息" @@ -392,7 +395,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese easy: "容易" medium: "中等" hard: "困难" -# player: "Player" + player: "玩家" about: who_is_codecombat: "什么是 CodeCombat?" @@ -535,7 +538,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese scribe_introduction_url_mozilla: "Mozilla 开发者社区" # scribe_introduction_suf: " has built. If your idea of fun is articulating the concepts of programming in Markdown form, then this class might be for you." # scribe_attribute_1: "Skill in words is pretty much all you need. Not only grammar and spelling, but able to convey complicated ideas to others." -# contact_us_url: "Contact us" + contact_us_url: "联系我们" scribe_join_description: "介绍一下你自己, 比如你的编程经历和你喜欢写什么东西, 我们将从这里开始了解你!!" more_about_scribe: "了解如何成为一名文书" scribe_subscribe_desc: "通过电子邮件获得写作新文档的通知。" @@ -607,7 +610,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese summary_wins: " 胜利, " summary_losses: " 失败" rank_no_code: "没有新代码可供评分" -# rank_my_game: "Rank My Game!" + rank_my_game: "为我的游戏评分!" rank_submitting: "正在提交..." # rank_submitted: "Submitted for Ranking" rank_failed: "评分失败" @@ -662,6 +665,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese gplus_friends: "G+ 朋友" # gplus_friend_sessions: "G+ Friend Sessions" leaderboard: "排行榜" -# user_schema: "User Schema" -# user_profile: "User Profile" -# patches: "Patches" + user_schema: "用户模式" + user_profile: "User Profile" + patches: "补丁" +# model: "Model" diff --git a/app/locale/zh-HANT.coffee b/app/locale/zh-HANT.coffee index 14acbe304..d5d7456df 100644 --- a/app/locale/zh-HANT.coffee +++ b/app/locale/zh-HANT.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/locale/zh.coffee b/app/locale/zh.coffee index 3499c6e6c..3f33a7be0 100644 --- a/app/locale/zh.coffee +++ b/app/locale/zh.coffee @@ -291,6 +291,9 @@ module.exports = nativeDescription: "中文", englishDescription: "Chinese", tra # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" +# infinite_loop_try_again: "Try Again" +# infinite_loop_reset_level: "Reset Level" +# infinite_loop_comment_out: "Comment Out My Code" # admin: # av_title: "Admin Views" @@ -665,3 +668,4 @@ module.exports = nativeDescription: "中文", englishDescription: "Chinese", tra # user_schema: "User Schema" # user_profile: "User Profile" # patches: "Patches" +# model: "Model" diff --git a/app/models/CocoModel.coffee b/app/models/CocoModel.coffee index c93708ee2..b33177a3a 100644 --- a/app/models/CocoModel.coffee +++ b/app/models/CocoModel.coffee @@ -60,6 +60,7 @@ class CocoModel extends Backbone.Model return result.errors unless result.valid save: (attrs, options) -> + @set 'editPath', document.location.pathname options ?= {} success = options.success options.success = (resp) => @@ -68,7 +69,6 @@ class CocoModel extends Backbone.Model @markToRevert() @clearBackup() @trigger "save", @ - patch.setStatus 'accepted' for patch in @acceptedPatches or [] return super attrs, options fetch: -> @@ -95,7 +95,6 @@ class CocoModel extends Backbone.Model cloneNewMinorVersion: -> newData = $.extend(null, {}, @attributes) clone = new @constructor(newData) - clone.acceptedPatches = @acceptedPatches clone cloneNewMajorVersion: -> @@ -221,9 +220,11 @@ class CocoModel extends Backbone.Model delta = @getDelta() deltasLib.expandDelta(delta, @_revertAttributes, @schema()) - addPatchToAcceptOnSave: (patch) -> - @acceptedPatches ?= [] - @acceptedPatches.push patch - @acceptedPatches = _.uniq(@acceptedPatches, false, (p) -> p.id) + watch: (doWatch=true) -> + $.ajax("#{@urlRoot}/#{@id}/watch", {type:'PUT', data:{on:doWatch}}) + @watching = -> doWatch + + watching: -> + return me.id in (@get('watchers') or []) module.exports = CocoModel diff --git a/app/models/Level.coffee b/app/models/Level.coffee index 7832c329a..b180218fb 100644 --- a/app/models/Level.coffee +++ b/app/models/Level.coffee @@ -8,7 +8,8 @@ module.exports = class Level extends CocoModel urlRoot: "/db/level" serialize: (supermodel) -> - o = _.cloneDeep @attributes # slow in level editor when there are hundreds of Thangs + # o = _.cloneDeep @attributes # slow in level editor when there are hundreds of Thangs + o = $.extend true, {}, @attributes # Figure out Components o.levelComponents = _.cloneDeep (lc.attributes for lc in supermodel.getModels LevelComponent) diff --git a/app/models/Patch.coffee b/app/models/Patch.coffee index 68b62eca9..c505c93c0 100644 --- a/app/models/Patch.coffee +++ b/app/models/Patch.coffee @@ -5,4 +5,7 @@ module.exports = class PatchModel extends CocoModel urlRoot: "/db/patch" setStatus: (status) -> - $.ajax("/db/patch/#{@id}/status", {type:"PUT", data: {status:status}}) \ No newline at end of file + PatchModel.setStatus @id, status + + @setStatus: (id, status) -> + $.ajax("/db/patch/#{id}/status", {type:"PUT", data: {status:status}}) \ No newline at end of file diff --git a/app/schemas/models/level_session.coffee b/app/schemas/models/level_session.coffee index 670dc9ad4..28db97daf 100644 --- a/app/schemas/models/level_session.coffee +++ b/app/schemas/models/level_session.coffee @@ -101,9 +101,13 @@ _.extend LevelSessionSchema.properties, source: type: 'string' -# TODO: specify this more code: type: 'object' + additionalProperties: + type: 'object' + additionalProperties: + type: 'string' + format: 'javascript' teamSpells: type: 'object' @@ -134,6 +138,11 @@ _.extend LevelSessionSchema.properties, submittedCode: type: 'object' + additionalProperties: + type: 'object' + additionalProperties: + type: 'string' + format: 'javascript' isRanking: type: 'boolean' diff --git a/app/schemas/models/user.coffee b/app/schemas/models/user.coffee index d07cc9ccd..b91c4571b 100644 --- a/app/schemas/models/user.coffee +++ b/app/schemas/models/user.coffee @@ -58,7 +58,7 @@ UserSchema = c.object {}, jobProfile: c.object {title: 'Job Profile', required: ['lookingFor', 'jobTitle', 'active', 'name', 'city', 'country', 'skills', 'experience', 'shortDescription', 'longDescription', 'visa', 'work', 'education', 'projects', 'links']}, lookingFor: {title: 'Looking For', type: 'string', enum: ['Full-time', 'Part-time', 'Remote', 'Contracting', 'Internship'], default: 'Full-time', description: 'What kind of developer position do you want?'} jobTitle: {type: 'string', maxLength: 50, title: 'Desired Job Title', description: 'What role are you looking for? Ex.: "Full Stack Engineer", "Front-End Developer", "iOS Developer"', default: 'Software Developer'} - active: {title: 'Active', type: 'boolean', description: 'Want interview offers right now?'} + active: {title: 'Open to Offers', type: 'boolean', description: 'Want interview offers right now?'} updated: c.date {title: 'Last Updated', description: 'How fresh your profile appears to employers. Profiles go inactive after 4 weeks.'} name: c.shortString {title: 'Name', description: 'Name you want employers to see, like "Nick Winter".'} city: c.shortString {title: 'City', description: 'City you want to work in (or live in now), like "San Francisco" or "Lubbock, TX".', default: 'Defaultsville, CA', format: 'city'} @@ -74,13 +74,14 @@ UserSchema = c.object {}, employer: c.shortString {title: 'Employer', description: 'Name of your employer.'} role: c.shortString {title: 'Job Title', description: 'What was your job title or role?'} duration: c.shortString {title: 'Duration', description: 'When did you hold this gig? Ex.: "Feb 2013 - present".'} - description: {type: 'string', title: 'Description', description: 'What did you do there? (140 chars)', maxLength: 140} + description: {type: 'string', title: 'Description', description: 'What did you do there? (140 chars; optional)', maxLength: 140} education: c.array {title: 'Education', description: 'List your academic ordeals.'}, c.object {title: 'Ordeal', description: 'Some education that befell you.', required: ['school', 'degree', 'duration']}, school: c.shortString {title: 'School', description: 'Name of your school.'} degree: c.shortString {title: 'Degree', description: 'What was your degree and field of study? Ex. Ph.D. Human-Computer Interaction (incomplete)'} duration: c.shortString {title: 'Dates', description: 'When? Ex.: "Aug 2004 - May 2008".'} - projects: c.array {title: 'Projects', description: 'Highlight your projects to amaze employers.'}, + description: {type: 'string', title: 'Description', description: 'Highlight anything about this educational experience. (140 chars; optional)', maxLength: 140} + projects: c.array {title: 'Projects (Top 3)', description: 'Highlight your projects to amaze employers.', maxItems: 3}, c.object {title: 'Project', description: 'A project you created.', required: ['name', 'description', 'picture'], default: {name: 'My Project', description: 'A project I worked on.', link: 'http://example.com', picture: ''}}, name: c.shortString {title: 'Project Name', description: 'What was the project called?', default: 'My Project'} description: {type: 'string', title: 'Description', description: 'Briefly describe the project.', maxLength: 400, default: 'A project I worked on.', format: 'markdown'} @@ -94,6 +95,8 @@ UserSchema = c.object {}, jobProfileApproved: {title: 'Job Profile Approved', type: 'boolean', description: 'Whether your profile has been approved by CodeCombat.'} jobProfileNotes: {type: 'string', maxLength: 1000, title: 'Our Notes', description: "CodeCombat's notes on the candidate.", format: 'markdown', default: ''} + employerAt: c.shortString {description: "If given employer permissions to view job candidates, for which employer?"} + c.extendBasicProperties UserSchema, 'user' module.exports = UserSchema diff --git a/app/schemas/schemas.coffee b/app/schemas/schemas.coffee index 2d7ae0603..9c20c9ba2 100644 --- a/app/schemas/schemas.coffee +++ b/app/schemas/schemas.coffee @@ -63,7 +63,7 @@ patchableProps = -> status: { enum: ['pending', 'accepted', 'rejected', 'cancelled']} }) allowPatches: { type: 'boolean' } - listeners: me.array({title:'Listeners'}, + watchers: me.array({title:'Watchers'}, me.objectId(links: [{rel: 'extra', href: "/db/user/{($)}"}])) me.extendPatchableProperties = (schema) -> diff --git a/app/styles/account/profile.sass b/app/styles/account/profile.sass index 57c15b0fc..59807aa1c 100644 --- a/app/styles/account/profile.sass +++ b/app/styles/account/profile.sass @@ -51,10 +51,14 @@ .job-profile-row height: 100% display: table-row + $side-width: 250px + $side-padding: 5px + $middle-width: 524px + $middle-padding: 20px .full-height-column height: 100% - padding: 5px + padding: $side-padding display: table-cell vertical-align: top @@ -62,16 +66,20 @@ margin: 5px 0 5px 0 .left-column - width: 250px - padding: 5px + width: $side-width - 2 * $side-padding + padding: $side-padding background-color: rgb(220, 220, 220) + .sub-column + width: $side-width - 2 * $side-padding + overflow-wrap: break-word + .profile-photo-container position: relative margin-bottom: 10px img.profile-photo - width: 240px + width: $side-width - 2 * $side-padding border-radius: 6px .profile-caption @@ -100,15 +108,24 @@ font-size: 20px .middle-column - width: 524px + width: $middle-width - 2 * $middle-padding + padding-left: $middle-padding + padding-right: $middle-padding background-color: white - padding-left: 20px - padding-right: 20px + + .sub-column + width: $middle-width - 2 * $middle-padding + overflow-wrap: break-word &.double-column - width: 524px + 250px - padding-left: 30px - padding-right: 30px + width: $middle-width + $side-width + 2 * $side-padding - 2 * $middle-padding + $middle-padding-double: 30px + padding-left: $middle-padding-double + padding-right: $middle-padding-double + + .sub-column + width: $middle-width + $side-width + 2 * $side-padding - 2 * $middle-padding - 2 * $middle-padding-double + overflow-wrap: break-word code background-color: rgb(220, 220, 220) @@ -131,27 +148,34 @@ width: 32px height: 32px + .experience-entry + margin-bottom: 15px + .duration margin-left: 10px margin-bottom: 10px - + #job-profile-notes width: 100% height: 100px .right-column - width: 250px + width: $side-width background-color: rgb(220, 220, 220) - > h3:first-child - background-color: white - padding: 5px 5px - margin: 5px 2px 5px 2px + .sub-column + width: $side-width - 2 * $side-padding + overflow-wrap: break-word + + > h3:first-child + background-color: white + padding: 5px 5px + margin: 5px 2px 5px 2px ul.projects li margin-bottom: 10px - padding: 5px 5px + padding: 5px 3px border: 2px solid rgb(220, 220, 220) transition: .5s ease-in-out position: relative diff --git a/app/styles/account/settings.sass b/app/styles/account/settings.sass index b768d69a2..ae607c086 100644 --- a/app/styles/account/settings.sass +++ b/app/styles/account/settings.sass @@ -44,6 +44,26 @@ .form max-width: 600px +#job-profile-view + .profile-preview-button + &.bottom-preview + margin: 15px 0 0 0 + + .sample-profile-thumbnail + margin-top: -60px + + .profile-completion-progress + width: 100% + display: inline-block + height: 33px + + .progress-bar + line-height: 33px + + .progress-next-item + margin-top: -20px + margin-bottom: 15px + #job-profile-treema background-color: white @@ -54,3 +74,16 @@ font-size: 14px line-height: 22px opacity: 1 + + .treema-row + padding-top: 6px + + .treema-image-file + .btn:after + content: "Upload Picture" + margin-left: 20px + + img + display: block + clear: both + max-width: 300px diff --git a/app/styles/base.sass b/app/styles/base.sass index 0425ba2d6..afa9fbcc9 100644 --- a/app/styles/base.sass +++ b/app/styles/base.sass @@ -265,3 +265,8 @@ body[lang='ja'] font-family: 'Glyphicons Halflings' src: url("/fonts/glyphicons-halflings-regular.eot") src: url("/fonts/glyphicons-halflings-regular.eot?#iefix") format("embedded-opentype"), url("/fonts/glyphicons-halflings-regular.woff") format("woff"), url("/fonts/glyphicons-halflings-regular.ttf") format("truetype"), url("/fonts/glyphicons-halflings-regular.svg#glyphicons-halflingsregular") format("svg") + +.spr:after + content: " " +.spl:before + content: " " \ No newline at end of file diff --git a/app/styles/common/top_nav.sass b/app/styles/common/top_nav.sass index f5c61685e..3619a3f9b 100644 --- a/app/styles/common/top_nav.sass +++ b/app/styles/common/top_nav.sass @@ -10,16 +10,19 @@ font-weight: 400 letter-spacing: 1px - .navbuttontext-user-name - max-width: 110px - overflow: hidden - text-overflow: ellipsis - white-space: nowrap + .navbuttontext-account display: inline-block padding: 0 5px 0 0 - margin: 0 + margin: 0 5px 0 0 height: 18px + .account-settings-image + width: 18px + height: 18px + + .glyphicon-user + font-size: 16px + .nav.navbar-link-text, .nav.navbar-link-text > li > a font-weight: normal font-size: 25px diff --git a/app/styles/community.sass b/app/styles/community.sass new file mode 100644 index 000000000..5156d3919 --- /dev/null +++ b/app/styles/community.sass @@ -0,0 +1,7 @@ +#community-view + + .community_columns + width: 330px + float: left + padding-left: 10px + padding-right: 10px \ No newline at end of file diff --git a/app/styles/editor/level/component/edit.sass b/app/styles/editor/level/component/edit.sass index 5c9deda4c..7a78534ed 100644 --- a/app/styles/editor/level/component/edit.sass +++ b/app/styles/editor/level/component/edit.sass @@ -1,4 +1,11 @@ #editor-level-component-edit-view + nav + margin-bottom: 0 + + #component-patches + padding: 0 10px 10px + background: white + .navbar-text float: left @@ -7,9 +14,13 @@ left: 0 right: 0 bottom: 0 - top: 50px + top: 35px border: 2px solid black border-top: none - .active > a, .active > a:hover, .active > a:focus - background-color: white !important \ No newline at end of file + .inner-editor + position: absolute + left: 0 + right: 0 + bottom: 0 + top: 0px \ No newline at end of file diff --git a/app/styles/editor/level/components_tab.sass b/app/styles/editor/level/components_tab.sass index b8a029a5b..c70a5f4d6 100644 --- a/app/styles/editor/level/components_tab.sass +++ b/app/styles/editor/level/components_tab.sass @@ -1,4 +1,6 @@ #editor-level-components-tab-view + h3 + margin-top: 0 .components-container position: absolute @@ -7,7 +9,7 @@ .treema-root position: absolute - top: 50px + top: 35px bottom: 0 width: 250px overflow: scroll @@ -25,13 +27,13 @@ .treema-root position: absolute - top: 50px + top: 35px right: 0 left: 0px bottom: 0 overflow: scroll - #create-new-component-button + #create-new-component-button-no-select position: absolute top: 0 right: 0 diff --git a/app/styles/editor/level/edit.sass b/app/styles/editor/level/edit.sass index f1cfc2303..02ff286c8 100644 --- a/app/styles/editor/level/edit.sass +++ b/app/styles/editor/level/edit.sass @@ -1,10 +1,10 @@ #editor-level-view + &, #level-editor-top-nav + min-width: 1024px + a font-family: helvetica, arial, sans serif - #top-nav - display: none - position: absolute top: 0px left: 0px @@ -12,22 +12,55 @@ bottom: 0px $BG: rgba(228, 207, 140, 1.0) + $NAVBG: #2f261d li.navbar-btn margin-right: 5px - #level-editor-top-nav - .nav-tabs - border-bottom: 0 !important - .active > a, .active > a:hover, .active > a:focus - background-color: $BG !important - border-color: darken($BG, 50%) - border-bottom: 0 + // custom navbar height rules + .navbar-nav > li > a + padding: 7px 8px 8px + cursor: pointer + &:hover + background-color: lighten($NAVBG, 10%) + .navbar + min-height: 0px + border-radius: 0 + .navbar-right + // not sure why bootstrap puts a big negative margin in, but this overrides it + margin-right: 10px + + // custom navbar styling + .navbar-brand + padding-top: 7px + padding-bottom: 7px + color: lighten(gold, 30%) + .navbar-header + border-left: 2px solid lighten($NAVBG, 20%) + border-right: 2px solid lighten($NAVBG, 20%) + background: lighten($NAVBG, 10%) + margin-left: 20px + .nav-tabs + margin-left: 5px + border-bottom: 0 !important + .active > a, .active > a:hover, .active > a:focus + background-color: $BG !important + border-color: darken($BG, 50%) + border-bottom: 0 + a + padding: 7px 5px !important + .dropdown-menu a + cursor: pointer + &:hover + background-color: #d3d3d3 + + .badge + background-color: green .outer-content background-color: $BG position: absolute - top: 0 + top: 35px bottom: 0 left: 0 right: 0 @@ -45,12 +78,11 @@ #level-editor-tabs position: absolute - left: 20px - right: 20px - top: 66px - bottom: 20px + left: 15px + right: 15px + top: 15px + bottom: 15px .treema-root background-color: white border-radius: 4px - diff --git a/app/styles/editor/level/system/edit.sass b/app/styles/editor/level/system/edit.sass index e86dc5a46..567ff5b27 100644 --- a/app/styles/editor/level/system/edit.sass +++ b/app/styles/editor/level/system/edit.sass @@ -7,9 +7,13 @@ left: 0 right: 0 bottom: 0 - top: 50px + top: 35px border: 2px solid black border-top: none - - .active > a, .active > a:hover, .active > a:focus - background-color: white !important \ No newline at end of file + + .inner-editor + position: absolute + left: 0 + right: 0 + bottom: 0 + top: 0px \ No newline at end of file diff --git a/app/styles/editor/level/systems_tab.sass b/app/styles/editor/level/systems_tab.sass index 88585504d..0d1aa6b33 100644 --- a/app/styles/editor/level/systems_tab.sass +++ b/app/styles/editor/level/systems_tab.sass @@ -1,4 +1,6 @@ #editor-level-systems-tab-view + h3 + margin-top: 0 .systems-container position: absolute @@ -7,7 +9,7 @@ .treema-root position: absolute - top: 50px + top: 35px bottom: 0 width: 250px overflow: scroll @@ -30,7 +32,7 @@ .treema-root position: absolute - top: 50px + top: 35px right: 0 left: 0px bottom: 0 diff --git a/app/styles/editor/patches.sass b/app/styles/editor/patches.sass index 87c22728e..110370137 100644 --- a/app/styles/editor/patches.sass +++ b/app/styles/editor/patches.sass @@ -1,3 +1,3 @@ .patches-view .status-buttons - margin: 10px 0 + margin-bottom: 10px diff --git a/app/styles/modal/model.sass b/app/styles/modal/model.sass new file mode 100644 index 000000000..8ecf502dd --- /dev/null +++ b/app/styles/modal/model.sass @@ -0,0 +1,9 @@ +#model-modal + .treema-root + background-color: white + + .modal-dialog + width: 1000px + + .treema-ace .ace_editor + height: 600px diff --git a/app/styles/play/ladder/ladder_tab.sass b/app/styles/play/ladder/ladder_tab.sass index 6d65cc5a6..f722faf18 100644 --- a/app/styles/play/ladder/ladder_tab.sass +++ b/app/styles/play/ladder/ladder_tab.sass @@ -4,6 +4,9 @@ white-space: nowrap overflow: hidden text-overflow: ellipsis + + .histogram-display + height: 130px .bar rect fill: steelblue @@ -39,4 +42,8 @@ .ogres-rank-text fill: #3f44bf - \ No newline at end of file + + .load-more-ladder-entries + position: absolute + right: 15px + bottom: -5px diff --git a/app/templates/account/job_profile.jade b/app/templates/account/job_profile.jade index 491ea8b9c..6ec836343 100644 --- a/app/templates/account/job_profile.jade +++ b/app/templates/account/job_profile.jade @@ -1,8 +1,28 @@ h3(data-i18n="account_settings.job_profile") Job Profile -if me.get('jobProfileApproved') - p.lead(data-i18n="account_settings.job_profile_approved") Your job profile has been approved by CodeCombat. Employers will be able to see it until you either mark it inactive or it has not been changed for four weeks. -else - p.lead(data-i18n="account_settings.job_profile_explanation") Hi! Fill this out, and we will get in touch about finding you a software developer job. +.row + .col-md-9 + if me.get('jobProfileApproved') + p.lead(data-i18n="account_settings.job_profile_approved") Your job profile has been approved by CodeCombat. Employers will be able to see it until you either mark it inactive or it has not been changed for four weeks. + else + p.lead(data-i18n="account_settings.job_profile_explanation") Hi! Fill this out, and we will get in touch about finding you a software developer job. -#job-profile-treema \ No newline at end of file + .row + .col-md-9 + .progress.profile-completion-progress + .progress-bar.progress-bar-success + .progress-next-item + + .col-md-3 + a.btn.btn-large.btn-primary.profile-preview-button.top-preview(href="/account/profile/#{me.id}", target="job_profile", data-i18n="account_settings.view_profile") View Your Profile + + .col-md-3 + .thumbnail.sample-profile-thumbnail + a(href="http://codecombat.com/images/pages/account/profile/sample_profile.png", target="_blank") + img(src="/images/pages/account/profile/sample_profile_thumb.png" alt="Sample Profile Thumbnail") + .caption + span(data-i18n="account_settings.sample_profile") See a sample profile + +#job-profile-treema + +a.btn.btn-large.btn-primary.profile-preview-button.bottom-preview(href="/account/profile/#{me.id}", target="job_profile", data-i18n="account_settings.view_profile") View Your Profile diff --git a/app/templates/account/profile.jade b/app/templates/account/profile.jade index e070c49ac..fbd3e15f5 100644 --- a/app/templates/account/profile.jade +++ b/app/templates/account/profile.jade @@ -5,7 +5,7 @@ block content if myProfile || (me.isAdmin() && user.get('jobProfile')) .profile-control-bar if myProfile - a(href="/account/settings") + a(href=user.get('jobProfile') ? "/account/settings#job-profile" : "/account/settings") button.btn.edit-settings-button i.icon-cog span(data-i18n="account_profile.edit_settings") Edit Settings @@ -20,80 +20,94 @@ block content .job-profile-container .job-profile-row .left-column.full-height-column - .profile-photo-container - img.profile-photo(src=user.getPhotoURL(240, true)) - .profile-caption= profile.jobTitle || 'Software Developer' - - if profileLinks.length - ul.links - each link in profileLinks - li(title=profile.name + " on " + link.name, class=link.icon ? "has-icon" : "") - a(href=link.link) - if link.icon - img(src=link.icon.url, alt=link.icon.name) - else - button.btn.btn-large.btn-inverse.flat-button= link.name - - div= profile.city + ', ' + profile.country - div= profile.visa - div - span(data-i18n="account_profile.looking_for") Looking for: - | #{profile.lookingFor} - div - span(data-i18n="account_profile.last_updated") Last updated: - | #{moment(profile.updated).fromNow()} - - button#contact-candidate.btn.btn-large.btn-inverse.flat-button - span(data-i18n="account_profile.contact") Contact - | #{profile.name.split(' ')[0]} + .sub-column + .profile-photo-container + img.profile-photo(src=user.getPhotoURL(240, true)) + .profile-caption= profile.jobTitle || 'Software Developer' + + if profileLinks.length + ul.links + each link in profileLinks + if link.link && link.name + li(title=profile.name + " on " + link.name, class=link.icon ? "has-icon" : "") + a(href=link.link) + if link.icon + img(src=link.icon.url, alt=link.icon.name) + else + button.btn.btn-large.btn-inverse.flat-button= link.name + + div= profile.city + ', ' + profile.country + div= profile.visa + div + span(data-i18n="account_profile.looking_for") Looking for: + | #{profile.lookingFor} + div + span(data-i18n="account_profile.last_updated") Last updated: + | #{moment(profile.updated).fromNow()} + + button#contact-candidate.btn.btn-large.btn-inverse.flat-button + span(data-i18n="account_profile.contact") Contact + | #{profile.name.split(' ')[0]} .middle-column.full-height-column - h3= profile.name - p= profile.shortDescription - - each skill in profile.skills - code= skill - span - div.long-description!= marked(profile.longDescription) - - if profile.work.length - h3.experience-header - img.header-icon(src="/images/pages/account/profile/work.png", alt="") - span(data-i18n="account_profile.work_experience") Work Experience - each job in profile.work - div.duration.pull-right= job.duration - | #{job.role} at #{job.employer} - .clearfix - if job.description - div!= marked(job.description) - - if profile.education.length - h3.experience-header - img.header-icon(src="/images/pages/account/profile/education.png", alt="") - span(data-i18n="account_profile.education") Education - each school in profile.education - div.duration.pull-right= school.duration - | #{school.degree} at #{school.school} - .clearfix - - if user.get('jobProfileNotes') || me.isAdmin() - h3.experience-header(data-i18n="account_profile.our_notes") Our Notes - - var notes = user.get('jobProfileNotes') || ''; - if me.isAdmin() - textarea#job-profile-notes!= notes - else - div!= marked(notes) + .sub-column + h3= profile.name || "Anonymous Developer" + if profile.shortDescription + p= profile.shortDescription + + each skill in profile.skills + code= skill + span + if profile.longDescription + div.long-description!= marked(profile.longDescription) + + if profile.work.length + h3.experience-header + img.header-icon(src="/images/pages/account/profile/work.png", alt="") + span(data-i18n="account_profile.work_experience") Work Experience + each job in profile.work + if job.role && job.employer + div.experience-entry + div.duration.pull-right= job.duration + | #{job.role} at #{job.employer} + .clearfix + if job.description + div!= marked(job.description) + + if profile.education.length + h3.experience-header + img.header-icon(src="/images/pages/account/profile/education.png", alt="") + span(data-i18n="account_profile.education") Education + each school in profile.education + if school.degree && school.school + div.experience-entry + div.duration.pull-right= school.duration + | #{school.degree} at #{school.school} + .clearfix + if school.description + div!= marked(school.description) + + if user.get('jobProfileNotes') || me.isAdmin() + h3.experience-header(data-i18n="account_profile.our_notes") Our Notes + - var notes = user.get('jobProfileNotes') || ''; + if me.isAdmin() + textarea#job-profile-notes!= notes + else + div!= marked(notes) .right-column.full-height-column - if profile.projects.length - h3(data-i18n="account_profile.projects") Projects - ul.projects - each project in profile.projects - li - a(href=project.link) - .project-image(style="background-image: url(/file/" + project.picture + ")") - p= project.name - div!= marked(project.description) + .sub-column + if profile.projects.length + h3(data-i18n="account_profile.projects") Projects + ul.projects + each project in profile.projects + if project.name + li + a(href=project.link) + if project.picture + .project-image(style="background-image: url(/file/" + project.picture + ")") + p= project.name + div!= marked(project.description) else .public-profile-container diff --git a/app/templates/account/settings.jade b/app/templates/account/settings.jade index a1e829b7e..96179d5ba 100644 --- a/app/templates/account/settings.jade +++ b/app/templates/account/settings.jade @@ -39,7 +39,7 @@ block content if !isProduction .form-group.checkbox label(for="email", data-i18n="account_settings.admin") Admin - input#admin(name="admin", type="checkbox", checked=me.get('permissions').indexOf('admin')>-1)) + input#admin(name="admin", type="checkbox", checked=me.get('permissions').indexOf('admin') != -1) #picture-pane.tab-pane diff --git a/app/templates/base.jade b/app/templates/base.jade index 96d184876..ebc6b5a97 100644 --- a/app/templates/base.jade +++ b/app/templates/base.jade @@ -16,12 +16,8 @@ body ul.nav.navbar-nav li.play a.header-font(href='/play', data-i18n="nav.play") Levels - li.editor - a.header-font(href='/editor', data-i18n="nav.editor") Editor - li.blog - a.header-font(href='http://blog.codecombat.com/', data-i18n="nav.blog") Blog - li.forum - a.header-font(href='http://discourse.codecombat.com/', data-i18n="nav.forum") Forum + li + a.header-font(href='/community', data-i18n="nav.community") Community .nav.navbar.navbar-fixed-top#top-nav .content.clearfix @@ -34,9 +30,11 @@ body if me.get('anonymous') === false button.btn.btn-primary.navbuttontext.header-font#logout-button(data-i18n="login.log_out") Log Out a.btn.btn-primary.navbuttontext.header-font(href=me.get('jobProfile') ? "/account/profile/#{me.id}" : "/account/settings") - div.navbuttontext-user-name - | #{me.displayName()} - i.icon-cog.icon-white.big + div.navbuttontext-account(data-i18n="nav.account") Account + if me.get('photoURL') + img.account-settings-image(src=me.getPhotoURL(18), alt="") + else + span.glyphicon.glyphicon-user else button.btn.btn-primary.navbuttontext.header-font(data-toggle="coco-modal", data-target="modal/signup", data-i18n="login.sign_up") Create Account @@ -45,13 +43,8 @@ body ul(class='navbar-link-text').nav.navbar-nav.pull-right li.play a.header-font(href='/play', data-i18n="nav.play") Levels - li.editor - a.header-font(href='/editor', data-i18n="nav.editor") Editor - li.blog - a.header-font(href='http://blog.codecombat.com/', data-i18n="nav.blog") Blog - li.forum - a.header-font(href='http://discourse.codecombat.com/', data-i18n="nav.forum") Forum - + li + a.header-font(href='/community', data-i18n="nav.community") Community block outer_content #outer-content-wrapper @@ -65,7 +58,7 @@ body .footer.clearfix .content p.footer-link-text - if pathname == "/" + if pathname == "/" || (me.get('permissions') || []).indexOf('employer') != -1 a(href='/employers', title='Home', tabindex=-1, data-i18n="nav.employers") Employers else a(href='/', title='Home', tabindex=-1, data-i18n="nav.home") Home @@ -73,6 +66,9 @@ body a(href='/legal', title='Legal', tabindex=-1, data-i18n="nav.legal") Legal a(href='/about', title='About', tabindex=-1, data-i18n="nav.about") About a(title='Contact', tabindex=-1, data-toggle="coco-modal", data-target="modal/contact", data-i18n="nav.contact") Contact + a(href='/editor', data-i18n="nav.editor") Editor + a(href='http://blog.codecombat.com/', data-i18n="nav.blog") Blog + a(href='http://discourse.codecombat.com/', data-i18n="nav.forum") Forum if me.isAdmin() a(href='/admin', data-i18n="nav.admin") Admin diff --git a/app/templates/community.jade b/app/templates/community.jade new file mode 100644 index 000000000..85cad6d21 --- /dev/null +++ b/app/templates/community.jade @@ -0,0 +1,88 @@ +extends /templates/base + +block content + + h1(data-i18n="community.main_title") CodeCombat Community + + p There are dozens of ways you can get involved with CodeCombat. Check out the resources we've built, decide what sounds the most fun, and we look forward to working with you! + + div + + .community_columns + + h2 Levels and Art + + p We have built several tools that enable users to get not only edit, but also build new game content! + + ul + li + a(href="/editor", data-i18n="community.level_editor") + | : fork, edit, or build your own CodeCombat levels. New levels can be kept private or published to the community. + li + a(href="/editor", data-i18n="editor.thang_title") + | : modify or import new art assets for the game using our powerful editor. + li + a(href="/editor", data-i18n="editor.article_title") + | : edit or create documentation used in CodeCombat levels. + + p Right now most of our editing tools are very rough, but we are improving them constantly and welcome your feedback. + + .community_columns + + h2 Connect + + p There are a bunch of ways you can connect with us and get involved in the ongoing development of CodeCombat: + + ul + + li We write about our progress and current projects on our + a(href="http://blog.codecombat.com", data-i18n="nav.blog") + | . + li Participate in our active user community by checking out our + a(href="http://discourse.codecombat.com", data-i18n="nav.forum") + | . + li For regular news about learning to code, games, and education, check out our + a(href="https://www.facebook.com/codecombat", data-i18n="community.facebook") + | . + li For realtime status or to have a quick chat, follow us on + a(href="https://twitter.com/CodeCombat", data-i18n="community.twitter") + | . + li Don't like Facebook? We're on + a(href="https://plus.google.com/115285980638641924488/posts", data-i18n="community.gplus") + | . + li You can also find us in our + a(href="http://www.hipchat.com/g3plnOKqa", data-i18n="editor.hipchat_url") + + .community_columns + + h2 Contribute + + p Put your skills to use helping us teach the world to code. We have a lot of roles you can consider, and if we don't have a role for you, let us know: + + ul + + li + a(href="/contribute#archmage", data-i18n="classes.archmage_title") + | : contribute by writing code. + li + a(href="/contribute#artisan", data-i18n="classes.artisan_title") + | : build new game levels. + li + a(href="/contribute#adventurer", data-i18n="classes.adventurer_title") + | : test new game levels. + li + a(href="/contribute#scribe", data-i18n="classes.scribe_title") + | : write educational documentation. + li + a(href="/contribute#diplomat", data-i18n="classes.diplomat_title") + | : translate site content. + li + a(href="/contribute#ambassador", data-i18n="classes.ambassador_title") + | : support our community of educators and coders. + li + a(href="/contribute#counselor", data-i18n="classes.counselor_title") + | : offer your advice and business acumen to the founders. + + | Check out the + a(href="/contribute", data-i18n="nav.contribute") + | page to find out more about the roles and how you can get started. \ No newline at end of file diff --git a/app/templates/editor.jade b/app/templates/editor.jade index c92140c29..82101e03f 100644 --- a/app/templates/editor.jade +++ b/app/templates/editor.jade @@ -34,11 +34,9 @@ block content hr p - span(data-i18n="editor.security_notice") - | Many major features in these editors are not currently enabled by default. - | As we improve the security of these systems, they will be made generally available. - | If you'd like to use these features sooner, - a(title='Contact', tabindex=-1, data-toggle="coco-modal", data-target="modal/contact", data-i18n="editor.contact_us") email us! + span(data-i18n="editor.got_questions") Questions about using the CodeCombat editors? + | + a(title='Contact', tabindex=-1, data-toggle="coco-modal", data-target="modal/contact", data-i18n="editor.contact_us") Contact us! | span(data-i18n="editor.hipchat_prefix") You can also find us in our | diff --git a/app/templates/editor/level/component/edit.jade b/app/templates/editor/level/component/edit.jade index 23c24cf6c..7228ff914 100644 --- a/app/templates/editor/level/component/edit.jade +++ b/app/templates/editor/level/component/edit.jade @@ -1,23 +1,44 @@ nav.navbar.navbar-default(role='navigation') - .container-fluid - .navbar-header - span.navbar-brand - span(data-i18n="editor.level_component_edit_title") - | Edit Component - span : - | "#{editTitle}" - .collapse.navbar-collapse - ul.nav.navbar-nav.nav-tabs - li.active - a(href="#component-code" data-toggle="tab" data-i18n="general.code") Code + ul.nav.navbar-nav.nav-tabs + li.active + a(href="#component-code" data-toggle="tab" data-i18n="general.code")#component-code-tab Code + li + a(href="#component-config-schema" data-toggle="tab" data-i18n="editor.level_component_config_schema")#component-config-schema-tab Config Schema + li + a(href="#component-settings" data-toggle="tab" data-i18n="editor.level_component_settings")#component-settings-tab Settings + li + a(href="#component-patches" data-toggle="tab" data-i18n="resources.patches")#component-patches-tab Patches + + .navbar-header + span.navbar-brand= editTitle + + ul.nav.navbar-nav.navbar-right + li.dropdown + a(data-toggle='dropdown') + span.glyphicon-chevron-down.glyphicon + + ul.dropdown-menu + li.dropdown-header Actions li - a(href="#component-config-schema" data-toggle="tab" data-i18n="editor.level_component_config_schema") Config Schema - li - a(href="#component-settings" data-toggle="tab" data-i18n="editor.level_component_settings") Settings - ul.nav.navbar-nav.navbar-left - li(data-i18n="general.version_history").btn.btn-primary.navbar-btn#history-button Version History - ul.nav.navbar-nav.navbar-right - li(data-i18n="editor.level_component_btn_new").btn.btn-primary.navbar-btn#create-new-component-button Create New Component + a#component-watch-button + span.watch + span.glyphicon.glyphicon-eye-open + span.spl Watch + span.unwatch.secret + span.glyphicon.glyphicon-eye-close + span.spl Unwatch + + li#patch-component-button + a(data-i18n="common.submit_patch") Submit Patch + + li#create-new-component-button + a(data-i18n="editor.level_component_btn_new") Create New Component + + li.divider + li.dropdown-header Info + + li#component-history-button + a(data-i18n="general.version_history") Version History .tab-content .tab-pane.active#component-code @@ -26,3 +47,5 @@ nav.navbar.navbar-default(role='navigation') #config-schema-treema .tab-pane#component-settings #edit-component-treema + .tab-pane#component-patches + .patches-view \ No newline at end of file diff --git a/app/templates/editor/level/components_tab.jade b/app/templates/editor/level/components_tab.jade index e97f47aa4..9cd86545e 100644 --- a/app/templates/editor/level/components_tab.jade +++ b/app/templates/editor/level/components_tab.jade @@ -4,6 +4,6 @@ .edit-component-container if me.isAdmin() - button(data-i18n="editor.level_component_btn_new").btn.btn-primary#create-new-component-button Create New Component + button(data-i18n="editor.level_component_btn_new").btn.btn-primary#create-new-component-button-no-select Create New Component #editor-level-component-edit-view diff --git a/app/templates/editor/level/edit.jade b/app/templates/editor/level/edit.jade index ba69b27fd..6b010912d 100644 --- a/app/templates/editor/level/edit.jade +++ b/app/templates/editor/level/edit.jade @@ -1,74 +1,90 @@ extends /templates/base -block outer_content - .outer-content - +block header + if level.loading nav.navbar.navbar-default(role='navigation')#level-editor-top-nav .container-fluid ul.nav.navbar-nav li - a(href="/editor/level", data-i18n="editor.back") Back - .navbar-header - span.navbar-brand - span(data-i18n="editor.level_title") Level Editor - span : - span.level-title #{level.attributes.name} - .collapse.navbar-collapse - ul.nav.navbar-nav.nav-tabs - - li.active - a(href="#editor-level-thangs-tab-view", data-toggle="tab", data-i18n="editor.level_tab_thangs") Thangs - li - a(href="#editor-level-scripts-tab-view", data-toggle="tab", data-i18n="editor.level_tab_scripts") Scripts - li - a(href="#editor-level-settings-tab-view", data-toggle="tab", data-i18n="editor.level_tab_settings") Settings - li - a(href="#editor-level-components-tab-view", data-toggle="tab", data-i18n="editor.level_tab_components") Components - li - a(href="#editor-level-systems-tab-view", data-toggle="tab", data-i18n="editor.level_tab_systems") Systems - li - a(href="#editor-level-patches", data-toggle="tab", data-i18n="resources.patches")#patches-tab Patches - - - ul.nav.navbar-nav.navbar-right - li(data-toggle="coco-modal", data-target="modal/revert", data-i18n="editor.revert", disabled=authorized === true ? undefined : "true").btn.btn-primary.navbar-btn#revert-button Revert - if authorized - li(data-i18n="common.save").btn.btn-primary.navbar-btn#commit-level-start-button Save - else - li(data-i18n="common.patch").btn.btn-primary.navbar-btn#commit-level-patch-button Patch - li(data-i18n="common.fork", disabled=anonymous ? "true": undefined).btn.btn-primary.navbar-btn#fork-level-start-button Fork - li(title="⌃↩ or ⌘↩: Play preview of current level", data-i18n="common.play")#play-button.btn.btn-inverse.banner.navbar-btn Play! - - li.divider - - li.dropdown - a.dropdown-toggle(href='#', data-toggle='dropdown', data-i18n="editor.more") - | More - b.caret - ul.dropdown-menu - li#history-button - a(href='#', data-i18n="general.version_history") Version History - li - a(href='https://github.com/codecombat/codecombat/wiki/Artisan-Home', data-i18n="editor.wiki") Wiki - li - a(href='http://www.hipchat.com/g3plnOKqa', data-i18n="editor.live_chat") Live Chat - li - a(href='http://discourse.codecombat.com/category/artisan', data-i18n="nav.forum") Forum - li - a(data-toggle="coco-modal", data-target="modal/contact", data-i18n="nav.contact") Email - - - - ul.dropdown-menu - li - span(data-i18n="editor.level_some_options").dropdown-menu-header Some Options? - li.divider - li - a(data-delay="1000", href="#", data-i18n="common.delay_1_sec") 1 second - a(data-delay="3000", href="#", data-i18n="common.delay_3_sec") 3 seconds - a(data-delay="5000", href="#", data-i18n="common.delay_5_sec") 5 seconds - a(data-delay="90019001", href="#", data-i18n="common.manual") Manual + a(href="/editor/level") + span.glyphicon-home.glyphicon + else + nav.navbar.navbar-default(role='navigation')#level-editor-top-nav + ul.nav.navbar-nav + li + a(href="/editor/level") + span.glyphicon-home.glyphicon + ul.nav.navbar-nav.nav-tabs + + li.active + a(href="#editor-level-thangs-tab-view", data-toggle="tab", data-i18n="editor.level_tab_thangs") Thangs + li + a(href="#editor-level-scripts-tab-view", data-toggle="tab", data-i18n="editor.level_tab_scripts") Scripts + li + a(href="#editor-level-settings-tab-view", data-toggle="tab", data-i18n="editor.level_tab_settings") Settings + li + a(href="#editor-level-components-tab-view", data-toggle="tab", data-i18n="editor.level_tab_components") Components + li + a(href="#editor-level-systems-tab-view", data-toggle="tab", data-i18n="editor.level_tab_systems") Systems + li + a(href="#editor-level-patches", data-toggle="tab")#patches-tab + span(data-i18n="resources.patches").spr Patches + - var patches = level.get('patches') + if patches && patches.length + span.badge= patches.length + + .navbar-header + span.navbar-brand #{level.attributes.name} + + ul.nav.navbar-nav.navbar-right + if authorized + li#commit-level-start-button + a + span.glyphicon-floppy-disk.glyphicon + else + li#level-patch-button + a + span.glyphicon-floppy-disk.glyphicon + + li(title="⌃↩ or ⌘↩: Play preview of current level")#play-button + a + span.glyphicon-play.glyphicon + li.dropdown + a(data-toggle='dropdown') + span.glyphicon-chevron-down.glyphicon + ul.dropdown-menu + li.dropdown-header Actions + li + a#level-watch-button + span.watch + span.glyphicon.glyphicon-eye-open + span.spl Watch + span.unwatch.secret + span.glyphicon.glyphicon-eye-close + span.spl Unwatch + + li(class=anonymous ? "disabled": "") + a(data-i18n="common.fork")#fork-level-start-button Fork + li(class=anonymous ? "disabled": "") + a(data-toggle="coco-modal", data-target="modal/revert", data-i18n="editor.revert")#revert-button Revert + li.divider + li.dropdown-header Info + li#level-history-button + a(href='#', data-i18n="general.version_history") Version History + li.divider + li.dropdown-header Help + li + a(href='https://github.com/codecombat/codecombat/wiki/Artisan-Home', data-i18n="editor.wiki", target="_blank") Wiki + li + a(href='http://www.hipchat.com/g3plnOKqa', data-i18n="editor.live_chat", target="_blank") Live Chat + li + a(href='http://discourse.codecombat.com/category/artisan', data-i18n="nav.forum", target="_blank") Forum + li + a(data-toggle="coco-modal", data-target="modal/contact", data-i18n="nav.contact") Email + +block outer_content + .outer-content div.tab-content#level-editor-tabs div.tab-pane.active#editor-level-thangs-tab-view diff --git a/app/templates/editor/level/system/edit.jade b/app/templates/editor/level/system/edit.jade index db20287b6..267993ea5 100644 --- a/app/templates/editor/level/system/edit.jade +++ b/app/templates/editor/level/system/edit.jade @@ -1,21 +1,40 @@ nav.navbar.navbar-default(role='navigation') - .container-fluid - .navbar-header - span.navbar-brand - span(data-i18n="editor.level_system_edit_title") - | Edit System - span : - | "#{editTitle}" - .collapse.navbar-collapse - ul.nav.navbar-nav.nav-tabs - li.active - a(href="#system-code" data-toggle="tab") Code + + ul.nav.navbar-nav.nav-tabs + li.active + a(href="#system-code" data-toggle="tab")#system-code-tab Code + li + a(href="#system-config-schema" data-toggle="tab")#system-config-schema-tab Config Schema + li + a(href="#system-settings" data-toggle="tab")#system-settings-tab Settings + li + a(href="#system-patches" data-toggle="tab" data-i18n="resources.patches")#system-patches-tab Patches + + ul.nav.navbar-nav.navbar-right + li.dropdown + a(data-toggle='dropdown') + span.glyphicon-chevron-down.glyphicon + ul.dropdown-menu + li.dropdown-header Actions li - a(href="#system-config-schema" data-toggle="tab") Config Schema - li - a(href="#system-settings" data-toggle="tab") Settings - ul.nav.navbar-nav.navbar-right - li(data-i18n="editor.level_system_btn_new").btn.btn-primary.navbar-btn#create-new-system-button Create New System + a#system-watch-button + span.watch + span.glyphicon.glyphicon-eye-open + span.spl Watch + span.unwatch.secret + span.glyphicon.glyphicon-eye-close + span.spl Unwatch + li#patch-system-button + a(data-i18n="common.submit_patch") Submit Patch + li#create-new-system + a(data-i18n="editor.level_system_btn_new") Create New System + li.divider + li.dropdown-header Info + li#system-history-button + a(data-i18n="general.version_history") Version History + + .navbar-header + span.navbar-brand= editTitle .tab-content .tab-pane.active#system-code @@ -24,3 +43,5 @@ nav.navbar.navbar-default(role='navigation') #config-schema-treema .tab-pane#system-settings #edit-system-treema + .tab-pane#system-patches + .patches-view \ No newline at end of file diff --git a/app/templates/editor/patch_modal.jade b/app/templates/editor/patch_modal.jade index 68fed43f7..4d46d8cb5 100644 --- a/app/templates/editor/patch_modal.jade +++ b/app/templates/editor/patch_modal.jade @@ -6,6 +6,7 @@ block modal-header-content block modal-body-content .modal-body + p= patch.get('commitMessage') .changes-stub diff --git a/app/templates/modal/model.jade b/app/templates/modal/model.jade new file mode 100644 index 000000000..4fae4c294 --- /dev/null +++ b/app/templates/modal/model.jade @@ -0,0 +1,9 @@ +extends /templates/modal/modal_base + +block modal-header + +block modal-body-content + for model in models + h3= model.type() + ': ' + model.id + .model-treema(data-model-id=model.id) + hr diff --git a/app/templates/modal/versions.jade b/app/templates/modal/versions.jade index bd5b099eb..af78e7fcd 100755 --- a/app/templates/modal/versions.jade +++ b/app/templates/modal/versions.jade @@ -8,7 +8,7 @@ block modal-header-content block modal-body-content if dataList - table.table + table.table.table-condensed tr th(data-i18n="general.name") Name th(data-i18n="general.version") Version diff --git a/app/templates/play/ladder.jade b/app/templates/play/ladder.jade index 2a749292f..bc8bd05d0 100644 --- a/app/templates/play/ladder.jade +++ b/app/templates/play/ladder.jade @@ -38,52 +38,4 @@ block content .tab-pane.well#my-matches #my-matches-tab-view .tab-pane.well#simulate - p(id="simulation-status-text") - if simulationStatus - | #{simulationStatus} - else - span(data-i18n="ladder.simulation_explanation") By simulating games you can get your game ranked faster! - p - button(data-i18n="ladder.simulate_games").btn.btn-warning.btn-lg.highlight#simulate-button Simulate Games! - if false && me.isAdmin() - p - button(data-i18n="ladder.simulate_all").btn.btn-danger.btn-lg.highlight#simulate-all-button RESET AND SIMULATE GAMES - - p.simulation-count - span(data-i18n="ladder.games_simulated_by") Games simulated by you: - | - span#simulated-by-you= me.get('simulatedBy') || 0 - - p.simulation-count - span(data-i18n="ladder.games_simulated_for") Games simulated for you: - | - span#simulated-for-you= me.get('simulatedFor') || 0 - - table.table.table-bordered.table-condensed.table-hover - tr - th(data-i18n="general.player").name-col-cell Player - th(data-i18n="ladder.games_simulated") Games simulated - th(data-i18n="ladder.games_played") Games played - th(data-i18n="ladder.ratio") Ratio - - var topSimulators = simulatorsLeaderboardData.topSimulators.models; - - var showJustTop = simulatorsLeaderboardData.inTopSimulators() || me.get('anonymous'); - - if(!showJustTop) topSimulators = topSimulators.slice(0, 10); - for user in topSimulators - - var myRow = user.id == me.id - tr(class=myRow ? "success" : "") - td.name-col-cell= user.get('name') || "Anonymous" - td.simulator-leaderboard-cell= user.get('simulatedBy') - td.simulator-leaderboard-cell= user.get('simulatedFor') - td.simulator-leaderboard-cell= Math.round((user.get('simulatedBy') / user.get('simulatedFor')) * 10) / 10 - - if !showJustTop && simulatorsLeaderboardData.nearbySimulators().length - tr(class="active") - td(colspan=4).ellipsis-row ... - for user in simulatorsLeaderboardData.nearbySimulators() - - var myRow = user.id == me.id - - var ratio = user.get('simulatedBy') / user.get('simulatedFor'); - tr(class=myRow ? "success" : "") - td.name-col-cell= user.get('name') || "Anonymous" - td.simulator-leaderboard-cell= user.get('simulatedBy') - td.simulator-leaderboard-cell= user.get('simulatedFor') - td.simulator-leaderboard-cell= _.isNaN(ratio) || ratio == Infinity ? '' : ratio.toFixed(1) \ No newline at end of file + #simulate-tab-view diff --git a/app/templates/play/ladder/ladder_tab.jade b/app/templates/play/ladder/ladder_tab.jade index 1b7d7351e..16bba4f8c 100644 --- a/app/templates/play/ladder/ladder_tab.jade +++ b/app/templates/play/ladder/ladder_tab.jade @@ -1,5 +1,5 @@ div#columns.row - for team in teams + for team, teamIndex in teams div.column.col-md-4 div(id="histogram-display-#{team.name}", class="histogram-display",data-team-name=team.name) table.table.table-bordered.table-condensed.table-hover @@ -17,10 +17,10 @@ div#columns.row - var topSessions = team.leaderboard.topPlayers.models; - var showJustTop = team.leaderboard.inTopSessions() || me.get('anonymous'); - - if(!showJustTop) topSessions = topSessions.slice(0, 10); + - if(!showJustTop && topSessions.length == 20) topSessions = topSessions.slice(0, 10); for session, rank in topSessions - var myRow = session.get('creator') == me.id - tr(class=myRow ? "success" : "") + tr(class=myRow ? "success" : "", data-player-id=session.get('creator'), data-session-id=session.id) td.rank-cell= rank + 1 td.score-cell= Math.round(session.get('totalScore') * 100) td.name-col-cell= session.get('creatorName') || "Anonymous" @@ -33,14 +33,16 @@ div#columns.row td(colspan=4).ellipsis-row ... for session in team.leaderboard.nearbySessions() - var myRow = session.get('creator') == me.id - tr(class=myRow ? "success" : "") + tr(class=myRow ? "success" : "", data-player-id=session.get('creator'), data-session-id=session.id) td.rank-cell= session.rank td.score-cell= Math.round(session.get('totalScore') * 100) td.name-col-cell= session.get('creatorName') || "Anonymous" td.fight-cell a(href="/play/level/#{level.get('slug') || level.id}/?team=#{team.otherTeam}&opponent=#{session.id}") span(data-i18n="ladder.fight") Fight! - + if teamIndex == 1 + .btn.btn-sm.load-more-ladder-entries moar + div.column.col-md-4 h4.friends-header Friends Playing if me.get('anonymous') diff --git a/app/templates/play/ladder/simulate_tab.jade b/app/templates/play/ladder/simulate_tab.jade new file mode 100644 index 000000000..e590c8c4c --- /dev/null +++ b/app/templates/play/ladder/simulate_tab.jade @@ -0,0 +1,49 @@ +p(id="simulation-status-text") + if simulationStatus + | #{simulationStatus} + else + span(data-i18n="ladder.simulation_explanation") By simulating games you can get your game ranked faster! +p + button(data-i18n="ladder.simulate_games").btn.btn-warning.btn-lg.highlight#simulate-button Simulate Games! + +p.simulation-count + span(data-i18n="ladder.games_simulated_by") Games simulated by you: + | + span#simulated-by-you= me.get('simulatedBy') || 0 + +p.simulation-count + span(data-i18n="ladder.games_simulated_for") Games simulated for you: + | + span#simulated-for-you= me.get('simulatedFor') || 0 + +table.table.table-bordered.table-condensed.table-hover + tr + th + th(data-i18n="general.player").name-col-cell Player + th(data-i18n="ladder.games_simulated") Games simulated + th(data-i18n="ladder.games_played") Games played + th(data-i18n="ladder.ratio") Ratio + - var topSimulators = simulatorsLeaderboardData.topSimulators.models; + - var showJustTop = simulatorsLeaderboardData.inTopSimulators() || me.get('anonymous'); + - if(!showJustTop) topSimulators = topSimulators.slice(0, 10); + for user, rank in topSimulators + - var myRow = user.id == me.id + tr(class=myRow ? "success" : "") + td.simulator-leaderboard-cell= rank + 1 + td.name-col-cell= user.get('name') || "Anonymous" + td.simulator-leaderboard-cell= user.get('simulatedBy') + td.simulator-leaderboard-cell= user.get('simulatedFor') + td.simulator-leaderboard-cell= Math.round((user.get('simulatedBy') / user.get('simulatedFor')) * 10) / 10 + + if !showJustTop && simulatorsLeaderboardData.nearbySimulators().length + tr(class="active") + td(colspan=5).ellipsis-row ... + for user in simulatorsLeaderboardData.nearbySimulators() + - var myRow = user.id == me.id + - var ratio = user.get('simulatedBy') / user.get('simulatedFor'); + tr(class=myRow ? "success" : "") + td.simulator-leaderboard-cell= user.rank + td.name-col-cell= user.get('name') || "Anonymous" + td.simulator-leaderboard-cell= user.get('simulatedBy') + td.simulator-leaderboard-cell= user.get('simulatedFor') + td.simulator-leaderboard-cell= _.isNaN(ratio) || ratio == Infinity ? '' : ratio.toFixed(1) diff --git a/app/views/account/job_profile_view.coffee b/app/views/account/job_profile_view.coffee index d5e112acc..0d32cd799 100644 --- a/app/views/account/job_profile_view.coffee +++ b/app/views/account/job_profile_view.coffee @@ -15,13 +15,12 @@ module.exports = class JobProfileView extends CocoView afterRender: -> super() return if @loading() - @buildJobProfileTreema() + _.defer => @buildJobProfileTreema() # Not sure why, but the Treemas don't fully build without this if you reload the page. buildJobProfileTreema: -> visibleSettings = @editableSettings.concat @readOnlySettings data = _.pick (me.get('jobProfile') ? {}), (value, key) => key in visibleSettings data.name ?= (me.get('firstName') + ' ' + me.get('lastName')).trim() if me.get('firstName') - console.log 'schema?', me.schema() schema = _.cloneDeep me.schema().properties.jobProfile schema.properties = _.pick schema.properties, (value, key) => key in visibleSettings schema.required = _.intersection schema.required, visibleSettings @@ -42,10 +41,56 @@ module.exports = class JobProfileView extends CocoView @jobProfileTreema = @$el.find('#job-profile-treema').treema treemaOptions @jobProfileTreema.build() @jobProfileTreema.open() + @updateProgress() onJobProfileChanged: (e) => @hasEditedProfile = true @trigger 'change' + @updateProgress() + + updateProgress: -> + completed = 0 + totalWeight = 0 + next = null + for metric in metrics = @getProgressMetrics() + done = metric.fn() + completed += metric.weight ? 1 if done + totalWeight += metric.weight + next = metric.name unless next or done + progress = Math.round 100 * completed / totalWeight + bar = @$el.find('.profile-completion-progress .progress-bar') + bar.css 'width', "#{progress}%" + text = "" + if progress > 19 + text = "#{progress}% complete" + else if progress > 5 + text = "#{progress}%" + bar.text text + bar.parent().toggle Boolean progress + @$el.find('.progress-next-item').text(next).toggle Boolean next + + getProgressMetrics: -> + return @progressMetrics if @progressMetrics + schema = me.schema().properties.jobProfile + jobProfile = @jobProfileTreema.data + exists = (field) -> -> jobProfile[field] + modified = (field) -> -> jobProfile[field] and jobProfile[field] isnt schema.properties[field].default + listStarted = (field, subfields) -> -> jobProfile[field]?.length and _.every subfields, (subfield) -> jobProfile[field][0][subfield] + @progressMetrics = [ + {name: "Mark yourself open to offers to show up in searches.", weight: 1, fn: modified 'active'} + {name: "Specify your desired job title.", weight: 0, fn: exists 'jobTitle'} + {name: "Provide your name.", weight: 1, fn: modified 'name'} + {name: "Choose your city.", weight: 1, fn: modified 'city'} + {name: "Pick your country.", weight: 0, fn: exists 'country'} + {name: "List at least five skills.", weight: 2, fn: -> jobProfile.skills.length >= 5} + {name: "Write a short description to summarize yourself at a glance.", weight: 2, fn: modified 'shortDescription'} + {name: "Fill in your main description to sell yourself and describe the work you're looking for.", weight: 3, fn: modified 'longDescription'} + {name: "List your work experience.", weight: 3, fn: listStarted 'work', ['role', 'employer']} + {name: "Recount your educational ordeals.", weight: 3, fn: listStarted 'education', ['degree', 'school']} + {name: "Show off up to three projects you've worked on.", weight: 3, fn: listStarted 'projects', ['name']} + {name: "Add any personal or social links.", weight: 2, fn: listStarted 'links', ['link', 'name']} + {name: "Add an optional professional photo.", weight: 2, fn: modified 'photoURL'} + ] getData: -> return {} unless me.get('jobProfile') or @hasEditedProfile diff --git a/app/views/account/settings_view.coffee b/app/views/account/settings_view.coffee index 5e1d606da..16ea6b059 100644 --- a/app/views/account/settings_view.coffee +++ b/app/views/account/settings_view.coffee @@ -3,6 +3,7 @@ template = require 'templates/account/settings' {me} = require('lib/auth') forms = require('lib/forms') User = require('models/User') +LoginModalView = require 'views/modal/login_modal' WizardSettingsView = require './wizard_settings_view' JobProfileView = require './job_profile_view' @@ -43,7 +44,12 @@ module.exports = class SettingsView extends View @jobProfileView = new JobProfileView() @listenTo @jobProfileView, 'change', @save @insertSubView @jobProfileView - @buildPictureTreema() + _.defer => @buildPictureTreema() # Not sure why, but the Treemas don't fully build without this if you reload the page. + + afterInsert: -> + super() + if me.get('anonymous') + @openModalView new LoginModalView() chooseTab: (category) -> id = "##{category}-pane" @@ -78,10 +84,9 @@ module.exports = class SettingsView extends View buildPictureTreema: -> data = photoURL: me.get('photoURL') data.photoURL = null if data.photoURL?.search('gravatar') isnt -1 # Old style - schema = _.cloneDeep me.schema() + schema = $.extend true, {}, me.schema() schema.properties = _.pick me.schema().properties, 'photoURL' schema.required = ['photoURL'] - console.log 'have data', data, 'schema', schema treemaOptions = filePath: "db/user/#{me.id}" schema: schema diff --git a/app/views/community_view.coffee b/app/views/community_view.coffee new file mode 100644 index 000000000..e31b09f33 --- /dev/null +++ b/app/views/community_view.coffee @@ -0,0 +1,6 @@ +View = require 'views/kinds/RootView' +template = require 'templates/community' + +module.exports = class CommunityView extends View + id: "community-view" + template: template diff --git a/app/views/editor/delta.coffee b/app/views/editor/delta.coffee index 09c0981a6..b79b1cda5 100644 --- a/app/views/editor/delta.coffee +++ b/app/views/editor/delta.coffee @@ -21,12 +21,12 @@ module.exports = class DeltaView extends CocoView if @headModel @headDeltas = @headModel.getExpandedDelta() @conflicts = deltasLib.getConflicts(@headDeltas, @expandedDeltas) - DeltaView.deltaCounter += @expandedDeltas.length getRenderData: -> c = super() c.deltas = @expandedDeltas c.counter = DeltaView.deltaCounter + DeltaView.deltaCounter += @expandedDeltas.length c afterRender: -> diff --git a/app/views/editor/level/component/edit.coffee b/app/views/editor/level/component/edit.coffee index 3f91f1467..74c23b567 100644 --- a/app/views/editor/level/component/edit.coffee +++ b/app/views/editor/level/component/edit.coffee @@ -1,7 +1,9 @@ View = require 'views/kinds/CocoView' -VersionHistoryView = require 'views/editor/component/versions_view' template = require 'templates/editor/level/component/edit' LevelComponent = require 'models/LevelComponent' +VersionHistoryView = require 'views/editor/component/versions_view' +PatchesView = require 'views/editor/patches_view' +SaveVersionModal = require 'views/modal/save_version_modal' module.exports = class LevelComponentEditView extends View id: "editor-level-component-edit-view" @@ -10,8 +12,14 @@ module.exports = class LevelComponentEditView extends View events: 'click #done-editing-component-button': 'endEditing' - 'click #history-button': 'showVersionHistory' 'click .nav a': (e) -> $(e.target).tab('show') + 'click #component-patches-tab': -> @patchesView.load() + 'click #component-code-tab': 'buildCodeEditor' + 'click #component-config-schema-tab': 'buildConfigSchemaTreema' + 'click #component-settings-tab': 'buildSettingsTreema' + 'click #component-history-button': 'showVersionHistory' + 'click #patch-component-button': 'startPatchingComponent' + 'click #component-watch-button': 'toggleWatchComponent' constructor: (options) -> super options @@ -21,6 +29,7 @@ module.exports = class LevelComponentEditView extends View getRenderData: (context={}) -> context = super(context) context.editTitle = "#{@levelComponent.get('system')}.#{@levelComponent.get('name')}" + context.component = @levelComponent context afterRender: -> @@ -28,6 +37,8 @@ module.exports = class LevelComponentEditView extends View @buildSettingsTreema() @buildConfigSchemaTreema() @buildCodeEditor() + @patchesView = @insertSubView(new PatchesView(@levelComponent), @$el.find('.patches-view')) + @$el.find('#component-watch-button').find('> span').toggleClass('secret') if @levelComponent.watching() buildSettingsTreema: -> data = _.pick @levelComponent.attributes, (value, key) => key in @editableSettings @@ -40,7 +51,6 @@ module.exports = class LevelComponentEditView extends View schema: schema data: data callbacks: {change: @onComponentSettingsEdited} - treemaOptions.readOnly = true unless me.isAdmin() @componentSettingsTreema = @$el.find('#edit-component-treema').treema treemaOptions @componentSettingsTreema.build() @componentSettingsTreema.open() @@ -58,7 +68,6 @@ module.exports = class LevelComponentEditView extends View schema: LevelComponent.schema.properties.configSchema data: @levelComponent.get 'configSchema' callbacks: {change: @onConfigSchemaEdited} - treemaOptions.readOnly = true unless me.isAdmin() @configSchemaTreema = @$el.find('#config-schema-treema').treema treemaOptions @configSchemaTreema.build() @configSchemaTreema.open() @@ -70,10 +79,10 @@ module.exports = class LevelComponentEditView extends View Backbone.Mediator.publish 'level-component-edited', levelComponent: @levelComponent buildCodeEditor: -> - editorEl = @$el.find '#component-code-editor' - editorEl.text @levelComponent.get('code') + @editor?.destroy() + editorEl = $('<div></div>').text(@levelComponent.get('code')).addClass('inner-editor') + @$el.find('#component-code-editor').empty().append(editorEl) @editor = ace.edit(editorEl[0]) - @editor.setReadOnly(not me.isAdmin()) session = @editor.getSession() session.setMode 'ace/mode/coffee' session.setTabSize 2 @@ -90,11 +99,21 @@ module.exports = class LevelComponentEditView extends View Backbone.Mediator.publish 'level-component-editing-ended', levelComponent: @levelComponent null + showVersionHistory: (e) -> + versionHistoryView = new VersionHistoryView {}, @levelComponent.id + @openModalView versionHistoryView + Backbone.Mediator.publish 'level:view-switched', e + + startPatchingComponent: (e) -> + @openModalView new SaveVersionModal({model:@levelComponent}) + Backbone.Mediator.publish 'level:view-switched', e + + toggleWatchComponent: -> + button = @$el.find('#component-watch-button') + @levelComponent.watch(button.find('.watch').is(':visible')) + button.find('> span').toggleClass('secret') + destroy: -> @editor?.destroy() super() - showVersionHistory: (e) -> - versionHistoryView = new VersionHistoryView component:@levelComponent, @levelComponent.id - @openModalView versionHistoryView - Backbone.Mediator.publish 'level:view-switched', e \ No newline at end of file diff --git a/app/views/editor/level/components_tab_view.coffee b/app/views/editor/level/components_tab_view.coffee index 823bebed1..0a6ab8518 100644 --- a/app/views/editor/level/components_tab_view.coffee +++ b/app/views/editor/level/components_tab_view.coffee @@ -21,6 +21,7 @@ module.exports = class ComponentsTabView extends View events: 'click #create-new-component-button': 'createNewLevelComponent' + 'click #create-new-component-button-no-select': 'createNewLevelComponent' onLevelThangsChanged: (e) -> thangsData = e.thangsData diff --git a/app/views/editor/level/edit.coffee b/app/views/editor/level/edit.coffee index e28f87247..88d50be62 100644 --- a/app/views/editor/level/edit.coffee +++ b/app/views/editor/level/edit.coffee @@ -27,10 +27,18 @@ module.exports = class EditorLevelView extends View 'click #play-button': 'onPlayLevel' 'click #commit-level-start-button': 'startCommittingLevel' 'click #fork-level-start-button': 'startForkingLevel' - 'click #history-button': 'showVersionHistory' + 'click #level-history-button': 'showVersionHistory' 'click #patches-tab': -> @patchesView.load() - 'click #commit-level-patch-button': 'startPatchingLevel' + 'click #level-patch-button': 'startPatchingLevel' + 'click #level-watch-button': 'toggleWatchLevel' + + subscriptions: + 'refresh-level-editor': 'rerenderAllViews' + rerenderAllViews: -> + for view in [@thangsTab, @settingsTab, @scriptsTab, @componentsTab, @systemsTab, @patchesView] + view.render() + constructor: (options, @levelID) -> super options @listenToOnce(@supermodel, 'loaded-all', @onAllLoaded) @@ -83,7 +91,6 @@ module.exports = class EditorLevelView extends View afterRender: -> return if @startsLoading super() - new LevelSystem # temp; trigger the LevelSystem schema to be loaded, if it isn't already @$el.find('a[data-toggle="tab"]').on 'shown.bs.tab', (e) => Backbone.Mediator.publish 'level:view-switched', e @thangsTab = @insertSubView new ThangsTabView world: @world, supermodel: @supermodel @@ -94,6 +101,8 @@ module.exports = class EditorLevelView extends View Backbone.Mediator.publish 'level-loaded', level: @level @showReadOnly() if me.get('anonymous') @patchesView = @insertSubView(new PatchesView(@level), @$el.find('.patches-view')) + @listenTo @patchesView, 'accepted-patch', -> setTimeout "location.reload()", 400 + @$el.find('#level-watch-button').find('> span').toggleClass('secret') if @level.watching() onPlayLevel: (e) -> sendLevel = => @@ -125,3 +134,8 @@ module.exports = class EditorLevelView extends View versionHistoryView = new VersionHistoryView level:@level, @levelID @openModalView versionHistoryView Backbone.Mediator.publish 'level:view-switched', e + + toggleWatchLevel: -> + button = @$el.find('#level-watch-button') + @level.watch(button.find('.watch').is(':visible')) + button.find('> span').toggleClass('secret') diff --git a/app/views/editor/level/save_view.coffee b/app/views/editor/level/save_view.coffee index f47b07657..86ba7e96b 100644 --- a/app/views/editor/level/save_view.coffee +++ b/app/views/editor/level/save_view.coffee @@ -30,7 +30,7 @@ module.exports = class LevelSaveView extends SaveVersionModal context afterRender: -> - super() + super(false) changeEls = @$el.find('.changes-stub') models = if @lastContext.levelNeedsSave then [@level] else [] models = models.concat @lastContext.modifiedComponents diff --git a/app/views/editor/level/system/edit.coffee b/app/views/editor/level/system/edit.coffee index 338ede1e5..a7699b316 100644 --- a/app/views/editor/level/system/edit.coffee +++ b/app/views/editor/level/system/edit.coffee @@ -1,6 +1,9 @@ View = require 'views/kinds/CocoView' template = require 'templates/editor/level/system/edit' LevelSystem = require 'models/LevelSystem' +VersionHistoryView = require 'views/editor/system/versions_view' +PatchesView = require 'views/editor/patches_view' +SaveVersionModal = require 'views/modal/save_version_modal' module.exports = class LevelSystemEditView extends View id: "editor-level-system-edit-view" @@ -10,6 +13,13 @@ module.exports = class LevelSystemEditView extends View events: 'click #done-editing-system-button': 'endEditing' 'click .nav a': (e) -> $(e.target).tab('show') + 'click #system-patches-tab': -> @patchesView.load() + 'click #system-code-tab': 'buildCodeEditor' + 'click #system-config-schema-tab': 'buildConfigSchemaTreema' + 'click #system-settings-tab': 'buildSettingsTreema' + 'click #system-history-button': 'showVersionHistory' + 'click #patch-system-button': 'startPatchingSystem' + 'click #system-watch-button': 'toggleWatchSystem' constructor: (options) -> super options @@ -26,6 +36,7 @@ module.exports = class LevelSystemEditView extends View @buildSettingsTreema() @buildConfigSchemaTreema() @buildCodeEditor() + @patchesView = @insertSubView(new PatchesView(@levelSystem), @$el.find('.patches-view')) buildSettingsTreema: -> data = _.pick @levelSystem.attributes, (value, key) => key in @editableSettings @@ -68,8 +79,9 @@ module.exports = class LevelSystemEditView extends View Backbone.Mediator.publish 'level-system-edited', levelSystem: @levelSystem buildCodeEditor: -> - editorEl = @$el.find '#system-code-editor' - editorEl.text @levelSystem.get('code') + @editor?.destroy() + editorEl = $('<div></div>').text(@levelSystem.get('code')).addClass('inner-editor') + @$el.find('#system-code-editor').empty().append(editorEl) @editor = ace.edit(editorEl[0]) @editor.setReadOnly(not me.isAdmin()) session = @editor.getSession() @@ -88,6 +100,21 @@ module.exports = class LevelSystemEditView extends View Backbone.Mediator.publish 'level-system-editing-ended', levelSystem: @levelSystem null + showVersionHistory: (e) -> + versionHistoryView = new VersionHistoryView {}, @levelSystem.id + @openModalView versionHistoryView + Backbone.Mediator.publish 'level:view-switched', e + + startPatchingSystem: (e) -> + @openModalView new SaveVersionModal({model:@levelSystem}) + Backbone.Mediator.publish 'level:view-switched', e + + toggleWatchSystem: -> + console.log 'toggle watch system?' + button = @$el.find('#system-watch-button') + @levelSystem.watch(button.find('.watch').is(':visible')) + button.find('> span').toggleClass('secret') + destroy: -> @editor?.destroy() super() diff --git a/app/views/editor/level/systems_tab_view.coffee b/app/views/editor/level/systems_tab_view.coffee index eb4747b0e..e3f4fa626 100644 --- a/app/views/editor/level/systems_tab_view.coffee +++ b/app/views/editor/level/systems_tab_view.coffee @@ -23,6 +23,7 @@ module.exports = class SystemsTabView extends View events: 'click #add-system-button': 'addLevelSystem' 'click #create-new-system-button': 'createNewLevelSystem' + 'click #create-new-system': 'createNewLevelSystem' constructor: (options) -> super options diff --git a/app/views/editor/level/thangs_tab_view.coffee b/app/views/editor/level/thangs_tab_view.coffee index 8a6c4cfe5..d19a93eab 100644 --- a/app/views/editor/level/thangs_tab_view.coffee +++ b/app/views/editor/level/thangs_tab_view.coffee @@ -179,6 +179,7 @@ module.exports = class ThangsTabView extends View destroy: -> @selectAddThangType null @surface.destroy() + $(document).unbind 'contextmenu', @preventDefaultContextMenu super() onViewSwitched: (e) -> @@ -254,6 +255,7 @@ module.exports = class ThangsTabView extends View # @thangsTreema.deselectAll() selectAddThang: (e) => + return unless e? and $(e.target).closest('.editor-level-thangs-tab-view').length if e then target = $(e.target) else target = @$el.find('.add-thangs-palette') # pretend to click on background if no event return true if target.attr('id') is 'surface' target = target.closest('.add-thang-palette-icon') @@ -424,10 +426,11 @@ module.exports = class ThangsTabView extends View @editThangView = null @onThangsChanged() @$el.find('.thangs-column').show() - + preventDefaultContextMenu: (e) -> + return unless $(e.target).closest('#canvas-wrapper').length e.preventDefault() - + onSpriteContextMenu: (e) -> {clientX, clientY} = e.originalEvent.nativeEvent if @addThangType @@ -436,11 +439,11 @@ module.exports = class ThangsTabView extends View $('#duplicate a').html 'Duplicate' $('#contextmenu').css { position: 'fixed', left: clientX, top: clientY } $('#contextmenu').show() - + onDeleteClicked: (e) -> $('#contextmenu').hide() @deleteSelectedExtantThang e - + onDuplicateClicked: (e) -> $('#contextmenu').hide() if !@addThangType diff --git a/app/views/editor/patch_modal.coffee b/app/views/editor/patch_modal.coffee index 19f3ebfe6..f5dc339cf 100644 --- a/app/views/editor/patch_modal.coffee +++ b/app/views/editor/patch_modal.coffee @@ -7,6 +7,7 @@ module.exports = class PatchModal extends ModalView id: "patch-modal" template: template plain: true + modalWidthPercent: 60 events: 'click #withdraw-button': 'withdrawPatch' @@ -30,12 +31,15 @@ module.exports = class PatchModal extends ModalView c.isPatchCreator = @patch.get('creator') is auth.me.id c.isPatchRecipient = @targetModel.hasWriteAccess() c.status = @patch.get 'status' + c.patch = @patch c afterRender: -> return if @originalSource.loading - headModel = @originalSource.clone(false) - headModel.set(@targetModel.attributes) + headModel = null + if @targetModel.hasWriteAccess() + headModel = @originalSource.clone(false) + headModel.set(@targetModel.attributes) pendingModel = @originalSource.clone(false) pendingModel.applyDelta(@patch.get('delta')) @@ -48,7 +52,8 @@ module.exports = class PatchModal extends ModalView acceptPatch: -> delta = @deltaView.getApplicableDelta() @targetModel.applyDelta(delta) - @targetModel.addPatchToAcceptOnSave(@patch) + @patch.setStatus('accepted') + @trigger 'accepted-patch' @hide() rejectPatch: -> diff --git a/app/views/editor/patches_view.coffee b/app/views/editor/patches_view.coffee index f8dd4fa15..8887b44bb 100644 --- a/app/views/editor/patches_view.coffee +++ b/app/views/editor/patches_view.coffee @@ -44,8 +44,11 @@ module.exports = class PatchesView extends CocoView @$el.find(".#{@status}").addClass 'active' onStatusButtonsChanged: (e) -> - @loaded = false @status = $(e.target).val() + @reloadPatches() + + reloadPatches: -> + @loaded = false @initPatches() @load() @render() @@ -53,4 +56,9 @@ module.exports = class PatchesView extends CocoView openPatchModal: (e) -> patch = _.find @patches.models, {id:$(e.target).data('patch-id')} modal = new PatchModal(patch, @model) - @openModalView(modal) \ No newline at end of file + @openModalView(modal) + @listenTo modal, 'accepted-patch', -> @trigger 'accepted-patch' + @listenTo modal, 'hide', -> + f = => @reloadPatches() + setTimeout(f, 400) + @stopListening modal \ No newline at end of file diff --git a/app/views/editor/system/versions_view.coffee b/app/views/editor/system/versions_view.coffee new file mode 100755 index 000000000..562d134ad --- /dev/null +++ b/app/views/editor/system/versions_view.coffee @@ -0,0 +1,9 @@ +VersionsModalView = require 'views/modal/versions_modal' + +module.exports = class SystemVersionsView extends VersionsModalView + id: "editor-system-versions-view" + url: "/db/level.system/" + page: "system" + + constructor: (options, @ID) -> + super options, ID, require 'models/LevelSystem' \ No newline at end of file diff --git a/app/views/editor/thang/colors_tab_view.coffee b/app/views/editor/thang/colors_tab_view.coffee index 87c887522..dab519da6 100644 --- a/app/views/editor/thang/colors_tab_view.coffee +++ b/app/views/editor/thang/colors_tab_view.coffee @@ -112,7 +112,7 @@ module.exports = class ColorsTabView extends CocoView @buttons = buttons tryToBuild: -> - return unless @thangType.loaded and @thangType.schema().loaded + return unless @thangType.loaded data = @thangType.get('colorGroups') data ?= {} schema = @thangType.schema().properties?.colorGroups diff --git a/app/views/kinds/CocoView.coffee b/app/views/kinds/CocoView.coffee index 6d295bdb2..5e9275ca3 100644 --- a/app/views/kinds/CocoView.coffee +++ b/app/views/kinds/CocoView.coffee @@ -113,15 +113,18 @@ class CocoView extends Backbone.View @listenToOnce modelOrCollection, 'sync', @updateProgress @listenTo modelOrCollection, 'error', @onResourceLoadFailed @updateProgress() + @loaded = false addRequestToLoad: (jqxhr, name, retryFunc, value=1) -> @loadProgress.requests.push {request:jqxhr, value:value, name: name, retryFunc: retryFunc} jqxhr.done @updateProgress jqxhr.fail @onRequestLoadFailed + @loaded = false addSomethingToLoad: (name, value=1) -> @loadProgress.somethings.push {loaded: false, name: name, value: value} @updateProgress() + @loaded = false somethingLoaded: (name) -> r = _.find @loadProgress.somethings, {name: name} @@ -145,9 +148,9 @@ class CocoView extends Backbone.View console.debug 'Loaded', r.name if arguments[0] and r = _.find @loadProgress.somethings, {name:arguments[0]} denom = 0 - denom += r.value for r in @loadProgress.resources + denom += r.value for r in @loadProgress.resources when not r.resource.destroyed denom += r.value for r in @loadProgress.requests - denom += r.value for r in @loadProgress.somethings + denom += r.value for r in @loadProgress.somethings when not r.destroyed num = @loadProgress.num num += r.value for r in @loadProgress.resources when r.resource.loaded num += r.value for r in @loadProgress.requests when r.request.status @@ -204,6 +207,7 @@ class CocoView extends Backbone.View # Modals toggleModal: (e) -> + return if visibleModal if $(e.currentTarget).prop('target') is '_blank' return true # special handler for opening modals that are dynamically loaded, rather than static in the page. It works (or should work) like Bootstrap's modals, except use coco-modal for the data-toggle value. diff --git a/app/views/kinds/ModalView.coffee b/app/views/kinds/ModalView.coffee index 2bf6ee8db..26a32081a 100644 --- a/app/views/kinds/ModalView.coffee +++ b/app/views/kinds/ModalView.coffee @@ -45,9 +45,11 @@ module.exports = class ModalView extends CocoView super($el) hide: -> + @trigger 'hide' @$el.removeClass('fade').modal "hide" onHidden: -> + @trigger 'hidden' destroy: -> @hide() unless @hidden diff --git a/app/views/modal/model_modal.coffee b/app/views/modal/model_modal.coffee new file mode 100644 index 000000000..fc7922320 --- /dev/null +++ b/app/views/modal/model_modal.coffee @@ -0,0 +1,47 @@ +View = require 'views/kinds/ModalView' +template = require 'templates/modal/model' + +module.exports = class ModelModal extends View + id: 'model-modal' + template: template + + constructor: (options) -> + super options + @models = options.models + for model in @models when not model.loaded + @addResourceToLoad model, 'model' + model.fetch() + + getRenderData: -> + c = super() + c.models = @models + c + + afterRender: -> + super() + return if @loading() + for model in @models + data = $.extend true, {}, model.attributes + schema = $.extend true, {}, model.schema() + treemaOptions = + schema: schema + data: data + readOnly: false + modelTreema = @$el.find(".model-treema[data-model-id='#{model.id}']").treema treemaOptions + modelTreema?.build() + modelTreema?.open() + @openTastyTreemas modelTreema, model + + openTastyTreemas: (modelTreema, model) -> + # To save on quick inspection, let's auto-open the properties we're most likely to want to see. + delicacies = ['code'] + for dish in delicacies + child = modelTreema.childrenTreemas[dish] + child?.open() + if child and dish is 'code' and model.type() is 'LevelSession' and team = modelTreema.get('team') + desserts = { + humans: ['programmable-tharin', 'programmable-librarian'] + ogres: ['programmable-brawler', 'programmable-shaman'] + }[team] + for dessert in desserts + child.childrenTreemas[dessert]?.open() diff --git a/app/views/modal/save_version_modal.coffee b/app/views/modal/save_version_modal.coffee index fda6b3951..d95fc4166 100644 --- a/app/views/modal/save_version_modal.coffee +++ b/app/views/modal/save_version_modal.coffee @@ -8,6 +8,7 @@ module.exports = class SaveVersionModal extends ModalView id: 'save-version-modal' template: template plain: true + modalWidthPercent: 60 events: 'click #save-version-button': 'onClickSaveButton' @@ -18,7 +19,6 @@ module.exports = class SaveVersionModal extends ModalView constructor: (options) -> super options @model = options.model or options.level - new Patch() # hack to get the schema to load, delete this later @isPatch = not @model.hasWriteAccess() getRenderData: -> @@ -27,15 +27,16 @@ module.exports = class SaveVersionModal extends ModalView c.hasChanges = @model.hasLocalChanges() c - afterRender: -> + afterRender: (insertDeltaView=true) -> super() @$el.find(if me.get('signedCLA') then '#accept-cla-wrapper' else '#save-version-button').hide() changeEl = @$el.find('.changes-stub') - try - deltaView = new DeltaView({model:@model}) - @insertSubView(deltaView, changeEl) - catch e - console.error "Couldn't create delta view:", e + if insertDeltaView + try + deltaView = new DeltaView({model:@model}) + @insertSubView(deltaView, changeEl) + catch e + console.error "Couldn't create delta view:", e @$el.find('.commit-message input').attr('placeholder', $.i18n.t('general.commit_msg')) onClickSaveButton: -> @@ -55,6 +56,7 @@ module.exports = class SaveVersionModal extends ModalView } errors = patch.validate() forms.applyErrorsToForm(@$el, errors) if errors + patch.set 'editPath', document.location.pathname res = patch.save() return unless res @enableModalInProgress(@$el) diff --git a/app/views/modal/versions_modal.coffee b/app/views/modal/versions_modal.coffee index 97aeafb33..6bf511396 100755 --- a/app/views/modal/versions_modal.coffee +++ b/app/views/modal/versions_modal.coffee @@ -13,6 +13,8 @@ class VersionsViewCollection extends Backbone.Collection module.exports = class VersionsModalView extends ModalView template: template startsLoading: true + plain: true + modalWidthPercent: 80 # needs to be overwritten by child id: "" diff --git a/app/views/play/ladder/ladder_tab.coffee b/app/views/play/ladder/ladder_tab.coffee index 59d04b102..cc88ed474 100644 --- a/app/views/play/ladder/ladder_tab.coffee +++ b/app/views/play/ladder/ladder_tab.coffee @@ -3,8 +3,10 @@ CocoClass = require 'lib/CocoClass' Level = require 'models/Level' LevelSession = require 'models/LevelSession' CocoCollection = require 'models/CocoCollection' +User = require 'models/User' LeaderboardCollection = require 'collections/LeaderboardCollection' {teamDataFromLevel} = require './utils' +ModelModal = require 'views/modal/model_modal' HIGHEST_SCORE = 1000000 @@ -23,6 +25,8 @@ module.exports = class LadderTabView extends CocoView events: 'click .connect-facebook': 'onConnectFacebook' 'click .connect-google-plus': 'onConnectGPlus' + 'click .name-col-cell': 'onClickPlayerName' + 'click .load-more-ladder-entries': 'onLoadMoreLadderEntries' subscriptions: 'fbapi-loaded': 'checkFriends' @@ -42,7 +46,7 @@ module.exports = class LadderTabView extends CocoView return if @checked or (not window.FB) or (not window.gapi) @checked = true - @addSomethingToLoad("facebook_status") + @addSomethingToLoad("facebook_status", 0) # This might not load ever, so we can't wait for it FB.getLoginStatus (response) => @facebookStatus = response.status @loadFacebookFriends() if @facebookStatus is 'connected' @@ -101,7 +105,7 @@ module.exports = class LadderTabView extends CocoView gplusSessionStateLoaded: -> if application.gplusHandler.loggedIn - @addSomethingToLoad("gplus_friends", 0) # this might not load ever, so we can't wait for it + @addSomethingToLoad("gplus_friends", 0) # This might not load ever, so we can't wait for it application.gplusHandler.loadFriends @gplusFriendsLoaded gplusFriendsLoaded: (friends) => @@ -134,7 +138,8 @@ module.exports = class LadderTabView extends CocoView for team in @teams @leaderboards[team.id]?.destroy() teamSession = _.find @sessions.models, (session) -> session.get('team') is team.id - @leaderboards[team.id] = new LeaderboardData(@level, team.id, teamSession) + @ladderLimit ?= parseInt @getQueryVariable('top_players', 20) + @leaderboards[team.id] = new LeaderboardData(@level, team.id, teamSession, @ladderLimit) @addResourceToLoad @leaderboards[team.id], 'leaderboard', 3 @@ -245,17 +250,30 @@ module.exports = class LadderTabView extends CocoView sessions.reverse() sessions + # Admin view of players' code + onClickPlayerName: (e) -> + return unless me.isAdmin() + row = $(e.target).parent() + player = new User _id: row.data 'player-id' + session = new LevelSession _id: row.data 'session-id' + @openModalView new ModelModal models: [session, player] + + onLoadMoreLadderEntries: (e) -> + @ladderLimit ?= 100 + @ladderLimit += 100 + @refreshLadder() + class LeaderboardData extends CocoClass ### Consolidates what you need to load for a leaderboard into a single Backbone Model-like object. ### - constructor: (@level, @team, @session) -> + constructor: (@level, @team, @session, @limit) -> super() @fetch() fetch: -> - @topPlayers = new LeaderboardCollection(@level, {order:-1, scoreOffset: HIGHEST_SCORE, team: @team, limit: 20}) + @topPlayers = new LeaderboardCollection(@level, {order:-1, scoreOffset: HIGHEST_SCORE, team: @team, limit: @limit}) promises = [] promises.push @topPlayers.fetch() @@ -291,8 +309,8 @@ class LeaderboardData extends CocoClass return [] unless @session?.get('totalScore') l = [] above = @playersAbove.models - above.reverse() l = l.concat(above) + l.reverse() l.push @session l = l.concat(@playersBelow.models) if @myRank diff --git a/app/views/play/ladder/simulate_tab.coffee b/app/views/play/ladder/simulate_tab.coffee new file mode 100644 index 000000000..7b032ef8f --- /dev/null +++ b/app/views/play/ladder/simulate_tab.coffee @@ -0,0 +1,130 @@ +CocoView = require 'views/kinds/CocoView' +CocoClass = require 'lib/CocoClass' +SimulatorsLeaderboardCollection = require 'collections/SimulatorsLeaderboardCollection' +Simulator = require 'lib/simulator/Simulator' +{me} = require 'lib/auth' + +module.exports = class SimulateTabView extends CocoView + id: 'simulate-tab-view' + template: require 'templates/play/ladder/simulate_tab' + + events: + 'click #simulate-button': 'onSimulateButtonClick' + 'click #simulate-all-button': 'onSimulateAllButtonClick' + + constructor: (options) -> + super(options) + @simulatorsLeaderboardData = new SimulatorsLeaderboardData(me) + @addResourceToLoad(@simulatorsLeaderboardData, 'top_simulators') + @simulator = new Simulator() + @listenTo(@simulator, 'statusUpdate', @updateSimulationStatus) + + onLoaded: -> + super() + + getRenderData: -> + ctx = super() + ctx.simulationStatus = @simulationStatus + ctx.simulatorsLeaderboardData = @simulatorsLeaderboardData + ctx._ = _ + ctx + + afterRender: -> + super() + + # Simulations + + onSimulateButtonClick: (e) -> + $("#simulate-button").prop "disabled",true + $("#simulate-button").text "Simulating..." + + @simulator.fetchAndSimulateTask() + + updateSimulationStatus: (simulationStatus, sessions) -> + @simulationStatus = simulationStatus + try + if sessions? + #TODO: Fetch names from Redis, the creatorName is denormalized + creatorNames = (session.creatorName for session in sessions) + @simulationStatus = "Simulating game between " + for index in [0...creatorNames.length] + unless creatorNames[index] + creatorNames[index] = "Anonymous" + @simulationStatus += (if index != 0 then " and " else "") + creatorNames[index] + @simulationStatus += "..." + catch e + console.log "There was a problem with the named simulation status: #{e}" + $("#simulation-status-text").text @simulationStatus + + resimulateAllSessions: -> + postData = + originalLevelID: @level.get('original') + levelMajorVersion: @level.get('version').major + console.log postData + + $.ajax + url: '/queue/scoring/resimulateAllSessions' + method: 'POST' + data: postData + complete: (jqxhr) -> + console.log jqxhr.responseText + + destroy: -> + clearInterval @refreshInterval + @simulator.destroy() + super() + +class SimulatorsLeaderboardData extends CocoClass + ### + Consolidates what you need to load for a leaderboard into a single Backbone Model-like object. + ### + + constructor: (@me) -> + super() + @fetch() + + fetch: -> + @topSimulators = new SimulatorsLeaderboardCollection({order:-1, scoreOffset: -1, limit: 20}) + promises = [] + promises.push @topSimulators.fetch() + unless @me.get('anonymous') + score = @me.get('simulatedBy') or 0 + @playersAbove = new SimulatorsLeaderboardCollection({order:1, scoreOffset: score, limit: 4}) + promises.push @playersAbove.fetch() + if score + @playersBelow = new SimulatorsLeaderboardCollection({order:-1, scoreOffset: score, limit: 4}) + promises.push @playersBelow.fetch() + success = (@myRank) => + promises.push $.ajax "/db/user/me/simulator_leaderboard_rank?scoreOffset=#{score}", {success} + @promise = $.when(promises...) + @promise.then @onLoad + @promise.fail @onFail + @promise + + onLoad: => + return if @destroyed + @loaded = true + @trigger 'sync', @ + + onFail: (resource, jqxhr) => + return if @destroyed + @trigger 'error', @, jqxhr + + inTopSimulators: -> + return me.id in (user.id for user in @topSimulators.models) + + nearbySimulators: -> + l = [] + above = @playersAbove.models + l = l.concat(above) + l.reverse() + l.push @me + l = l.concat(@playersBelow.models) if @playersBelow + if @myRank + startRank = @myRank - 4 + user.rank = startRank + i for user, i in l + l + + allResources: -> + resources = [@topSimulators, @playersAbove, @playersBelow] + return (r for r in resources when r) diff --git a/app/views/play/ladder_view.coffee b/app/views/play/ladder_view.coffee index 2b8e3a2b8..e8781c685 100644 --- a/app/views/play/ladder_view.coffee +++ b/app/views/play/ladder_view.coffee @@ -1,6 +1,5 @@ RootView = require 'views/kinds/RootView' Level = require 'models/Level' -Simulator = require 'lib/simulator/Simulator' LevelSession = require 'models/LevelSession' CocoCollection = require 'models/CocoCollection' {teamDataFromLevel} = require './ladder/utils' @@ -9,8 +8,8 @@ application = require 'application' LadderTabView = require './ladder/ladder_tab' MyMatchesTabView = require './ladder/my_matches_tab' +SimulateTabView = require './ladder/simulate_tab' LadderPlayModal = require './ladder/play_modal' -SimulatorsLeaderboardCollection = require 'collections/SimulatorsLeaderboardCollection' CocoClass = require 'lib/CocoClass' HIGHEST_SCORE = 1000000 @@ -31,8 +30,6 @@ module.exports = class LadderView extends RootView 'application:idle-changed': 'onIdleChanged' events: - 'click #simulate-button': 'onSimulateButtonClick' - 'click #simulate-all-button': 'onSimulateAllButtonClick' 'click .play-button': 'onClickPlayButton' 'click a': 'onClickedLink' @@ -44,10 +41,6 @@ module.exports = class LadderView extends RootView @sessions.fetch({}) @addResourceToLoad(@sessions, 'your_sessions') @addResourceToLoad(@level, 'level') - @simulatorsLeaderboardData = new SimulatorsLeaderboardData(me) - @addResourceToLoad(@simulatorsLeaderboardData, 'top_simulators') - @simulator = new Simulator() - @listenTo(@simulator, 'statusUpdate', @updateSimulationStatus) @teams = [] onLoaded: -> @@ -58,11 +51,9 @@ module.exports = class LadderView extends RootView ctx = super() ctx.level = @level ctx.link = "/play/level/#{@level.get('name')}" - ctx.simulationStatus = @simulationStatus ctx.teams = @teams ctx.levelID = @levelID ctx.levelDescription = marked(@level.get('description')) if @level.get('description') - ctx.simulatorsLeaderboardData = @simulatorsLeaderboardData ctx._ = _ ctx @@ -71,7 +62,8 @@ module.exports = class LadderView extends RootView return if @loading() @insertSubView(@ladderTab = new LadderTabView({}, @level, @sessions)) @insertSubView(@myMatchesTab = new MyMatchesTabView({}, @level, @sessions)) - @refreshInterval = setInterval(@fetchSessionsAndRefreshViews.bind(@), 10 * 1000) + @insertSubView(@simulateTab = new SimulateTabView()) + @refreshInterval = setInterval(@fetchSessionsAndRefreshViews.bind(@), 20 * 1000) hash = document.location.hash[1..] if document.location.hash if hash and not (hash in ['my-matches', 'simulate', 'ladder']) @showPlayModal(hash) if @sessions.loaded @@ -90,57 +82,9 @@ module.exports = class LadderView extends RootView onIdleChanged: (e) -> @fetchSessionsAndRefreshViews() unless e.idle - # Simulations - - onSimulateAllButtonClick: (e) -> - submitIDs = _.pluck @leaderboards[@teams[0].id].topPlayers.models, "id" - for ID in submitIDs - $.ajax - url: '/queue/scoring' - method: 'POST' - data: - session: ID - $("#simulate-all-button").prop "disabled", true - $("#simulate-all-button").text "Submitted all!" - - onSimulateButtonClick: (e) -> - $("#simulate-button").prop "disabled",true - $("#simulate-button").text "Simulating..." - - @simulator.fetchAndSimulateTask() - - updateSimulationStatus: (simulationStatus, sessions) -> - @simulationStatus = simulationStatus - try - if sessions? - #TODO: Fetch names from Redis, the creatorName is denormalized - creatorNames = (session.creatorName for session in sessions) - @simulationStatus = "Simulating game between " - for index in [0...creatorNames.length] - unless creatorNames[index] - creatorNames[index] = "Anonymous" - @simulationStatus += (if index != 0 then " and " else "") + creatorNames[index] - @simulationStatus += "..." - catch e - console.log "There was a problem with the named simulation status: #{e}" - $("#simulation-status-text").text @simulationStatus - onClickPlayButton: (e) -> @showPlayModal($(e.target).closest('.play-button').data('team')) - resimulateAllSessions: -> - postData = - originalLevelID: @level.get('original') - levelMajorVersion: @level.get('version').major - console.log postData - - $.ajax - url: '/queue/scoring/resimulateAllSessions' - method: 'POST' - data: postData - complete: (jqxhr) -> - console.log jqxhr.responseText - showPlayModal: (teamID) -> return @showApologeticSignupModal() if me.get('anonymous') session = (s for s in @sessions.models when s.get('team') is teamID)[0] @@ -160,55 +104,4 @@ module.exports = class LadderView extends RootView destroy: -> clearInterval @refreshInterval - @simulator.destroy() super() - -class SimulatorsLeaderboardData extends CocoClass - ### - Consolidates what you need to load for a leaderboard into a single Backbone Model-like object. - ### - - constructor: (@me) -> - super() - @fetch() - - fetch: -> - @topSimulators = new SimulatorsLeaderboardCollection({order:-1, scoreOffset: -1, limit: 20}) - promises = [] - promises.push @topSimulators.fetch() - unless @me.get('anonymous') - score = @me.get('simulatedBy') or 0 - @playersAbove = new SimulatorsLeaderboardCollection({order:1, scoreOffset: score, limit: 4}) - promises.push @playersAbove.fetch() - if score - @playersBelow = new SimulatorsLeaderboardCollection({order:-1, scoreOffset: score, limit: 4}) - promises.push @playersBelow.fetch() - @promise = $.when(promises...) - @promise.then @onLoad - @promise.fail @onFail - @promise - - onLoad: => - return if @destroyed - @loaded = true - @trigger 'sync', @ - - onFail: (resource, jqxhr) => - return if @destroyed - @trigger 'error', @, jqxhr - - inTopSimulators: -> - return me.id in (user.id for user in @topSimulators.models) - - nearbySimulators: -> - l = [] - above = @playersAbove.models - above.reverse() - l = l.concat(above) - l.push @me - l = l.concat(@playersBelow.models) if @playersBelow - l - - allResources: -> - resources = [@topSimulators, @playersAbove, @playersBelow] - return (r for r in resources when r) diff --git a/app/views/play/level/level_loading_view.coffee b/app/views/play/level/level_loading_view.coffee index f242acec3..2c8b608b0 100644 --- a/app/views/play/level/level_loading_view.coffee +++ b/app/views/play/level/level_loading_view.coffee @@ -17,6 +17,7 @@ module.exports = class LevelLoadingView extends View @$el.find('.to-remove').remove() onLevelLoaderProgressChanged: (e) -> + return if @destroyed @progress = e.progress @progress = 0.01 if @progress < 0.01 @updateProgressBar() diff --git a/app/views/play/level/tome/tome_view.coffee b/app/views/play/level/tome/tome_view.coffee index 26246b26c..569f205bf 100644 --- a/app/views/play/level/tome/tome_view.coffee +++ b/app/views/play/level/tome/tome_view.coffee @@ -36,7 +36,7 @@ ThangListView = require './thang_list_view' SpellPaletteView = require './spell_palette_view' CastButtonView = require './cast_button_view' -window.SHIM_WORKER_PATH = '/javascripts/workers/catiline_worker_shim.coffee' +window.SHIM_WORKER_PATH = '/javascripts/workers/catiline_worker_shim.js' module.exports = class TomeView extends View id: 'tome-view' diff --git a/config.coffee b/config.coffee index 27c476980..b95413164 100644 --- a/config.coffee +++ b/config.coffee @@ -11,6 +11,7 @@ exports.config = ignored: (path) -> startsWith(sysPath.basename(path), '_') workers: enabled: false # turned out to be much, much slower than without workers + sourceMaps: true files: javascripts: defaultExtension: 'coffee' diff --git a/package.json b/package.json index ee0dcc201..d4c3fb6c9 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,8 @@ "karma-requirejs": "~0.2.1", "karma-phantomjs-launcher": "~0.1.1", "karma": "~0.10.9", - "karma-coverage": "~0.1.4" + "karma-coverage": "~0.1.4", + "compressible": "~1.0.1" }, "license": "MIT for the code, and CC-BY for the art and music", "private": true, diff --git a/scripts/mail.coffee b/scripts/mail.coffee new file mode 100644 index 000000000..140697370 --- /dev/null +++ b/scripts/mail.coffee @@ -0,0 +1,103 @@ +do (setupLodash = this) -> + GLOBAL._ = require 'lodash' + _.str = require 'underscore.string' + _.mixin _.str.exports() + +async = require 'async' + +serverSetup = require '../server_setup' +sendwithus = require '../server/sendwithus' +User = require '../server/users/User.coffee' +Level = require '../server/levels/Level.coffee' +LevelSession = require '../server/levels/sessions/LevelSession.coffee' + +alreadyEmailed = [] + +DEBUGGING = true + +sendInitialRecruitingEmail = -> + leaderboards = [ + {slug: 'brawlwood', team: 'humans', limit: 55, name: "Brawlwood", original: "52d97ecd32362bc86e004e87", majorVersion: 0} + {slug: 'brawlwood', team: 'ogres', limit: 40, name: "Brawlwood", original: "52d97ecd32362bc86e004e87", majorVersion: 0} + {slug: 'dungeon-arena', team: 'humans', limit: 200, name: "Dungeon Arena", original: "53173f76c269d400000543c2", majorVersion: 0} + {slug: 'dungeon-arena', team: 'ogres', limit: 150, name: "Dungeon Arena", original: "53173f76c269d400000543c2", majorVersion: 0} + ] + async.waterfall [ + (callback) -> async.map leaderboards, grabSessions, callback + (sessionLists, callback) -> async.map collapseSessions(sessionLists), grabUser, callback + (users, callback) -> async.map users, emailUser, callback + ], (err, results) -> + return console.log "Error:", err if err + console.log "Looked at sending to #{results.length} users; sent to #{_.filter(results).length}." + console.log "Sent to: ['#{(user.email for user in results when user).join('\', \'')}']" + +grabSessions = (levelInfo, callback) -> + queryParameters = + level: {original: levelInfo.original, majorVersion: levelInfo.majorVersion} + team: levelInfo.team + submitted: true + sortParameters = totalScore: -1 + selectString = 'totalScore creator' + query = LevelSession + .find(queryParameters) + .limit(levelInfo.limit) + .sort(sortParameters) + .select(selectString) + .lean() + query.exec (err, sessions) -> + return callback err if err + for session, rank in sessions + session.levelInfo = levelInfo + session.rank = rank + 1 + callback null, sessions + +collapseSessions = (sessionLists) -> + userRanks = {} + for sessionList in sessionLists + for session in sessionList + ranks = userRanks[session.creator] ? [] + ranks.push session + userRanks[session.creator] = _.sortBy ranks, 'rank' + topSessions = [] + for userID, ranks of userRanks + topSessions.push ranks[0] + topSessions + +grabUser = (session, callback) -> + findParameters = _id: session.creator + selectString = 'email emailSubscriptions name jobProfile' + query = User + .findOne(findParameters) + .select(selectString) + .lean() + query.exec (err, user) -> + return callback err if err + user.session = session + callback null, user + +totalEmailsSent = 0 +emailUser = (user, callback) -> + return callback null, false if user.emails?.recruiting?.enabled is false # TODO: later, obey also "announcements" when that's untangled + return callback null, false if user.email in alreadyEmailed + return callback null, false if DEBUGGING and (totalEmailsSent > 1 or Math.random() > 0.1) + ++totalEmailsSent + name = if user.firstName and user.lastName then "#{user.firstName}" else user.name + name = "Wizard" if not name or name is "Anoner" + team = user.session.levelInfo.team + team = team.substr(0, team.length - 1) + context = + email_id: sendwithus.templates.one_time_recruiting_email + recipient: + address: if DEBUGGING then 'nick@codecombat.com' else user.email + name: name + email_data: + name: name + level_name: user.session.levelInfo.name + place: "##{user.session.rank}" # like "#31" + level_race: team + sendwithus.api.send context, (err, result) -> + return callback err if err + callback null, user + +serverSetup.connectToDatabase() +sendInitialRecruitingEmail() diff --git a/server/commons/Handler.coffee b/server/commons/Handler.coffee index b486b79b0..aed496fd8 100644 --- a/server/commons/Handler.coffee +++ b/server/commons/Handler.coffee @@ -4,6 +4,8 @@ Grid = require 'gridfs-stream' errors = require './errors' log = require 'winston' Patch = require '../patches/Patch' +User = require '../users/User' +sendwithus = require '../sendwithus' PROJECT = {original:1, name:1, version:1, description: 1, slug:1, kind: 1} FETCH_LIMIT = 200 @@ -95,7 +97,7 @@ module.exports = class Handler # this handler should be overwritten by subclasses if @modelClass.schema.is_patchable return @getPatchesFor(req, res, args[0]) if req.route.method is 'get' and args[1] is 'patches' - return @setListening(req, res, args[0]) if req.route.method is 'put' and args[1] is 'listen' + return @setWatching(req, res, args[0]) if req.route.method is 'put' and args[1] is 'watch' return @sendNotFoundError(res) getPatchesFor: (req, res, id) -> @@ -105,16 +107,16 @@ module.exports = class Handler patches = (patch.toObject() for patch in patches) @sendSuccess(res, patches) - setListening: (req, res, id) -> + setWatching: (req, res, id) -> @getDocumentForIdOrSlug id, (err, document) => return @sendUnauthorizedError(res) unless @hasAccessToDocument(req, document, 'get') return @sendDatabaseError(res, err) if err return @sendNotFoundError(res) unless document? - listeners = document.get('listeners') or [] + watchers = document.get('watchers') or [] me = req.user.get('_id') - listeners = (l for l in listeners when not l.equals(me)) - listeners.push me if req.body.on - document.set 'listeners', listeners + watchers = (l for l in watchers when not l.equals(me)) + watchers.push me if req.body.on and req.body.on isnt 'false' + document.set 'watchers', watchers document.save (err, document) => return @sendDatabaseError(res, err) if err @sendSuccess(res, @formatEntity(req, document)) @@ -233,6 +235,9 @@ module.exports = class Handler return @sendBadInputError(res, err.errors) if err?.valid is false return @sendDatabaseError(res, err) if err @sendSuccess(res, @formatEntity(req, document)) + @onPostSuccess(req, document) + + onPostSuccess: (req, doc) -> ### TODO: think about pulling some common stuff out of postFirstVersion/postNewVersion @@ -248,7 +253,6 @@ module.exports = class Handler document.set('original', document._id) document.set('creator', req.user._id) @saveChangesToDocument req, document, (err) => - console.log 'saved new version', document.toObject() return @sendBadInputError(res, err.errors) if err?.valid is false return @sendDatabaseError(res, err) if err @sendSuccess(res, @formatEntity(req, document)) @@ -291,6 +295,7 @@ module.exports = class Handler newDocument.save (err) => return @sendDatabaseError(res, err) if err @sendSuccess(res, @formatEntity(req, newDocument)) + @notifyWatchersOfChange(req.user, newDocument, req.body.editPath) if @modelClass.schema.is_patchable if major? parentDocument.makeNewMinorVersion(updatedObject, major, done) @@ -298,8 +303,31 @@ module.exports = class Handler else parentDocument.makeNewMajorVersion(updatedObject, done) + notifyWatchersOfChange: (editor, changedDocument, editPath) -> + watchers = changedDocument.get('watchers') or [] + watchers = (w for w in watchers when not w.equals(editor.get('_id'))) + return unless watchers.length + User.find({_id:{$in:watchers}}).select({email:1, name:1}).exec (err, watchers) => + for watcher in watchers + @notifyWatcherOfChange editor, watcher, changedDocument, editPath + + notifyWatcherOfChange: (editor, watcher, changedDocument, editPath) -> + context = + email_id: sendwithus.templates.change_made_notify_watcher + recipient: + address: watcher.get('email') + name: watcher.get('name') + email_data: + doc_name: changedDocument.get('name') or '???' + submitter_name: editor.get('name') or '???' + doc_link: if editPath then "http://codecombat.com#{editPath}" else null + commit_message: changedDocument.get('commitMessage') + sendwithus.api.send context, (err, result) -> + makeNewInstance: (req) -> - new @modelClass({}) + model = new @modelClass({}) + model.set 'watchers', [req.user.get('_id')] if @modelClass.schema.is_patchable + model validateDocumentInput: (input) -> tv4 = require('tv4').tv4 diff --git a/server/patches/Patch.coffee b/server/patches/Patch.coffee index df621f2a4..3e12638cf 100644 --- a/server/patches/Patch.coffee +++ b/server/patches/Patch.coffee @@ -39,8 +39,10 @@ PatchSchema.pre 'save', (next) -> target.original = targetID patches = document.get('patches') or [] + patches = _.clone patches patches.push @_id - document.set 'patches', patches + document.set 'patches', patches, {strict: false} + @targetLoaded = document document.save (err) -> next(err) module.exports = mongoose.model('patch', PatchSchema) diff --git a/server/patches/patch_handler.coffee b/server/patches/patch_handler.coffee index 12a68ed9a..4e134d73d 100644 --- a/server/patches/patch_handler.coffee +++ b/server/patches/patch_handler.coffee @@ -1,8 +1,11 @@ Patch = require('./Patch') +User = require '../users/User' Handler = require('../commons/Handler') schema = require '../../app/schemas/models/patch' {handlers} = require '../commons/mapping' mongoose = require('mongoose') +log = require 'winston' +sendwithus = require '../sendwithus' PatchHandler = class PatchHandler extends Handler modelClass: Patch @@ -50,6 +53,29 @@ PatchHandler = class PatchHandler extends Handler patch.update {$set:{status:newStatus}}, {}, -> target.update {$pull:{patches:patch.get('_id')}}, {}, -> @sendSuccess(res, null) + + onPostSuccess: (req, doc) -> + log.error "Error sending patch created: could not find the loaded target on the patch object." unless doc.targetLoaded + return unless doc.targetLoaded + watchers = doc.targetLoaded.get('watchers') or [] + watchers = (w for w in watchers when not w.equals(editor.get('_id'))) + return unless watchers?.length + User.find({_id:{$in:watchers}}).select({email:1, name:1}).exec (err, watchers) => + for watcher in watchers + @sendPatchCreatedEmail req.user, watcher, doc, doc.targetLoaded, req.body.editPath + sendPatchCreatedEmail: (patchCreator, watcher, patch, target, editPath) -> +# return if watcher._id is patchCreator._id + context = + email_id: sendwithus.templates.patch_created + recipient: + address: watcher.get('email') + name: watcher.get('name') + email_data: + doc_name: target.get('name') or '???' + submitter_name: patchCreator.get('name') or '???' + doc_link: "http://codecombat.com#{editPath}" + commit_message: patch.get('commitMessage') + sendwithus.api.send context, (err, result) -> module.exports = new PatchHandler() diff --git a/server/sendwithus.coffee b/server/sendwithus.coffee index bda58d896..1f8145eb1 100644 --- a/server/sendwithus.coffee +++ b/server/sendwithus.coffee @@ -1,12 +1,10 @@ config = require '../server_config' sendwithusAPI = require 'sendwithus' swuAPIKey = config.mail.sendwithusAPIKey -queues = require './commons/queue' module.exports.setupRoutes = (app) -> return - debug = not config.isProduction module.exports.api = new sendwithusAPI swuAPIKey, debug if config.unittest @@ -14,3 +12,6 @@ if config.unittest module.exports.templates = welcome_email: 'utnGaBHuSU4Hmsi7qrAypU' ladder_update_email: 'JzaZxf39A4cKMxpPZUfWy4' + patch_created: 'tem_xhxuNosLALsizTNojBjNcL' + change_made_notify_watcher: 'tem_7KVkfmv9SZETb25dtHbUtG' + one_time_recruiting_email: 'tem_mdFMgtcczHKYu94Jmq68j8' diff --git a/server/users/user_handler.coffee b/server/users/user_handler.coffee index 0c128e31a..0073bf5ae 100644 --- a/server/users/user_handler.coffee +++ b/server/users/user_handler.coffee @@ -14,7 +14,7 @@ LevelSessionHandler = require '../levels/sessions/level_session_handler' serverProperties = ['passwordHash', 'emailLower', 'nameLower', 'passwordReset'] privateProperties = [ 'permissions', 'email', 'firstName', 'lastName', 'gender', 'facebookID', - 'gplusID', 'music', 'volume', 'aceConfig' + 'gplusID', 'music', 'volume', 'aceConfig', 'employerAt' ] candidateProperties = [ 'jobProfile', 'jobProfileApproved', 'jobProfileNotes' @@ -47,7 +47,7 @@ UserHandler = class UserHandler extends Handler delete obj[prop] for prop in serverProperties includePrivates = req.user and (req.user.isAdmin() or req.user._id.equals(document._id)) delete obj[prop] for prop in privateProperties unless includePrivates - includeCandidate = includePrivates or (obj.jobProfileApproved and req.user and ('employer' in (req.user.permissions ? []))) + includeCandidate = includePrivates or (obj.jobProfileApproved and req.user and ('employer' in (req.user.get('permissions') ? [])) and @employerCanViewCandidate req.user, obj) delete obj[prop] for prop in candidateProperties unless includeCandidate return obj @@ -155,8 +155,24 @@ UserHandler = class UserHandler extends Handler res.end() getSimulatorLeaderboard: (req, res) -> + queryParameters = @getSimulatorLeaderboardQueryParameters(req) + leaderboardQuery = User.find(queryParameters.query).select("name simulatedBy simulatedFor").sort({"simulatedBy":queryParameters.sortOrder}).limit(queryParameters.limit) + leaderboardQuery.exec (err, otherUsers) -> + otherUsers = _.reject otherUsers, _id: req.user._id if req.query.scoreOffset isnt -1 + otherUsers ?= [] + res.send(otherUsers) + res.end() + + getMySimulatorLeaderboardRank: (req, res) -> + req.query.order = 1 + queryParameters = @getSimulatorLeaderboardQueryParameters(req) + User.count queryParameters.query, (err, count) => + return @sendDatabaseError(res, err) if err + res.send JSON.stringify(count + 1) + + getSimulatorLeaderboardQueryParameters: (req) -> @validateSimulateLeaderboardRequestParameters(req) - + query = {} sortOrder = -1 limit = if req.query.limit > 30 then 30 else req.query.limit @@ -167,14 +183,7 @@ UserHandler = class UserHandler extends Handler sortOrder = 1 if req.query.order is 1 else query.simulatedBy = {"$exists": true} - - leaderboardQuery = User.find(query).select("name simulatedBy simulatedFor").sort({"simulatedBy":sortOrder}).limit(limit) - leaderboardQuery.exec (err, otherUsers) -> - otherUsers = _.reject otherUsers, _id: req.user._id if req.query.scoreOffset isnt -1 - otherUsers ?= [] - res.send(otherUsers) - res.end() - + {query: query, sortOrder: sortOrder, limit: limit} validateSimulateLeaderboardRequestParameters: (req) -> req.query.order = parseInt(req.query.order) ? -1 @@ -202,6 +211,7 @@ UserHandler = class UserHandler extends Handler return @getLevelSessions(req, res, args[0]) if args[1] is 'level.sessions' return @getCandidates(req, res) if args[1] is 'candidates' return @getSimulatorLeaderboard(req, res, args[0]) if args[1] is 'simulatorLeaderboard' + return @getMySimulatorLeaderboardRank(req, res, args[0]) if args[1] is 'simulator_leaderboard_rank' return @sendNotFoundError(res) super(arguments...) @@ -248,28 +258,38 @@ UserHandler = class UserHandler extends Handler getCandidates: (req, res) -> authorized = req.user.isAdmin() or ('employer' in req.user.get('permissions')) since = (new Date((new Date()) - 2 * 30.4 * 86400 * 1000)).toISOString() - #query = {'jobProfileApproved': true, 'jobProfile.active': true, 'jobProfile.updated': {$gt: since}} - query = {'jobProfile.active': true, 'jobProfile.updated': {$gt: since}} # testing + query = {'jobProfile.active': true, 'jobProfile.updated': {$gt: since}} + #query = {'jobProfile.updated': {$gt: since}} query.jobProfileApproved = true unless req.user.isAdmin() selection = 'jobProfile' selection += ' email' if authorized selection += ' jobProfileApproved' if req.user.isAdmin() User.find(query).select(selection).exec (err, documents) => return @sendDatabaseError(res, err) if err - candidates = (@formatCandidate(authorized, doc) for doc in documents) + candidates = (candidate for candidate in documents when @employerCanViewCandidate req.user, candidate.toObject()) + candidates = (@formatCandidate(authorized, candidate) for candidate in candidates) @sendSuccess(res, candidates) formatCandidate: (authorized, document) -> fields = if authorized then ['jobProfile', 'jobProfileApproved', 'photoURL', '_id'] else ['jobProfile'] obj = _.pick document.toObject(), fields obj.photoURL ||= obj.jobProfile.photoURL if authorized - obj.photoURL ||= @buildGravatarURL document if authorized subfields = ['country', 'city', 'lookingFor', 'jobTitle', 'skills', 'experience', 'updated'] if authorized subfields = subfields.concat ['name'] obj.jobProfile = _.pick obj.jobProfile, subfields obj + employerCanViewCandidate: (employer, candidate) -> + return true if employer.isAdmin() + for job in candidate.jobProfile?.work ? [] + # TODO: be smarter about different ways to write same company names to ensure privacy. + # We'll have to manually pay attention to how we set employer names for now. + if job.employer?.toLowerCase() is employer.get('employerAt')?.toLowerCase() + log.info "#{employer.get('name')} at #{employer.get('employerAt')} can't see #{candidate.jobProfile.name} because s/he worked there." + return false if job.employer?.toLowerCase() is employer.get('employerAt')?.toLowerCase() + true + buildGravatarURL: (user, size, fallback) -> emailHash = @buildEmailHash user fallback ?= "http://codecombat.com/file/db/thang.type/52a00d55cf1818f2be00000b/portrait.png" diff --git a/server_setup.coffee b/server_setup.coffee index d8dcd1c03..6aeed9ee6 100644 --- a/server_setup.coffee +++ b/server_setup.coffee @@ -3,7 +3,8 @@ path = require 'path' authentication = require 'passport' useragent = require 'express-useragent' fs = require 'graceful-fs' -log = require('winston') +log = require 'winston' +compressible = require 'compressible' database = require './server/commons/database' baseRoute = require './server/routes/base' @@ -11,17 +12,7 @@ user = require './server/users/user_handler' logging = require './server/commons/logging' config = require './server_config' auth = require './server/routes/auth' -UserHandler = require('./server/users/user_handler') - -###Middleware setup functions implementation### -# 2014-03-03: Try not using this and see if it's still a problem -#setupRequestTimeoutMiddleware = (app) -> -# app.use (req, res, next) -> -# req.setTimeout 15000, -> -# console.log 'timed out!' -# req.abort() -# self.emit('pass',message) -# next() +UserHandler = require './server/users/user_handler' productionLogging = (tokens, req, res) -> status = res.statusCode @@ -31,15 +22,17 @@ productionLogging = (tokens, req, res) -> else if status >= 300 then color = 36 elapsed = (new Date()) - req._startTime elapsedColor = if elapsed < 500 then 90 else 31 - if (status isnt 200 and status isnt 304) or elapsed > 500 + if (status isnt 200 and status isnt 304 and status isnt 302) or elapsed > 500 return "\x1b[90m#{req.method} #{req.originalUrl} \x1b[#{color}m#{res.statusCode} \x1b[#{elapsedColor}m#{elapsed}ms\x1b[0m" null setupExpressMiddleware = (app) -> - #setupRequestTimeoutMiddleware app if config.isProduction express.logger.format('prod', productionLogging) app.use(express.logger('prod')) + app.use express.compress filter: (req, res) -> + return false if req.headers.host is 'codecombat.com' # Cloudflare will gzip it for us on codecombat.com + compressible res.getHeader('Content-Type') else app.use(express.logger('dev')) app.use(express.static(path.join(__dirname, 'public'))) @@ -50,7 +43,6 @@ setupExpressMiddleware = (app) -> app.use(express.bodyParser()) app.use(express.methodOverride()) app.use(express.cookieSession({secret:'defenestrate'})) - #app.use(express.compress()) if config.isProduction # just let Cloudflare do it setupPassportMiddleware = (app) -> app.use(authentication.initialize()) diff --git a/test/server/common.coffee b/test/server/common.coffee index e68c27b72..80aa6e47e 100644 --- a/test/server/common.coffee +++ b/test/server/common.coffee @@ -64,13 +64,13 @@ GLOBAL.unittest = {} unittest.users = unittest.users or {} unittest.getNormalJoe = (done, force) -> - unittest.getUser('normal@jo.com', 'food', done, force) + unittest.getUser('Joe', 'normal@jo.com', 'food', done, force) unittest.getOtherSam = (done, force) -> - unittest.getUser('other@sam.com', 'beer', done, force) + unittest.getUser('Sam', 'other@sam.com', 'beer', done, force) unittest.getAdmin = (done, force) -> - unittest.getUser('admin@afc.com', '80yqxpb38j', done, force) + unittest.getUser('Admin', 'admin@afc.com', '80yqxpb38j', done, force) -unittest.getUser = (email, password, done, force) -> +unittest.getUser = (name, email, password, done, force) -> # Creates the user if it doesn't already exist. return done(unittest.users[email]) if unittest.users[email] and not force @@ -81,6 +81,7 @@ unittest.getUser = (email, password, done, force) -> throw err if err User.findOne({email:email}).exec((err, user) -> user.set('permissions', if password is '80yqxpb38j' then [ 'admin' ] else []) + user.set('name', name) user.save (err) -> wrapUpGetUser(email, user, done) ) @@ -88,7 +89,6 @@ unittest.getUser = (email, password, done, force) -> form = req.form() form.append('email', email) form.append('password', password) - wrapUpGetUser = (email, user, done) -> unittest.users[email] = user diff --git a/test/server/functional/patch.spec.coffee b/test/server/functional/patch.spec.coffee index d8694baf0..9d0f4265d 100644 --- a/test/server/functional/patch.spec.coffee +++ b/test/server/functional/patch.spec.coffee @@ -16,13 +16,14 @@ describe '/db/patch', -> patch = commitMessage: 'Accept this patch!' delta: {name:['test']} + editPath: '/who/knows/yes' target: id:null collection: 'article' it 'creates an Article to patch', (done) -> loginAdmin -> - request.post {uri:articleURL, json:patch}, (err, res, body) -> + request.post {uri:articleURL, json:article}, (err, res, body) -> articles[0] = body patch.target.id = articles[0]._id done() @@ -51,29 +52,29 @@ describe '/db/patch', -> body = JSON.parse(body) expect(res.statusCode).toBe(200) expect(body.length).toBe(1) - done() + done() - it 'allows you to set yourself as listening', (done) -> - listeningURL = getURL("/db/article/#{articles[0]._id}/listen") - request.put {uri: listeningURL, json: {on:true}}, (err, res, body) -> - expect(body.listeners[0]).toBeDefined() + it 'allows you to set yourself as watching', (done) -> + watchingURL = getURL("/db/article/#{articles[0]._id}/watch") + request.put {uri: watchingURL, json: {on:true}}, (err, res, body) -> + expect(body.watchers[1]).toBeDefined() done() - it 'added the listener to the target document', (done) -> + it 'added the watcher to the target document', (done) -> Article.findOne({}).exec (err, article) -> - expect(article.toObject().listeners[0]).toBeDefined() + expect(article.toObject().watchers[1]).toBeDefined() done() - it 'does not add duplicate listeners', (done) -> - listeningURL = getURL("/db/article/#{articles[0]._id}/listen") - request.put {uri: listeningURL, json: {on:true}}, (err, res, body) -> - expect(body.listeners.length).toBe(1) + it 'does not add duplicate watchers', (done) -> + watchingURL = getURL("/db/article/#{articles[0]._id}/watch") + request.put {uri: watchingURL, json: {on:true}}, (err, res, body) -> + expect(body.watchers.length).toBe(2) done() it 'allows removing yourself', (done) -> - listeningURL = getURL("/db/article/#{articles[0]._id}/listen") - request.put {uri: listeningURL, json: {on:false}}, (err, res, body) -> - expect(body.listeners.length).toBe(0) + watchingURL = getURL("/db/article/#{articles[0]._id}/watch") + request.put {uri: watchingURL, json: {on:false}}, (err, res, body) -> + expect(body.watchers.length).toBe(1) done() it 'allows the submitter to withdraw the pull request', (done) -> diff --git a/test/server/functional/user.spec.coffee b/test/server/functional/user.spec.coffee index 29e1360a9..0ee2ff364 100644 --- a/test/server/functional/user.spec.coffee +++ b/test/server/functional/user.spec.coffee @@ -112,7 +112,7 @@ ghlfarghlarghlfarghlarghlfarghlarghlfarghlarghlfarghlarghlfarghlarghlfarghlarghl unittest.getNormalJoe (joe) -> req = request.put getURL(urlUser), (err, res) -> expect(res.statusCode).toBe(200) - unittest.getUser('New@email.com', 'null', (joe) -> + unittest.getUser('Wilhelm', 'New@email.com', 'null', (joe) -> expect(joe.get('name')).toBe('Wilhelm') expect(joe.get('emailLower')).toBe('new@email.com') expect(joe.get('email')).toBe('New@email.com')