diff --git a/app/assets/images/pages/play/modal/buy-gems-background.png b/app/assets/images/pages/play/modal/buy-gems-background.png index 563124aeb..fadecf6dc 100644 Binary files a/app/assets/images/pages/play/modal/buy-gems-background.png and b/app/assets/images/pages/play/modal/buy-gems-background.png differ diff --git a/app/lib/surface/Label.coffee b/app/lib/surface/Label.coffee index b745fb63c..1aeed7d1c 100644 --- a/app/lib/surface/Label.coffee +++ b/app/lib/surface/Label.coffee @@ -47,7 +47,7 @@ module.exports = class Label extends CocoClass @layer.updateLayerOrder() update: -> - return unless @text + return unless @text and @sprite.sprite offset = @sprite.getOffset? (if @style in ['dialogue', 'say'] then 'mouth' else 'aboveHead') offset ?= x: 0, y: 0 # temp (if not Lank) rotation = @sprite.getRotation() diff --git a/app/lib/world/names.coffee b/app/lib/world/names.coffee index 0f50043c0..e1217b17a 100644 --- a/app/lib/world/names.coffee +++ b/app/lib/world/names.coffee @@ -148,6 +148,7 @@ module.exports.thangNames = thangNames = 'Wayne' 'William' 'Willie' + 'Zachary' ] 'Soldier F': [ 'Alana' @@ -220,6 +221,7 @@ module.exports.thangNames = thangNames = 'Kay' 'Kelly' 'Kimberly' + 'Kira' 'Lana' 'Laura' 'Lillian' @@ -231,10 +233,12 @@ module.exports.thangNames = thangNames = 'Lukaz' 'Margaret' 'Maria' + 'Mariah' 'Marie' 'Marilyn' 'Martha' 'Mary' + 'Medusa' 'Melissa' 'Michelle' 'Mildred' @@ -365,6 +369,7 @@ module.exports.thangNames = thangNames = 'Logos' 'Lycan' 'Mars' + 'Odysseos' 'Oliver' 'Quinn' 'Robin' @@ -428,6 +433,7 @@ module.exports.thangNames = thangNames = ] 'Ogre M': [ 'Axe Ox' + 'Belch' 'Dronck' 'Gorlog' 'Grumus' @@ -441,6 +447,7 @@ module.exports.thangNames = thangNames = 'Polifemo' 'Saltporker' 'Skrungt' + 'Steve' 'Stinker' 'Tarlok' 'Trogdor' @@ -468,6 +475,7 @@ module.exports.thangNames = thangNames = 'Grul\'thock' 'Grumoll' 'Haggar' + 'Heizenburg' 'Ironjaw' 'Muul' 'Ork\'han' @@ -511,6 +519,7 @@ module.exports.thangNames = thangNames = 'Tuzang' 'Tuzell' 'Ugoki' + 'Uld\'Mak' 'Varreth' 'Yamizeb' 'Yerong' @@ -568,6 +577,7 @@ module.exports.thangNames = thangNames = 'Satish' ] 'Equestrian': [ + 'Beauty' 'Mirial' 'Neely' 'Reynaldo' @@ -579,6 +589,7 @@ module.exports.thangNames = thangNames = 'Alphonse' 'Altair' 'Arthur' + 'Bruce' 'Drake' 'Duran' 'Edward' @@ -590,6 +601,7 @@ module.exports.thangNames = thangNames = 'Neville' 'Shug' 'Tharin' + 'Wain' ] 'Captain': [ 'Anya' @@ -608,6 +620,7 @@ module.exports.thangNames = thangNames = 'Nicks' 'Philips' 'Sarre' + 'Sun Tzu' ] 'Ninja': [ 'Amara' @@ -615,14 +628,19 @@ module.exports.thangNames = thangNames = 'Naruto' 'Sakura' 'Sasuke' + 'Shigeru' ] 'Sorcerer': [ 'Beazer' 'Gandalf' 'Pender' + 'Jezebel' ] 'Samurai': [ 'Hattori' + 'Ieyasu' + 'Izotokogawa' + 'Nobunaga' ] 'Sand Yak': [ 'Arngotho' @@ -660,6 +678,9 @@ module.exports.thangNames = thangNames = 'Sacra' 'Scraps' 'Shelly' + 'Shishka-Bob' + 'Shishka-Larry' + 'Shishka-Joe' 'Skeletor' 'Skellington' 'Skulldugger' diff --git a/app/locale/en.coffee b/app/locale/en.coffee index ad57f851e..1332bd8db 100644 --- a/app/locale/en.coffee +++ b/app/locale/en.coffee @@ -94,15 +94,15 @@ campaign_classic_algorithms: "Classic Algorithms" campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." - share_progress_modal: - blurb: "You’re making great progress! Tell someone how much you've learned with CodeCombat." - email_invalid: "Email address invalid." - form_blurb: "Enter their email below and we’ll show them!" - form_label: "Email Address" - placeholder: "email address" - title: "Excellent Work, Apprentice" - tell_friend: "Tell your Friend" - tell_parent: "Tell your Parent" + share_progress_modal: + blurb: "You’re making great progress! Tell someone how much you've learned with CodeCombat." + email_invalid: "Email address invalid." + form_blurb: "Enter their email below and we’ll show them!" + form_label: "Email Address" + placeholder: "email address" + title: "Excellent Work, Apprentice" + tell_friend: "Tell your Friend" + tell_parent: "Tell your Parent" login: sign_up: "Create Account" @@ -335,6 +335,9 @@ tip_source_code: "I want to change the world but they would not give me the source code." tip_javascript_java: "Java is to JavaScript what Car is to Carpet. - Chris Heilmann" tip_move_forward: "Whatever you do, keep moving forward. - Martin Luther King Jr." + tip_google: "Have a problem you can't solve? Google it!" + tip_adding_evil: "Adding a pinch of evil." + tip_miss_lunch: "Anyone who has lost track of time when using a computer knows the propensity to dream, the urge to make dreams come true and the tendency to miss lunch. - Tim Berners-Lee" game_menu: inventory_tab: "Inventory" diff --git a/app/locale/fr.coffee b/app/locale/fr.coffee index aa0d3eb92..d760f9ad9 100644 --- a/app/locale/fr.coffee +++ b/app/locale/fr.coffee @@ -337,7 +337,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t choose_hero_caption: "Choisissez votre héro, langage" save_load_caption: "... et voir l'historique" options_caption: "Configurer les réglages" - guide_caption: "Docs and conseils" + guide_caption: "Docs et conseils" multiplayer_caption: "Jouer avec des amis!" auth_caption: "Sauvegarder votre progression." diff --git a/app/locale/zh-HANT.coffee b/app/locale/zh-HANT.coffee index c2803c969..42dcf7d72 100644 --- a/app/locale/zh-HANT.coffee +++ b/app/locale/zh-HANT.coffee @@ -399,14 +399,14 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese thank_you: "感謝您支持CodeCombat." sorry_to_see_you_go: "捨不得您離開! 請讓我們知道我們如何做得更好." unsubscribe_feedback_placeholder: "O, 我們做錯事了嗎?" -# parent_button: "Ask your parent" -# parent_email_description: "We'll email them so they can buy you a CodeCombat subscription." -# parent_email_input_invalid: "Email address invalid." -# parent_email_input_label: "Parent email address" -# parent_email_input_placeholder: "Enter parent email" -# parent_email_send: "Send Email" -# parent_email_sent: "Email sent!" -# parent_email_title: "What's your parent's email?" + parent_button: "詢問您的父母" + parent_email_description: "我們將寄信向他們說明,所以他們能放心幫您訂閱CodeCombat." + parent_email_input_invalid: "信箱位址無效." + parent_email_input_label: "父母信箱位址" + parent_email_input_placeholder: "輸入Enter父母信箱" + parent_email_send: "寄信" + parent_email_sent: "已寄信!" + parent_email_title: "您父母信箱是?" parents: "致家長" parents_title: "您的孩子將學習編寫程式." parents_blurb1: "使用CodeCombat, 您的孩子學習真正的編寫程式. 他們學習從簡單的指令,漸進到更加進階的課題." @@ -520,42 +520,42 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese teachers: title: "CodeCombat致教師的說明" preparation_title: "準備" -# preparation_1: "CodeCombat is free to play for the core level progression and does not require students to sign up. We encourage teachers to" -# preparation_play_campaign: "play through the campaign" -# preparation_2: "to try it out, but the only thing you absolutely need to do to be ready is ensure students have access to a computer." -# preparation_3: "It is not necessary for teachers to be comfortable with computer science concepts for students to have fun learning with CodeCombat." - violent_title: "這暴戾嗎?" -# violent_1: "We get this from teachers a lot due to our name. Although CodeCombat does contain cartoon violence, there is nothing graphic in either the visuals or language." -# violent_2: "If you are comfortable having your students play Angry Birds, you will be comfortable with CodeCombat." + preparation_1: "學生可以免費玩CodeCombat的核心關卡並且不需要登入. 我們鼓勵教師透過" + preparation_play_campaign: "玩過每道關卡" + preparation_2: "去體驗它所傳達的, 你唯一需要準備的事情是確保學生可以接觸可上網的電腦." + preparation_3: "教師是不需要具備電腦科學的知識去讓學生有樂趣的經由CodeCombat學習." + violent_title: "這暴力嗎?" + violent_1: "因為我們的命名導致我們受到許多質疑. 儘管CodeCombat確實包含卡通暴力, 但我們在視覺和語言上是絕不包含的." + violent_2: "如果您覺得Angry Birds(憤怒鳥)適合學生玩, 你將覺得CodeCombat也是適合的." for_girls_title: "這適合女生嗎?" -# for_girls_1: "There are three game modes in CodeCombat: building, puzzles, and combat. We have intentionally designed each to appeal to both boys and girls and think that the building and puzzle levels especially differentiate the game from violent triple A titles that repel female players." + for_girls_1: "在CodeCombat裡存在三種遊戲模式: 建造, 謎題和戰鬥. 我們已刻意調整設計去迎合男性和女性並且特別思考讓'建造'和'謎題'的關卡不被女性玩家厭惡." what_cover_title: "我們涵蓋哪些?" -# what_cover_1: "There are 20 levels in the Hour of Code tutorial that teach and reinforce 6 specific computer science concepts:" -# what_cover_notation_1: "Formal notation" -# what_cover_notation_2: "- builds an understanding of the importance of syntax in programming." + what_cover_1: "在Hour of Code的教學裡已放置20道關卡教導並強化6種特定的電腦科學概念:" + what_cover_notation_1: "正式的表示法" + what_cover_notation_2: "- 建立重要的'編程文法'理解." what_cover_methods_1: "呼叫方法" -# what_cover_methods_2: "- familiarizes students with the syntax of object-oriented method calls." + what_cover_methods_2: "- 讓學生熟悉如何呼叫物件導向的文法." what_cover_parameters_1: "參數" -# what_cover_parameters_2: "- trains how to pass parameters to functions." -# what_cover_strings_1: "Strings" -# what_cover_strings_2: "- teaches students about string notation and passing strings as parameters." + what_cover_parameters_2: "- 訓練學生如何傳遞參數到函數中." + what_cover_strings_1: "字串" + what_cover_strings_2: "- teaches students about string notation and passing strings as parameters." what_cover_loops_1: "回圈" -# what_cover_loops_2: "- develops the abstraction of designing short programs with loops." + what_cover_loops_2: "- 發展如何運用回圈設計簡短程式的抽象概念d." what_cover_variables_1: "變數" -# what_cover_variables_2: "- adds the skill of referencing values that change over time." -# what_cover_2: "Students may continue past level 20, depending on their speed and interest, to learn two additional concepts in later levels:" + what_cover_variables_2: "- 增加如何讓變動的值可被參考的技巧." + what_cover_2: "根據學生的速度和興趣,他們也許持續地通過20道關卡並且在接下去的關卡中將學習額外的兩種概念:" what_cover_logic_1: "條件邏輯" -# what_cover_logic_2: "- when and how to use if/else to control in-game outcomes." -# what_cover_input_1: "Handling player input" -# what_cover_input_2: "- responding to input events to create a user interface." -# sys_requirements_title: "System Requirements" -# sys_requirements_1: "Because CodeCombat is a game, it is more intensive for computers to run smoothly than video or written tutorials. We have optimized it to run quickly on all modern browsers and on older machines so that everyone can play. That said, here are our suggestions for getting the most out of your Hour of Code experience:" -# sys_requirements_2: "Use newer versions of Chrome or Firefox." -# sys_requirements_3: "Although CodeCombat will work on browsers as old as IE9, the performance is not as good. Chrome is best." - sys_requirements_4: "使用更新的電腦." -# sys_requirements_5: "Older computers, Chromebooks, and netbooks tend to have very few system resources, which makes for a less enjoyable experience. At least 2GB of RAM is required." -# sys_requirements_6: "Allow players to wear headphones/earbuds to hear the audio." -# sys_requirements_7: "We help players learn through voiceover and sound effects, which will make classrooms noisy and distracting." + what_cover_logic_2: "- 何時以及如何使用if/else來控制遊戲中的結果." + what_cover_input_1: "處理玩家的輸入" + what_cover_input_2: "- 回應輸入事件來創造一個使用者界面." + sys_requirements_title: "系統要求" + sys_requirements_1: "因為CodeCombat是遊戲, 相比播放影片它讓電腦花費更多資源去順暢的執行. 為了讓所有人都可以接觸,我們已經讓它在現在的瀏覽器和老舊的電腦上執行最佳化. 以下是我們為了讓您順暢體驗Hour of Code所給的系統建議:" + sys_requirements_2: "使用較新的Chrome or Firefox版本." + sys_requirements_3: "儘管CodeCombat在老舊的IE9上也可執行, 但它的效果不會是順暢的. Chrome則會是最好的." + sys_requirements_4: "使用較新的電腦." + sys_requirements_5: "因為老舊電腦, Chromebooks, 和小筆電都有較少的電腦資源, 這讓玩家不是盡興的擁有遊戲體驗. 最少需要2GB of RAM." + sys_requirements_6: "讓所有玩家都可擁有頭罩型耳機/塞耳式耳機來體驗遊戲的配樂." + sys_requirements_7: "我們借由聲音和音效來幫助玩家學習, 所以這會使教室有點吵." versions: save_version_title: "保存新版本" @@ -660,25 +660,25 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese social_hipchat: "通過公共的HipChat與我們交流" contribute_to_the_project: "貢獻這專案" -# classes: -# archmage_title: "Archmage" -# archmage_title_description: "(Coder)" -# archmage_summary: "If you are a developer interested in coding educational games, become an archmage to help us build CodeCombat!" -# artisan_title: "Artisan" -# artisan_title_description: "(Level Builder)" -# artisan_summary: "Build and share levels for you and your friends to play. Become an Artisan to learn the art of teaching others to program." -# adventurer_title: "Adventurer" -# adventurer_title_description: "(Level Playtester)" -# adventurer_summary: "Get our new levels (even our subscriber content) for free one week early and help us work out bugs before our public release." -# scribe_title: "Scribe" -# scribe_title_description: "(Article Editor)" -# scribe_summary: "Good code needs good documentation. Write, edit, and improve the docs read by millions of players across the globe." -# diplomat_title: "Diplomat" -# diplomat_title_description: "(Translator)" -# diplomat_summary: "CodeCombat is localized in 45+ languages by our Diplomats. Help us out and contribute translations." -# ambassador_title: "Ambassador" -# ambassador_title_description: "(Support)" -# ambassador_summary: "Tame our forum users and provide direction for those with questions. Our ambassadors represent CodeCombat to the world." + classes: + archmage_title: "大法師" + archmage_title_description: "(Coder)" + archmage_summary: "如果你是個在coding教育遊戲有興趣的開發者, 成為大法師來幫助我們建立CodeCombat!" + artisan_title: "工匠" + artisan_title_description: "(Level Builder)" + artisan_summary: "建造遊戲關卡並且分享給您的朋友們. 成為工匠來幫助其他人學習編程." + adventurer_title: "冒險家" + adventurer_title_description: "(Level Playtester)" + adventurer_summary: "提前一周免費取得我們新的關卡(甚至是訂閱的內容)並且提前在釋出前幫助我們找出錯誤." + scribe_title: "文書" + scribe_title_description: "(Article Editor)" + scribe_summary: "好的程式需要好的文件. 來自全世界數百萬的玩家一起編寫, 編輯和提升文件的可讀性." + diplomat_title: "外交員" + diplomat_title_description: "(Translator)" + diplomat_summary: "借由我們的外交員,CodeCombat已翻譯到45種以上的語言. 幫助我們並且貢獻翻譯." + ambassador_title: "使節" + ambassador_title_description: "(Support)" + ambassador_summary: "安撫我們論壇的用戶並且提供發問者適當的方向. 我們的使節代表CodeCombat面對全世界." editor: main_title: "CodeCombat編輯器" @@ -712,51 +712,51 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese level_tab_components: "組件" level_tab_systems: "系統" level_tab_docs: "文件" -# level_tab_thangs_title: "Current Thangs" -# level_tab_thangs_all: "All" -# level_tab_thangs_conditions: "Starting Conditions" -# level_tab_thangs_add: "Add Thangs" -# add_components: "Add Components" -# component_configs: "Component Configurations" -# config_thang: "Double click to configure a thang" -# delete: "Delete" -# duplicate: "Duplicate" -# stop_duplicate: "Stop Duplicate" -# rotate: "Rotate" -# 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" -# new_article_title_login: "Log In to Create a New Article" -# new_thang_title_login: "Log In to Create a New Thang Type" -# new_level_title_login: "Log In to Create a New Level" -# new_achievement_title: "Create a New Achievement" -# new_achievement_title_login: "Log In to Create a New Achievement" -# article_search_title: "Search Articles Here" -# thang_search_title: "Search Thang Types Here" -# level_search_title: "Search Levels Here" -# achievement_search_title: "Search Achievements" -# read_only_warning2: "Note: you can't save any edits here, because you're not logged in." -# no_achievements: "No achievements have been added for this level yet." -# achievement_query_misc: "Key achievement off of miscellanea" -# achievement_query_goals: "Key achievement off of level goals" -# level_completion: "Level Completion" -# pop_i18n: "Populate I18N" -# tasks: "Tasks" + level_tab_thangs_title: "目前物體" + level_tab_thangs_all: "所有的" + level_tab_thangs_conditions: "啟動條件" + level_tab_thangs_add: "增加物體" + add_components: "增加組件" + component_configs: "組件組態" + config_thang: "雙擊來構建物體" + delete: "刪除" + duplicate: "複製" + stop_duplicate: "停止複製" + rotate: "旋轉" + level_settings_title: "設定" + level_component_tab_title: "現在組件" + level_component_btn_new: "建立新組件" + level_systems_tab_title: "目前系統" + level_systems_btn_new: "建立新系統" + level_systems_btn_add: "增加系統" + level_components_title: "回到所有物體" + level_components_type: "類型" + level_component_edit_title: "編輯組件" + level_component_config_schema: "配置模式" + level_component_settings: "設定" + level_system_edit_title: "編輯系統" + create_system_title: "Create New System" + new_component_title: "建立新系統" + new_component_field_system: "系統" + new_article_title: "建立新文件" + new_thang_title: "建立新物體類型" + new_level_title: "建立新關卡" + new_article_title_login: "登錄以建立新文件" + new_thang_title_login: "登錄以建立新物體類型" + new_level_title_login: "登錄以建立新關卡" + new_achievement_title: "建立新成就" + new_achievement_title_login: "登錄以建立新成就" + article_search_title: "在這搜尋文件" + thang_search_title: "在這搜尋物體類型" + level_search_title: "在這搜尋關卡" + achievement_search_title: "搜尋成就" + read_only_warning2: "注意: 你不能在這儲存任何編輯, 因為你尚未登入." + no_achievements: "尚未有任何成就加入到這關卡中." + achievement_query_misc: "關閉成就欄的雜項" + achievement_query_goals: "關閉成就欄的關卡目標" + level_completion: "關卡完成" + pop_i18n: "填寫 I18N" + tasks: "任務" article: edit_btn_preview: "預覽" diff --git a/app/styles/common/site-chrome.sass b/app/styles/common/site-chrome.sass index d0b1b2380..0a707651a 100644 --- a/app/styles/common/site-chrome.sass +++ b/app/styles/common/site-chrome.sass @@ -117,9 +117,14 @@ color: black border-bottom: #32281e 1px solid - img + .img-circle + background-position: center + background-size: cover border: #e3be7a 8px solid + width: 98px height: 98px // Includes the border + display: inline-block + vertical-align: middle &:hover box-shadow: 0 0 20px #e3be7a diff --git a/app/styles/play/modal/buy-gems-modal.sass b/app/styles/play/modal/buy-gems-modal.sass index 8552cc411..e0770f2ad 100644 --- a/app/styles/play/modal/buy-gems-modal.sass +++ b/app/styles/play/modal/buy-gems-modal.sass @@ -1,8 +1,23 @@ +@import "app/styles/mixins" + #buy-gems-modal + //- Header + + h1 + position: absolute + left: 164px + top: -70px + margin: 0 + width: 450px + text-align: center + color: rgb(254,188,68) + font-size: 38px + text-shadow: black 4px 4px 0, black -4px -4px 0, black 4px -4px 0, black -4px 4px 0, black 4px 0px 0, black 0px -4px 0, black -4px 0px 0, black 0px 4px 0 + //- Clear modal defaults .modal-dialog - margin: 100px auto 0 auto + margin: 150px auto 0 auto padding: 0 width: 820px height: 460px @@ -14,6 +29,24 @@ top: -157px left: -2px + //- Close modal button + + #close-modal + position: absolute + left: 612px + top: -80px + width: 60px + height: 60px + color: white + text-align: center + font-size: 30px + padding-top: 15px + cursor: pointer + @include rotate(-3deg) + + &:hover + color: yellow + //- Products #products @@ -54,3 +87,13 @@ width: 80% top: 20px border: 5px solid gray + + #or-subscribe + position: absolute + right: 30px + top: 420px + font-size: 16px + color: #eee + + button + min-width: 182px diff --git a/app/templates/base.jade b/app/templates/base.jade index bda7a21dd..181f2b75e 100644 --- a/app/templates/base.jade +++ b/app/templates/base.jade @@ -26,7 +26,7 @@ block header li.user-dropdown-header span.user-level= me.level() a(href="/user/#{me.getSlugOrID()}") - img.img-circle(src="#{me.getPhotoURL()}" alt="") + div.img-circle(style="background-image: url(#{me.getPhotoURL()})") h3=me.displayName() li a(href="/user/#{me.getSlugOrID()}" data-i18n="nav.profile") diff --git a/app/templates/play/campaign-view.jade b/app/templates/play/campaign-view.jade index ee679fabc..dd1688bef 100644 --- a/app/templates/play/campaign-view.jade +++ b/app/templates/play/campaign-view.jade @@ -109,7 +109,7 @@ button.btn.btn-lg.btn-inverse#volume-button(data-i18n="[title]play.adjust_volume .glyphicon.glyphicon-volume-up if campaign - .btn.btn-lg.btn-inverse#back-button(data-i18n="[title]resources.campaigns", title="Campaigns") + button.btn.btn-lg.btn-inverse#back-button(data-i18n="[title]resources.campaigns", title="Campaigns") .glyphicon.glyphicon-globe if campaign && campaign.loaded diff --git a/app/templates/play/level/level_loading.jade b/app/templates/play/level/level_loading.jade index 590795119..4ebfb8b6d 100644 --- a/app/templates/play/level/level_loading.jade +++ b/app/templates/play/level/level_loading.jade @@ -37,6 +37,7 @@ strong.tip(data-i18n='play_level.tip_forums') Head over to the forums and tell us what you think! strong.tip(data-i18n='play_level.tip_impossible') It always seems impossible until it's done. - Nelson Mandela strong.tip(data-i18n='play_level.tip_move_forward') Whatever you do, keep moving forward. - Martin Luther King Jr. + strong.tip(data-i18n='play_level.tip_google') Have a problem you can't solve? Google it! strong.tip.rare(data-i18n='play_level.tip_baby_coders') In the future, even babies will be Archmages. strong.tip.rare(data-i18n='play_level.tip_hardware_problem') Q: How many programmers does it take to change a light bulb? A: None, it's a hardware problem. @@ -68,3 +69,5 @@ strong.tip.rare(data-i18n='play_level.tip_reusable_software') Before software can be reusable it first has to be usable. strong.tip.rare(data-i18n='play_level.tip_optimization_operator') Every language has an optimization operator. In most languages that operator is ‘//’ strong.tip.rare(data-i18n='play_level.tip_lines_of_code') Measuring programming progress by lines of code is like measuring aircraft building progress by weight. — Bill Gates + strong.tip.rare(data-i18n='play_level.tip_adding_evil') Adding a pinch of evil. + strong.tip.rare(data-i18n='play_level.tip_miss_lunch') Anyone who has lost track of time when using a computer knows the propensity to dream, the urge to make dreams come true and the tendency to miss lunch. - Tim Berners-Lee diff --git a/app/templates/play/modal/buy-gems-modal.jade b/app/templates/play/modal/buy-gems-modal.jade index 701ecc0aa..f8e0bacf0 100644 --- a/app/templates/play/modal/buy-gems-modal.jade +++ b/app/templates/play/modal/buy-gems-modal.jade @@ -1,5 +1,6 @@ .modal-dialog .modal-content + if state === 'purchasing' .alert.alert-info(data-i18n="buy_gems.purchasing") @@ -8,7 +9,8 @@ else img(src="/images/pages/play/modal/buy-gems-background.png")#buy-gems-background - + h1(data-i18n="play.buy_gems") + #products for product in products .product @@ -35,3 +37,11 @@ span(data-i18n="buy_gems.recovered") button.close(type="button" data-dismiss="alert") span(aria-hidden="true") × + + div#close-modal + span.glyphicon.glyphicon-remove + + #or-subscribe + span Or 3500 gems/mo if you... + br + button.start-subscription-button.btn.btn-lg.btn-illustrated.btn-success(data-i18n="subscribe.subscribe") Subscribe diff --git a/app/views/account/AccountSettingsView.coffee b/app/views/account/AccountSettingsView.coffee index 4d0a8a1cb..b24dcac2d 100644 --- a/app/views/account/AccountSettingsView.coffee +++ b/app/views/account/AccountSettingsView.coffee @@ -69,7 +69,7 @@ module.exports = class AccountSettingsView extends CocoView photoContainer.addClass('saving') onSaved = (uploadingPath) => @$el.find('#photoURL').val(uploadingPath) - @onInputChanged() # cause for some reason editing the value doesn't trigger the jquery event + @$el.find('#photoURL').trigger('change') # cause for some reason editing the value doesn't trigger the jquery event me.set('photoURL', uploadingPath) photoContainer.removeClass('saving').attr('src', me.getPhotoURL(photoContainer.width())) filepicker.pick {mimetypes: 'image/*'}, @onImageChosen(onSaving, onSaved) diff --git a/app/views/play/CampaignView.coffee b/app/views/play/CampaignView.coffee index 9f1c9d7e8..2ece8bdbc 100644 --- a/app/views/play/CampaignView.coffee +++ b/app/views/play/CampaignView.coffee @@ -143,7 +143,8 @@ module.exports = class CampaignView extends RootView @render() @preloadTopHeroes() unless me.get('heroConfig')?.thangType @$el.find('#campaign-status').delay(4000).animate({top: "-=58"}, 1000) unless @terrain is 'dungeon' - @openModalView new ShareProgressModal() if @terrain and me.get('lastLevel') is 'forgetful-gemsmith' + if @terrain and me.get('name') and me.get('lastLevel') is 'forgetful-gemsmith' + @openModalView new ShareProgressModal() setCampaign: (@campaign) -> @@ -279,7 +280,7 @@ module.exports = class CampaignView extends RootView determineNextLevel: (levels) -> foundNext = false for level in levels - level.nextLevels = (reward.level for reward in level.rewards when reward.level) + level.nextLevels = (reward.level for reward in level.rewards ? [] when reward.level) unless foundNext for nextLevelOriginal in level.nextLevels nextLevel = _.find levels, original: nextLevelOriginal diff --git a/app/views/play/modal/BuyGemsModal.coffee b/app/views/play/modal/BuyGemsModal.coffee index 2a3539b50..13c836f34 100644 --- a/app/views/play/modal/BuyGemsModal.coffee +++ b/app/views/play/modal/BuyGemsModal.coffee @@ -2,6 +2,7 @@ ModalView = require 'views/core/ModalView' template = require 'templates/play/modal/buy-gems-modal' stripeHandler = require 'core/services/stripe' utils = require 'core/utils' +SubscribeModal = require 'views/core/SubscribeModal' module.exports = class BuyGemsModal extends ModalView id: 'buy-gems-modal' @@ -21,6 +22,8 @@ module.exports = class BuyGemsModal extends ModalView events: 'click .product button': 'onClickProductButton' + 'click #close-modal': 'hide' + 'click .start-subscription-button': 'onClickStartSubscription' constructor: (options) -> super(options) @@ -110,3 +113,7 @@ module.exports = class BuyGemsModal extends ModalView purchased.gems += product.gems me.set('purchased', purchased) @hide() + + onClickStartSubscription: (e) -> + @openModalView new SubscribeModal() + window.tracker?.trackEvent 'Show subscription modal', category: 'Subscription', label: 'buy gems modal' diff --git a/server/campaigns/Campaign.coffee b/server/campaigns/Campaign.coffee index 4d536ca08..35e218971 100644 --- a/server/campaigns/Campaign.coffee +++ b/server/campaigns/Campaign.coffee @@ -1,5 +1,6 @@ mongoose = require 'mongoose' plugins = require '../plugins/plugins' +log = require 'winston' CampaignSchema = new mongoose.Schema(body: String, {strict: false}) @@ -10,4 +11,26 @@ CampaignSchema.plugin(plugins.NamedPlugin) CampaignSchema.plugin(plugins.TranslationCoveragePlugin) CampaignSchema.plugin plugins.PatchablePlugin +CampaignSchema.statics.updateAdjacentCampaigns = (savedCampaign) -> + Campaign = require '../campaigns/Campaign' + query = {} + query["adjacentCampaigns.#{savedCampaign.get '_id'}"] = {$exists: true} + Campaign.find(query).exec (err, campaigns) -> + return log.error "Couldn't search for adjacent campaigns to update because of #{err}" if err + for campaign in campaigns + acs = campaign.get 'adjacentCampaigns' + ac = acs[savedCampaign.get '_id'] + # Let's make sure that we're adding translations, otherwise let's not update yet. + # We could possibly remove this; not sure it's worth having. + [oldI18NCount, newI18NCount] = [0, 0] + oldI18NCount += _.size(translations) for lang, translations of ac.i18n ? {} + newI18NCount += _.size(translations) for lang, translations of savedCampaign.get('i18n') ? {} + continue unless newI18NCount > oldI18NCount + ac.i18n = savedCampaign.get('i18n') + # Save without using middleware so that we don't get into a post-save loop. + Campaign.findByIdAndUpdate campaign._id, {$set: {adjacentCampaigns: acs}}, (err, doc) -> + return log.error "Couldn't save updated adjacent campaign because of #{err}" if err + +CampaignSchema.post 'save', -> @constructor.updateAdjacentCampaigns @ + module.exports = mongoose.model('campaign', CampaignSchema) diff --git a/server/payments/payment_handler.coffee b/server/payments/payment_handler.coffee index 9e24be60e..f51adea87 100644 --- a/server/payments/payment_handler.coffee +++ b/server/payments/payment_handler.coffee @@ -309,7 +309,7 @@ PaymentHandler = class PaymentHandler extends Handler return @sendSuccess(res) unless customerID = req.user.get('stripe')?.customerID async.parallel([ ((callback) -> - criteria = { recipient: req.user._id, 'stripe.invoiceID': { $exists: false } } + criteria = { recipient: req.user._id, 'stripe.invoiceID': { $exists: false }, 'ios.transactionID': { $exists: false } } Payment.find(criteria).limit(100).sort({_id:-1}).exec((err, payments) => callback(err, payments) )