mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-29 02:25:37 -05:00
Merge branch 'master' into production
This commit is contained in:
commit
64db50e122
34 changed files with 394 additions and 141 deletions
|
@ -12,6 +12,7 @@ module.exports = class CocoRouter extends Backbone.Router
|
|||
@bind 'route', @_trackPageView
|
||||
Backbone.Mediator.subscribe 'auth:gplus-api-loaded', @onGPlusAPILoaded, @
|
||||
Backbone.Mediator.subscribe 'router:navigate', @onNavigate, @
|
||||
@initializeSocialMediaServices = _.once @initializeSocialMediaServices
|
||||
|
||||
routes:
|
||||
'': go('HomeView') # This will go somewhere deprecated when FrontView is done.
|
||||
|
@ -125,7 +126,7 @@ module.exports = class CocoRouter extends Backbone.Router
|
|||
$('#page-container').empty().append view.el
|
||||
window.currentView = view
|
||||
@activateTab()
|
||||
@renderLoginButtons()
|
||||
@renderLoginButtons() if view.usesSocialMedia
|
||||
view.afterInsert()
|
||||
view.didReappear()
|
||||
|
||||
|
@ -139,8 +140,22 @@ module.exports = class CocoRouter extends Backbone.Router
|
|||
|
||||
onGPlusAPILoaded: =>
|
||||
@renderLoginButtons()
|
||||
|
||||
initializeSocialMediaServices: ->
|
||||
return if application.testing or application.demoing
|
||||
services = [
|
||||
'./lib/services/facebook'
|
||||
'./lib/services/google'
|
||||
'./lib/services/twitter'
|
||||
'./lib/services/linkedin'
|
||||
]
|
||||
|
||||
for service in services
|
||||
service = require service
|
||||
service()
|
||||
|
||||
renderLoginButtons: ->
|
||||
@initializeSocialMediaServices()
|
||||
$('.share-buttons, .partner-badges').addClass('fade-in').delay(10000).removeClass('fade-in', 5000)
|
||||
setTimeout(FB.XFBML.parse, 10) if FB?.XFBML?.parse # Handles FB login and Like
|
||||
twttr?.widgets?.load?()
|
||||
|
|
|
@ -24,9 +24,9 @@ init = ->
|
|||
watchForErrors()
|
||||
setUpIOSLogging()
|
||||
path = document.location.pathname
|
||||
testing = path.startsWith '/test'
|
||||
demoing = path.startsWith '/demo'
|
||||
initializeServices() unless testing or demoing
|
||||
app.testing = path.startsWith '/test'
|
||||
app.demoing = path.startsWith '/demo'
|
||||
initializeUtilityServices() unless app.testing or app.demoing
|
||||
setUpBackboneMediator()
|
||||
app.initialize()
|
||||
Backbone.history.start({ pushState: true })
|
||||
|
@ -74,15 +74,11 @@ setUpMoment = ->
|
|||
me.on 'change:preferredLanguage', (me) ->
|
||||
moment.lang me.get('preferredLanguage', true), {}
|
||||
|
||||
initializeServices = ->
|
||||
initializeUtilityServices = ->
|
||||
services = [
|
||||
'./lib/services/filepicker'
|
||||
'./lib/services/segmentio'
|
||||
'./lib/services/olark'
|
||||
'./lib/services/facebook'
|
||||
'./lib/services/google'
|
||||
'./lib/services/twitter'
|
||||
'./lib/services/linkedin'
|
||||
]
|
||||
|
||||
for service in services
|
||||
|
|
|
@ -105,7 +105,7 @@ module.exports = class LevelLoader extends CocoClass
|
|||
@loadThangsRequiredByThangType heroThangType
|
||||
|
||||
for itemThangType in _.values(heroConfig.inventory)
|
||||
url = "/db/thang.type/#{itemThangType}/version?project=name,components,original"
|
||||
url = "/db/thang.type/#{itemThangType}/version?project=name,components,original,rasterIcon"
|
||||
if itemResource = @maybeLoadURL(url, ThangType, 'thang')
|
||||
@worldNecessities.push itemResource
|
||||
else
|
||||
|
@ -183,7 +183,7 @@ module.exports = class LevelLoader extends CocoClass
|
|||
else if component.config.requiredThangTypes
|
||||
requiredThangTypes = requiredThangTypes.concat component.config.requiredThangTypes
|
||||
for thangType in requiredThangTypes
|
||||
url = "/db/thang.type/#{thangType}/version?project=name,components,original"
|
||||
url = "/db/thang.type/#{thangType}/version?project=name,components,original,rasterIcon"
|
||||
@worldNecessities.push @maybeLoadURL(url, ThangType, 'thang')
|
||||
|
||||
onThangNamesLoaded: (thangNames) ->
|
||||
|
|
|
@ -44,8 +44,10 @@ functionParameters =
|
|||
evaluateBoard: ['board', 'player']
|
||||
getPossibleMoves: ['board']
|
||||
minimax_alphaBeta: ['board', 'player', 'depth', 'alpha', 'beta']
|
||||
distanceTo: ['target']
|
||||
|
||||
chooseAction: []
|
||||
plan: []
|
||||
initializeCentroids: []
|
||||
update: []
|
||||
getNearestEnemy: []
|
||||
|
|
|
@ -522,7 +522,7 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
newWidth = 0.55 * pageWidth
|
||||
newHeight = newWidth / aspectRatio
|
||||
return unless newWidth > 0 and newHeight > 0
|
||||
return if newWidth is oldWidth and newHeight is oldHeight
|
||||
return if newWidth is oldWidth and newHeight is oldHeight and not @options.spectateGame
|
||||
#scaleFactor = if application.isIPadApp then 2 else 1 # Retina
|
||||
scaleFactor = 1
|
||||
@normalCanvas.add(@webGLCanvas).attr width: newWidth * scaleFactor, height: newHeight * scaleFactor
|
||||
|
@ -533,7 +533,9 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
@normalStage.scaleX *= newWidth / oldWidth
|
||||
@normalStage.scaleY *= newHeight / oldHeight
|
||||
@camera.onResize newWidth, newHeight
|
||||
|
||||
if @options.spectateGame
|
||||
# Since normalCanvas is absolutely positioned, it needs help aligning with webGLCanvas. But not further than +149px (1920px screen).
|
||||
@normalCanvas.css 'left', Math.min 149, @webGLCanvas.offset().left
|
||||
|
||||
#- Camera focus on hero
|
||||
focusOnHero: ->
|
||||
|
|
|
@ -216,13 +216,13 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
|||
tome_cast_button_castable: "Lançar" # Temporary, if tome_cast_button_run isn't translated.
|
||||
tome_cast_button_casting: "Conjurando" # Temporary, if tome_cast_button_running isn't translated.
|
||||
tome_cast_button_cast: "Feitiço" # Temporary, if tome_cast_button_ran isn't translated.
|
||||
# tome_cast_button_run: "Run"
|
||||
# tome_cast_button_running: "Running"
|
||||
# tome_cast_button_ran: "Ran"
|
||||
tome_cast_button_run: "Rodar"
|
||||
tome_cast_button_running: "Rodando"
|
||||
tome_cast_button_ran: "Encerrado"
|
||||
tome_submit_button: "Enviar"
|
||||
# tome_reload_method: "Reload original code for this method" # Title text for individual method reload button.
|
||||
tome_reload_method: "Recarregar o código original para este método" # Title text for individual method reload button.
|
||||
tome_select_method: "Selecione um Método"
|
||||
# tome_see_all_methods: "See all methods you can edit" # Title text for method list selector (shown when there are multiple programmable methdos).
|
||||
tome_see_all_methods: "Visualizar todos os métodos que você pode editar" # Title text for method list selector (shown when there are multiple programmable methdos).
|
||||
tome_select_a_thang: "Selecione alguém para "
|
||||
tome_available_spells: "Feitiços Disponíveis"
|
||||
tome_your_skills: "Suas habilidades"
|
||||
|
@ -236,14 +236,14 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
|||
time_total: "Máximo:"
|
||||
time_goto: "Ir para:"
|
||||
infinite_loop_try_again: "Tentar novamente"
|
||||
# infinite_loop_reset_level: "Reset Level"
|
||||
infinite_loop_reset_level: "Resetar nível"
|
||||
# infinite_loop_comment_out: "Comment Out My Code"
|
||||
# tip_toggle_play: "Toggle play/paused with Ctrl+P."
|
||||
# tip_scrub_shortcut: "Ctrl+[ and Ctrl+] rewind and fast-forward."
|
||||
tip_toggle_play: "Alterne entre rodando/pausado com Ctrl+P."
|
||||
tip_scrub_shortcut: "Ctrl+[ e Ctrl+] rebobina e avança."
|
||||
# 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_think_solution: "Think of the solution, not the problem."
|
||||
tip_open_source: "CodeCombat é 100% código aberto!"
|
||||
tip_beta_launch: "CodeCombat lançou sua versão beta em outubro de 2013."
|
||||
tip_think_solution: "Pense na solução, não no problema."
|
||||
# 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"
|
||||
|
@ -257,16 +257,16 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
|||
# 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_no_try: "Faça. Ou não faça. Não existe tentar. - Yoda"
|
||||
tip_patience: "Paciência você deve ter, jovem Padawan. - Yoda"
|
||||
tip_documented_bug: "Um bug documentado não é um bug; é uma funcionalidade."
|
||||
# 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"
|
||||
# tip_hardware_problem: "Q: How many programmers does it take to change a light bulb? A: None, it's a hardware problem."
|
||||
# tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
|
||||
# tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
|
||||
# tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
|
||||
tip_brute_force: "Na dúvida, utilize força bruta. - Ken Thompson"
|
||||
customize_wizard: "Personalize o feiticeiro"
|
||||
|
||||
game_menu:
|
||||
|
@ -277,14 +277,14 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
|||
guide_tab: "Guia"
|
||||
multiplayer_tab: "Multijogador"
|
||||
inventory_caption: "Equipar seu herói"
|
||||
# choose_hero_caption: "Choose hero, language"
|
||||
choose_hero_caption: "Escolha seu herói, linguagem"
|
||||
# save_load_caption: "... and view history"
|
||||
# options_caption: "Configure settings"
|
||||
options_caption: "Configurar preferências"
|
||||
guide_caption: "Documentos e dicas"
|
||||
# multiplayer_caption: "Play with friends!"
|
||||
multiplayer_caption: "Jogue com seus amigos!"
|
||||
|
||||
# inventory:
|
||||
# choose_inventory: "Equip Items"
|
||||
choose_inventory: "Equipar itens"
|
||||
|
||||
choose_hero:
|
||||
choose_hero: "Escolha seu Herói"
|
||||
|
@ -300,23 +300,23 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
|||
granularity_change_history: "Histórico"
|
||||
|
||||
options:
|
||||
# general_options: "General Options" # Check out the Options tab in the Game Menu while playing a level
|
||||
general_options: "Opções Gerais" # Check out the Options tab in the Game Menu while playing a level
|
||||
volume_label: "Volume"
|
||||
music_label: "Música"
|
||||
# music_description: "Turn background music on/off."
|
||||
# autorun_label: "Autorun"
|
||||
# autorun_description: "Control automatic code execution."
|
||||
music_description: "Ligar/desligar música de fundo."
|
||||
autorun_label: "Rodar automaticamente"
|
||||
autorun_description: "Controlar execução automática do código."
|
||||
editor_config: "Editor de Configurações"
|
||||
editor_config_title: "Editor de Configurações"
|
||||
# editor_config_level_language_label: "Language for This Level"
|
||||
# editor_config_level_language_description: "Define the programming language for this particular level."
|
||||
# editor_config_default_language_label: "Default Programming Language"
|
||||
# editor_config_default_language_description: "Define the programming language you want to code in when starting new levels."
|
||||
editor_config_level_language_label: "Linguagem para este nível"
|
||||
editor_config_level_language_description: "Definir linguagem para esse nível específico."
|
||||
editor_config_default_language_label: "Linguagem de programação padrão"
|
||||
editor_config_default_language_description: "Define a linguagem de programação que você quer utilizar quando iniciar novos níveis."
|
||||
editor_config_keybindings_label: "Teclas de Atalho"
|
||||
editor_config_keybindings_default: "Padrão (Ace)"
|
||||
editor_config_keybindings_description: "Adicionar atalhos conhecidos de editores comuns."
|
||||
# editor_config_livecompletion_label: "Live Autocompletion"
|
||||
# editor_config_livecompletion_description: "Displays autocomplete suggestions while typing."
|
||||
editor_config_livecompletion_label: "Autocompletar durante a escrita"
|
||||
editor_config_livecompletion_description: "Mostra opções de autocompletar enquanto estiver escrevendo."
|
||||
editor_config_invisibles_label: "Mostrar Invisíveis"
|
||||
editor_config_invisibles_description: "Mostrar invisíveis como espaços e tabs."
|
||||
editor_config_indentguides_label: "Mostrar Linhas de Identação"
|
||||
|
@ -367,8 +367,8 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
|||
forum_page: "nosso fórum"
|
||||
forum_suffix: " ao invés disso."
|
||||
send: "Enviar opinião"
|
||||
# contact_candidate: "Contact Candidate" # Deprecated
|
||||
# recruitment_reminder: "Use this form to reach out to candidates you are interested in interviewing. Remember that CodeCombat charges 15% 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." # Deprecated
|
||||
contact_candidate: "Contactar Candidato" # Deprecated
|
||||
recruitment_reminder: "Utilize esse formulário para entrar em contato com candidatos que você esteja interessado em entrevistar. Lembre-se que o CodeCombat cobra 15% do salário do primeiro ano. A taxa de contratação é cobrada quando da contratação do empregado e é reembolsável por 90 dias, se o empregado não permanece no emprego. Empregados de meio-turno, remotos ou com contrato serão gratuitos como estagiários." # Deprecated
|
||||
|
||||
account_settings:
|
||||
title: "Configurações da Conta"
|
||||
|
@ -416,20 +416,20 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
|||
enter: "Enter"
|
||||
escape: "Esc"
|
||||
shift: "Shift"
|
||||
# cast_spell: "Cast current spell."
|
||||
# run_real_time: "Run in real time."
|
||||
cast_spell: "Lançar feitiço atual."
|
||||
run_real_time: "Rodar em tempo real."
|
||||
# continue_script: "Continue past current script."
|
||||
# skip_scripts: "Skip past all skippable scripts."
|
||||
# toggle_playback: "Toggle play/pause."
|
||||
# scrub_playback: "Scrub back and forward through time."
|
||||
# single_scrub_playback: "Scrub back and forward through time by a single frame."
|
||||
# scrub_execution: "Scrub through current spell execution."
|
||||
# toggle_debug: "Toggle debug display."
|
||||
# toggle_grid: "Toggle grid overlay."
|
||||
# toggle_pathfinding: "Toggle pathfinding overlay."
|
||||
# beautify: "Beautify your code by standardizing its formatting."
|
||||
# maximize_editor: "Maximize/minimize code editor."
|
||||
# move_wizard: "Move your Wizard around the level."
|
||||
toggle_playback: "Alternar play/pause."
|
||||
scrub_playback: "Rolar para frente e para trás no tempo."
|
||||
single_scrub_playback: "Rolar para frente e para trás no tempo, quadro a quadro."
|
||||
scrub_execution: "Rolar através da execução do feitiço atual."
|
||||
toggle_debug: "Ligar/desligar informações de debug."
|
||||
toggle_grid: "Ligar/desligar exibição da grade."
|
||||
toggle_pathfinding: "Ligar/desligar exibição do pathfinding (caminho)."
|
||||
beautify: "Embeleze seu código a partir da padronização de formatação."
|
||||
maximize_editor: "Maximizar/minimizar editor de código."
|
||||
move_wizard: "Mova o Wizard pelo nível."
|
||||
|
||||
community:
|
||||
main_title: "Comunidade CodeCombat"
|
||||
|
@ -468,7 +468,7 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
|||
article_title: "Editor de Artigo"
|
||||
thang_title: "Editor de Thang"
|
||||
level_title: "Editor de Nível"
|
||||
# achievement_title: "Achievement Editor"
|
||||
achievement_title: "Editor de Conquistas"
|
||||
back: "Voltar"
|
||||
revert: "Reverter"
|
||||
revert_models: "Reverter Modelos"
|
||||
|
@ -979,11 +979,11 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
|||
projects_header_2: "Projetos (Top 3)"
|
||||
projects_blurb: "Destaque seus projetos para impressionar os empregadores."
|
||||
project_name: "Nome do Projeto"
|
||||
# project_name_help: "What was the project called?"
|
||||
project_name_help: "Como o projeto se chama?"
|
||||
project_description: "Descrição"
|
||||
# project_description_help: "Briefly describe the project."
|
||||
project_description_help: "Descreva o projeto brevemente."
|
||||
project_picture: "Imagem"
|
||||
# project_picture_help: "Upload a 230x115px or larger image showing off the project."
|
||||
project_picture_help: "Envie uma imagem com 230x115px ou maior mostrando o projeto."
|
||||
project_link: "Link"
|
||||
project_link_help: "Link para o projeto."
|
||||
# player_code: "Player Code"
|
||||
|
@ -1035,11 +1035,11 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
|||
# inactive_developers: "Inactive Developers"
|
||||
|
||||
admin:
|
||||
# av_espionage: "Espionage" # Really not important to translate /admin controls.
|
||||
# av_espionage_placeholder: "Email or username"
|
||||
# av_usersearch: "User Search"
|
||||
# av_usersearch_placeholder: "Email, username, name, whatever"
|
||||
# av_usersearch_search: "Search"
|
||||
av_espionage: "Espionagem" # Really not important to translate /admin controls.
|
||||
av_espionage_placeholder: "Email ou username"
|
||||
av_usersearch: "Busca de Usuário"
|
||||
av_usersearch_placeholder: "Email, username, nome, qualquer coisa"
|
||||
av_usersearch_search: "Buscar"
|
||||
av_title: "Visualização de Administrador"
|
||||
av_entities_sub_title: "Entidades"
|
||||
av_entities_users_url: "Usuários"
|
||||
|
|
|
@ -58,3 +58,54 @@
|
|||
-moz-filter: $filters
|
||||
-o-filter: $filters
|
||||
filter: $filters
|
||||
|
||||
@mixin flexbox()
|
||||
display: -webkit-box
|
||||
display: -moz-box
|
||||
display: -ms-flexbox
|
||||
display: -webkit-flex
|
||||
display: flex
|
||||
|
||||
@mixin flex($values)
|
||||
-webkit-box-flex: $values
|
||||
-moz-box-flex: $values
|
||||
-webkit-flex: $values
|
||||
-ms-flex: $values
|
||||
flex: $values
|
||||
|
||||
@mixin order($val)
|
||||
-webkit-box-ordinal-group: $val
|
||||
-moz-box-ordinal-group: $val
|
||||
-ms-flex-order: $val
|
||||
-webkit-order: $val
|
||||
order: $val
|
||||
|
||||
@mixin flex-justify()
|
||||
-webkit-box-pack: justify
|
||||
-webkit-justify-content: space-between
|
||||
-ms-flex-pack: justify
|
||||
justify-content: space-between
|
||||
|
||||
@mixin flex-align-content-start()
|
||||
-webkit-align-content: flex-start
|
||||
-ms-flex-align-content: flex-start
|
||||
align-content: flex-start
|
||||
|
||||
@mixin flex-center()
|
||||
-webkit-box-align: center
|
||||
-webkit-align-items: center
|
||||
-ms-flex-align: center
|
||||
align-items: center
|
||||
|
||||
@mixin flex-wrap()
|
||||
-webkit-flex-wrap: wrap
|
||||
-ms-flex-wrap: wrap
|
||||
flex-wrap: wrap
|
||||
|
||||
@mixin flex-column()
|
||||
-webkit-box-orient: vertical
|
||||
-moz-box-orient: vertical
|
||||
-ms-box-orient: vertical
|
||||
-webkit-flex-direction: column
|
||||
-ms-flex-direction: column
|
||||
-flex-direction: column
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
.problem-alert
|
||||
z-index: 10
|
||||
position: absolute
|
||||
bottom: -135px
|
||||
// Position these at the end of the spell editor, right above the spell toolbar.
|
||||
bottom: -20px
|
||||
left: 10px
|
||||
right: 10px
|
||||
background: transparent
|
||||
|
|
|
@ -12,9 +12,8 @@
|
|||
position: absolute
|
||||
left: 10px
|
||||
top: 48px
|
||||
bottom: 121px
|
||||
// Bottom relates to .palette height and padding-top
|
||||
right: 10px
|
||||
padding-bottom: 10px
|
||||
z-index: 1
|
||||
// Set z-index above palette
|
||||
display: none
|
||||
|
@ -62,9 +61,6 @@
|
|||
line-height: 20px
|
||||
overflow: visible
|
||||
|
||||
&.user-code-problem.spell-cast
|
||||
@include editor-height(60px)
|
||||
|
||||
&.disabled
|
||||
@include opacity(80)
|
||||
.ace_cursor
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
#spell-palette-view
|
||||
position: absolute
|
||||
bottom: 10px
|
||||
padding-bottom: 10px
|
||||
left: 10px
|
||||
right: 10px
|
||||
height: 140px
|
||||
//height: 140px
|
||||
// Height relates to .tab-content height
|
||||
padding-top: 35px
|
||||
padding-left: 12px
|
||||
|
@ -69,6 +69,37 @@
|
|||
margin-right: 3px
|
||||
vertical-align: top
|
||||
|
||||
&.hero .properties
|
||||
@include flexbox()
|
||||
@include flex-wrap()
|
||||
@include flex-column()
|
||||
@include flex-align-content-start()
|
||||
|
||||
.property-entry-item-group
|
||||
display: inline-block
|
||||
min-height: 38px
|
||||
max-width: 212px
|
||||
@include flexbox()
|
||||
@include flex-wrap()
|
||||
@include flex-center()
|
||||
outline: 1px dashed #b86
|
||||
position: relative
|
||||
|
||||
img.item-image
|
||||
width: 38px
|
||||
height: 38px
|
||||
position: absolute
|
||||
|
||||
&:not(:hover) img.item-image
|
||||
-webkit-filter: sepia(100%)
|
||||
filter: sepia(100%)
|
||||
|
||||
.spell-palette-entry-view
|
||||
margin-left: 38px
|
||||
width: 174px
|
||||
width: -webkit-calc(100% - 38px)
|
||||
width: calc(100% - 38px)
|
||||
|
||||
.code-language-logo
|
||||
position: absolute
|
||||
width: 16px
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
border: 1px solid transparent
|
||||
cursor: pointer
|
||||
@include user-select(all)
|
||||
height: 19px
|
||||
text-overflow: ellipsis
|
||||
overflow: hidden
|
||||
white-space: nowrap
|
||||
|
||||
&:hover
|
||||
border: 1px solid #000000
|
||||
|
|
|
@ -42,12 +42,18 @@
|
|||
position: relative
|
||||
margin: 0 auto
|
||||
|
||||
canvas#surface
|
||||
background-color: #333
|
||||
canvas#webgl-surface, canvas#normal-surface
|
||||
display: block
|
||||
z-index: 1
|
||||
margin: 0 auto
|
||||
|
||||
canvas#webgl-surface
|
||||
background-color: #333
|
||||
|
||||
canvas#normal-surface
|
||||
position: absolute
|
||||
top: 0
|
||||
pointer-events: none
|
||||
|
||||
min-width: 1024px
|
||||
position: relative
|
||||
|
|
|
@ -75,14 +75,15 @@ body
|
|||
a(href='/teachers', data-i18n="nav.teachers") Teachers
|
||||
if me.isAdmin()
|
||||
a(href='/admin', data-i18n="nav.admin") Admin
|
||||
|
||||
.share-buttons
|
||||
if !isIE
|
||||
.g-plusone(data-href="http://codecombat.com", data-size="medium")
|
||||
.fb-like(data-href="https://www.facebook.com/codecombat", data-send="false", data-layout="button_count", data-width="350", data-show-faces="true", data-ref="coco_footer_#{fbRef}")
|
||||
if !isIE
|
||||
a.twitter-follow-button(href="https://twitter.com/CodeCombat", data-show-count="true", data-show-screen-name="false", data-dnt="true", data-align="right", data-i18n="nav.twitter_follow") Follow
|
||||
iframe.github-star-button(src="http://ghbtns.com/github-btn.html?user=codecombat&repo=codecombat&type=watch&count=true", allowtransparency="true", frameborder="0", scrolling="0", width="110", height="20")
|
||||
|
||||
if usesSocialMedia
|
||||
.share-buttons
|
||||
if !isIE
|
||||
.g-plusone(data-href="http://codecombat.com", data-size="medium")
|
||||
.fb-like(data-href="https://www.facebook.com/codecombat", data-send="false", data-layout="button_count", data-width="350", data-show-faces="true", data-ref="coco_footer_#{fbRef}")
|
||||
if !isIE
|
||||
a.twitter-follow-button(href="https://twitter.com/CodeCombat", data-show-count="true", data-show-screen-name="false", data-dnt="true", data-align="right", data-i18n="nav.twitter_follow") Follow
|
||||
iframe.github-star-button(src="http://ghbtns.com/github-btn.html?user=codecombat&repo=codecombat&type=watch&count=true", allowtransparency="true", frameborder="0", scrolling="0", width="110", height="20")
|
||||
|
||||
.partner-badges
|
||||
a.mixpanel-badge(href="https://mixpanel.com/f/partner")
|
||||
|
|
|
@ -43,11 +43,11 @@
|
|||
|
||||
.form
|
||||
.form-group.select-group
|
||||
span.help-block(data-i18n="choose_hero.programming_language_description") Which programming language do you want to use?
|
||||
label.control-label(for="option-code-language", data-i18n="choose_hero.programming_language") Programming Language
|
||||
select#option-code-language(name="code-language")
|
||||
for option in codeLanguages
|
||||
option(value=option.id, selected=codeLanguage === option.id)= option.name
|
||||
span.help-block(data-i18n="choose_hero.programming_language_description") Which programming language do you want to use?
|
||||
|
||||
if level
|
||||
.form-group.select-group
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
.progress-bar.progress-bar-success
|
||||
|
||||
#tip-wrapper
|
||||
strong.tip(data-i18n='play_level.tip_insert_positions') Shift+Click a point on the map to insert it into the spell editor.
|
||||
strong.tip(data-i18n='play_level.tip_toggle_play') Toggle play/paused with Ctrl+P.
|
||||
strong.tip(data-i18n='play_level.tip_scrub_shortcut') Ctrl+[ and Ctrl+] rewind and fast-forward.
|
||||
strong.tip(data-i18n='play_level.tip_guide_exists') Click the guide at the top of the page for useful info.
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
button.btn.btn-lg.btn-inverse.banner.cast-button(title=castVerbose, data-i18n="play_level.tome_run_button_ran") Ran
|
||||
|
||||
button.btn.btn-lg.btn-success.banner.submit-button(title=castRealTimeVerbose) Submit
|
||||
button.btn.btn-lg.btn-success.banner.submit-button(title=castRealTimeVerbose, data-i18n="play_level.tome_submit_button") Submit
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
img(src="/images/level/code_palette_background.png").code-palette-background
|
||||
span.code-palette-background
|
||||
.code-language-logo
|
||||
ul(class="nav nav-pills" + (tabbed ? ' multiple-tabs' : ''))
|
||||
each slug, group in entryGroupSlugs
|
||||
li(class=group == "this" || slug == "available-spells" ? "active" : "")
|
||||
a(data-toggle="pill", data-target='#palette-tab-' + slug)
|
||||
h4= entryGroupNames[group]
|
||||
.tab-content
|
||||
each slug, group in entryGroupSlugs
|
||||
div(id="palette-tab-" + slug, class="tab-pane nano" + (group == "this" || slug == defaultGroupSlug ? " active" : ""))
|
||||
div(class="properties properties-" + slug + " nano-content")
|
||||
if entryGroupSlugs
|
||||
// Non-hero; group by entry groups, or maybe nothing.
|
||||
.code-language-logo
|
||||
ul(class="nav nav-pills" + (tabbed ? ' multiple-tabs' : ''))
|
||||
each slug, group in entryGroupSlugs
|
||||
li(class=group == "this" || slug == "available-spells" ? "active" : "")
|
||||
a(data-toggle="pill", data-target='#palette-tab-' + slug)
|
||||
h4= entryGroupNames[group]
|
||||
.tab-content
|
||||
each slug, group in entryGroupSlugs
|
||||
div(id="palette-tab-" + slug, class="tab-pane nano" + (group == "this" || slug == defaultGroupSlug ? " active" : ""))
|
||||
div(class="properties properties-" + slug + " nano-content")
|
||||
else
|
||||
// Hero; group by items, no tabs.
|
||||
.properties
|
||||
|
|
|
@ -1 +1 @@
|
|||
span= doc.title
|
||||
span.doc-title= doc.title
|
|
@ -105,6 +105,10 @@ if doc.returns
|
|||
if doc.returns.description
|
||||
div!= marked(doc.returns.description)
|
||||
|
||||
if item
|
||||
p
|
||||
em Granted by #{item.get('name')}.
|
||||
|
||||
if selectedMethod
|
||||
p
|
||||
em Write the body of this method below.
|
|
@ -3,7 +3,8 @@
|
|||
.level-content
|
||||
#control-bar-view
|
||||
#canvas-wrapper
|
||||
canvas(width=924, height=589)#surface
|
||||
canvas(width=924, height=589)#webgl-surface
|
||||
canvas(width=924, height=589)#normal-surface
|
||||
#canvas-left-gradient.gradient
|
||||
#canvas-top-gradient.gradient
|
||||
#gold-view.secret.expanded
|
||||
|
|
|
@ -36,15 +36,17 @@ block append content
|
|||
th XP
|
||||
each earnedAchievement in earnedAchievements.models
|
||||
- var achievement = earnedAchievement.get('achievement');
|
||||
tr
|
||||
td= achievement.i18nName()
|
||||
td= achievement.i18nDescription()
|
||||
td= moment().format("MMMM Do YYYY", earnedAchievement.get('changed'))
|
||||
if achievement.isRepeatable()
|
||||
td= earnedAchievement.get('achievedAmount')
|
||||
else
|
||||
td
|
||||
td= earnedAchievement.get('earnedPoints')
|
||||
if achievement.get('category')
|
||||
// No level-specific achievements in here.
|
||||
tr
|
||||
td= achievement.i18nName()
|
||||
td= achievement.i18nDescription()
|
||||
td= moment().format("MMMM Do YYYY", earnedAchievement.get('changed'))
|
||||
if achievement.isRepeatable()
|
||||
td= earnedAchievement.get('achievedAmount')
|
||||
else
|
||||
td
|
||||
td= earnedAchievement.get('earnedPoints')
|
||||
else
|
||||
.panel#no-achievements
|
||||
.panel-body(data-i18n="user.no_achievements") No achievements earned yet.
|
||||
|
|
|
@ -334,7 +334,7 @@ module.exports = class InventoryView extends CocoView
|
|||
'the-second-kithmaze': {feet: 'simple-boots', 'programming-book': 'programmaticon-i'}
|
||||
'new-sight': {'right-hand': 'longsword', 'programming-book': 'programmaticon-i'}
|
||||
'lowly-kithmen': {feet: 'simple-boots', 'right-hand': 'longsword', 'programming-book': 'programmaticon-i', eyes: 'crude-glasses'}
|
||||
'a-bolt-in-the-dark': {feet: 'simple-boots', 'right-hand': 'longsword', torso: 'leather-tunic', eyes: 'crude-glasses'}
|
||||
'closing-the-distance': {feet: 'simple-boots', 'right-hand': 'longsword', torso: 'leather-tunic', eyes: 'crude-glasses'}
|
||||
'the-final-kithmaze': {feet: 'simple-boots', 'right-hand': 'longsword', torso: 'leather-tunic', 'programming-book': 'programmaticon-i', eyes: 'crude-glasses'}
|
||||
'kithgard-gates': {feet: 'simple-boots', 'right-hand': 'builders-hammer'}
|
||||
'defence-of-plainswood': {feet: 'simple-boots', 'right-hand': 'builders-hammer'}
|
||||
|
|
|
@ -70,6 +70,7 @@ module.exports = class RootView extends CocoView
|
|||
getRenderData: ->
|
||||
c = super()
|
||||
c.showBackground = @showBackground
|
||||
c.usesSocialMedia = @usesSocialMedia
|
||||
c
|
||||
|
||||
afterRender: ->
|
||||
|
|
|
@ -42,7 +42,7 @@ module.exports = class AuthModal extends ModalView
|
|||
|
||||
afterInsert: ->
|
||||
super()
|
||||
_.delay application.router.renderLoginButtons, 500
|
||||
_.delay (=> application.router.renderLoginButtons()), 500
|
||||
_.delay (=> $('input:visible:first', @$el).focus()), 500
|
||||
|
||||
onSignupInstead: (e) ->
|
||||
|
|
|
@ -205,8 +205,9 @@ module.exports = class SpectateLevelView extends RootView
|
|||
# initialization
|
||||
|
||||
initSurface: ->
|
||||
surfaceCanvas = $('canvas#surface', @$el)
|
||||
@surface = new Surface(@world, surfaceCanvas, thangTypes: @supermodel.getModels(ThangType), playJingle: not @isEditorPreview, spectateGame: true, wizards: @level.get('type', true) isnt 'hero')
|
||||
webGLSurface = $('canvas#webgl-surface', @$el)
|
||||
normalSurface = $('canvas#normal-surface', @$el)
|
||||
@surface = new Surface(@world, normalSurface, webGLSurface, thangTypes: @supermodel.getModels(ThangType), playJingle: not @isEditorPreview, spectateGame: true, wizards: @level.get('type', true) isnt 'hero')
|
||||
worldBounds = @world.getBounds()
|
||||
bounds = [{x:worldBounds.left, y:worldBounds.top}, {x:worldBounds.right, y:worldBounds.bottom}]
|
||||
@surface.camera.setBounds(bounds)
|
||||
|
|
|
@ -97,7 +97,7 @@ module.exports = class WorldMapView extends RootView
|
|||
@$el.find('.level').tooltip()
|
||||
@$el.addClass _.string.slugify @terrain
|
||||
@updateVolume()
|
||||
@highlightElement '.level.next', delay: 8000, duration: 20000, rotation: 0, sides: ['top']
|
||||
@highlightElement '.level.next', delay: 2000, duration: 60000, rotation: 0, sides: ['top']
|
||||
|
||||
onSessionsLoaded: (e) ->
|
||||
for session in @sessions.models
|
||||
|
|
|
@ -25,6 +25,7 @@ class LevelSessionsCollection extends CocoCollection
|
|||
module.exports = class LadderView extends RootView
|
||||
id: 'ladder-view'
|
||||
template: require 'templates/play/ladder/ladder'
|
||||
usesSocialMedia: true
|
||||
|
||||
subscriptions:
|
||||
'application:idle-changed': 'onIdleChanged'
|
||||
|
|
|
@ -28,6 +28,7 @@ module.exports = class VictoryModal extends ModalView
|
|||
'enter': -> 'onPlayNextLevel'
|
||||
|
||||
constructor: (options) ->
|
||||
application.router.initializeSocialMediaServices()
|
||||
victory = options.level.get('victory')
|
||||
body = utils.i18n(victory, 'body') or 'Sorry, this level has no victory message yet.'
|
||||
@body = marked(body)
|
||||
|
|
|
@ -83,9 +83,11 @@ module.exports = class DocFormatter
|
|||
@doc.title = if @options.shortenize then @doc.shorterName else @doc.shortName
|
||||
|
||||
# Grab the language-specific documentation for some sub-properties, if we have it.
|
||||
toTranslate = [{obj: @doc, prop: 'description'}, {obj: @doc, prop: 'example'}, {obj: @doc, prop: 'returns'}]
|
||||
toTranslate = [{obj: @doc, prop: 'description'}, {obj: @doc, prop: 'example'}]
|
||||
for arg in (@doc.args ? [])
|
||||
toTranslate.push {obj: arg, prop: 'example'}, {obj: arg, prop: 'description'}
|
||||
if @doc.returns
|
||||
toTranslate.push {obj: @doc.returns, prop: 'example'}, {obj: @doc.returns, prop: 'description'}
|
||||
for {obj, prop} in toTranslate
|
||||
if val = obj[prop]?[@options.language]
|
||||
obj[prop] = val
|
||||
|
@ -93,7 +95,7 @@ module.exports = class DocFormatter
|
|||
obj[prop] = null
|
||||
|
||||
formatPopover: ->
|
||||
content = popoverTemplate doc: @doc, language: @options.language, value: @formatValue(), marked: marked, argumentExamples: (arg.example or arg.default or arg.name for arg in @doc.args ? []), writable: @options.writable, selectedMethod: @options.selectedMethod, cooldowns: @inferCooldowns()
|
||||
content = popoverTemplate doc: @doc, language: @options.language, value: @formatValue(), marked: marked, argumentExamples: (arg.example or arg.default or arg.name for arg in @doc.args ? []), writable: @options.writable, selectedMethod: @options.selectedMethod, cooldowns: @inferCooldowns(), item: @options.item
|
||||
owner = if @doc.owner is 'this' then @options.thang else window[@doc.owner]
|
||||
content = content.replace /#{spriteName}/g, @options.thang.type ? @options.thang.spriteName # Prefer type, and excluded the quotes we'd get with @formatValue
|
||||
content.replace /\#\{(.*?)\}/g, (s, properties) => @formatValue downTheChain(owner, properties.split('.'))
|
||||
|
|
|
@ -4,6 +4,7 @@ template = require 'templates/play/level/tome/spell_palette'
|
|||
filters = require 'lib/image_filter'
|
||||
SpellPaletteEntryView = require './SpellPaletteEntryView'
|
||||
LevelComponent = require 'models/LevelComponent'
|
||||
ThangType = require 'models/ThangType'
|
||||
EditorConfigModal = require '../modal/EditorConfigModal'
|
||||
|
||||
N_ROWS = 4
|
||||
|
@ -26,6 +27,7 @@ module.exports = class SpellPaletteView extends CocoView
|
|||
super options
|
||||
@thang = options.thang
|
||||
@createPalette()
|
||||
$(window).on 'resize', @onResize
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
|
@ -38,20 +40,53 @@ module.exports = class SpellPaletteView extends CocoView
|
|||
|
||||
afterRender: ->
|
||||
super()
|
||||
for group, entries of @entryGroups
|
||||
groupSlug = @entryGroupSlugs[group]
|
||||
for columnNumber, entryColumn of entries
|
||||
col = $('<div class="property-entry-column"></div>').appendTo @$el.find(".properties-#{groupSlug}")
|
||||
for entry in entryColumn
|
||||
col.append entry.el
|
||||
if @entryGroupSlugs
|
||||
for group, entries of @entryGroups
|
||||
groupSlug = @entryGroupSlugs[group]
|
||||
for columnNumber, entryColumn of entries
|
||||
col = $('<div class="property-entry-column"></div>').appendTo @$el.find(".properties-#{groupSlug}")
|
||||
for entry in entryColumn
|
||||
col.append entry.el
|
||||
entry.render() # Render after appending so that we can access parent container for popover
|
||||
$('.nano').nanoScroller()
|
||||
@updateCodeLanguage @options.language
|
||||
else
|
||||
@entryGroupElements = {}
|
||||
for group, entries of @entryGroups
|
||||
@entryGroupElements[group] = itemGroup = $('<div class="property-entry-item-group"></div>').appendTo @$el.find('.properties')
|
||||
itemGroup.append $('<img class="item-image"></img>').attr('src', entries[0].options.item.getPortraitURL()).css('top', Math.max(0, 19 * (entries.length - 2) / 2)) if entries[0].options.item?.getPortraitURL
|
||||
for entry in entries
|
||||
itemGroup.append entry.el
|
||||
entry.render() # Render after appending so that we can access parent container for popover
|
||||
$('.nano').nanoScroller()
|
||||
@updateCodeLanguage @options.language
|
||||
@$el.addClass 'hero'
|
||||
@updateMaxHeight()
|
||||
|
||||
afterInsert: ->
|
||||
super()
|
||||
_.delay => @$el?.css('bottom', 0) unless $('#spell-view').is('.shown')
|
||||
|
||||
updateCodeLanguage: (language) ->
|
||||
@options.language = language
|
||||
@$el.find('.code-language-logo').removeClass().addClass 'code-language-logo ' + language
|
||||
|
||||
updateMaxHeight: ->
|
||||
return unless @isHero
|
||||
nColumns = Math.floor @$el.find('.properties').innerWidth() / 212 # ~212px is a good max entry width; will always have 2 columns
|
||||
columns = ({items: [], nEntries: 0} for i in [0 ... nColumns])
|
||||
nRows = 0
|
||||
for group, entries of @entryGroups
|
||||
shortestColumn = _.sortBy(columns, (column) -> column.nEntries)[0]
|
||||
shortestColumn.nEntries += Math.max 2, entries.length
|
||||
shortestColumn.items.push @entryGroupElements[group]
|
||||
nRows = Math.max nRows, shortestColumn.nEntries
|
||||
for column in columns
|
||||
for item in column.items
|
||||
item.detach().appendTo @$el.find('.properties')
|
||||
@$el.find('.properties').css('height', 19 * (nRows + 1))
|
||||
|
||||
onResize: (e) =>
|
||||
@updateMaxHeight()
|
||||
|
||||
createPalette: ->
|
||||
Backbone.Mediator.publish 'tome:palette-cleared', {thangID: @thang.id}
|
||||
lcs = @supermodel.getModels LevelComponent
|
||||
|
@ -86,6 +121,12 @@ module.exports = class SpellPaletteView extends CocoView
|
|||
else
|
||||
propStorage =
|
||||
'this': ['apiProperties', 'apiMethods']
|
||||
if @options.level.get('type', true) isnt 'hero' or not @options.programmable
|
||||
@organizePalette propStorage, allDocs, excludedDocs
|
||||
else
|
||||
@organizePaletteHero propStorage, allDocs, excludedDocs
|
||||
|
||||
organizePalette: (propStorage, allDocs, excludedDocs) ->
|
||||
count = 0
|
||||
propGroups = {}
|
||||
for owner, storages of propStorage
|
||||
|
@ -95,13 +136,11 @@ module.exports = class SpellPaletteView extends CocoView
|
|||
added = _.sortBy(props).slice()
|
||||
propGroups[owner] = (propGroups[owner] ? []).concat added
|
||||
count += added.length
|
||||
Backbone.Mediator.publish 'tome:update-snippets', propGroups: propGroups, allDocs: allDocs, language: @options.language
|
||||
|
||||
shortenize = count > 6
|
||||
tabbify = count >= 10
|
||||
@entries = []
|
||||
|
||||
Backbone.Mediator.publish 'tome:update-snippets', propGroups: propGroups, allDocs: allDocs, language: @options.language
|
||||
|
||||
for owner, props of propGroups
|
||||
for prop in props
|
||||
doc = _.find (allDocs['__' + prop] ? []), (doc) ->
|
||||
|
@ -130,22 +169,68 @@ module.exports = class SpellPaletteView extends CocoView
|
|||
@defaultGroupSlug = _.string.slugify defaultGroup
|
||||
@entryGroupSlugs = {}
|
||||
@entryGroupNames = {}
|
||||
iOSEntryGroups = {}
|
||||
for group, entries of @entryGroups
|
||||
@entryGroups[group] = _.groupBy entries, (entry, i) -> Math.floor i / N_ROWS
|
||||
@entryGroupSlugs[group] = _.string.slugify group
|
||||
@entryGroupNames[group] = group
|
||||
iOSEntryGroups[group] = (entry.doc for entry in entries)
|
||||
if thisName = {coffeescript: '@', lua: 'self', clojure: 'self'}[@options.language]
|
||||
if @entryGroupNames.this
|
||||
@entryGroupNames.this = thisName
|
||||
iOSEntryGroups[thisName] = iOSEntryGroups.this
|
||||
delete iOSEntryGroups.this
|
||||
Backbone.Mediator.publish 'tome:palette-updated', thangID: @thang.id, entryGroups: JSON.stringify(iOSEntryGroups) # TODO: make it sort these by granting items if it's a hero level
|
||||
|
||||
addEntry: (doc, shortenize, tabbify, isSnippet=false) ->
|
||||
organizePaletteHero: (propStorage, allDocs, excludedDocs) ->
|
||||
# Assign any kind of programmable properties to the items that grant them.
|
||||
@isHero = true
|
||||
itemThangTypes = {}
|
||||
itemThangTypes[tt.get('name')] = tt for tt in @supermodel.getModels ThangType
|
||||
propsByItem = {}
|
||||
propCount = 0
|
||||
itemsByProp = {}
|
||||
for slot, inventoryID of @thang.inventoryIDs ? {}
|
||||
if item = itemThangTypes[inventoryID]
|
||||
for component in item.get('components') when component.config
|
||||
for owner, storages of propStorage
|
||||
if props = component.config[storages]
|
||||
for prop in _.sortBy(props) when prop[0] isnt '_' # no private properties
|
||||
propsByItem[item.get('name')] ?= []
|
||||
propsByItem[item.get('name')].push owner: owner, prop: prop, item: item
|
||||
itemsByProp[prop] = item
|
||||
++propCount
|
||||
else
|
||||
console.log @thang.id, "couldn't find item ThangType for", slot, inventoryID
|
||||
|
||||
# Assign any unassigned properties to the hero itself.
|
||||
for owner, storage of propStorage
|
||||
for prop in _.reject(@thang[storage] ? [], (prop) -> itemsByProp[prop] or prop[0] is '_') # no private properties
|
||||
propsByItem['Hero'] ?= []
|
||||
propsByItem['Hero'].push owner: owner, prop: prop, item: null
|
||||
++propCount
|
||||
|
||||
Backbone.Mediator.publish 'tome:update-snippets', propGroups: propsByItem, allDocs: allDocs, language: @options.language
|
||||
|
||||
shortenize = propCount > 6
|
||||
@entries = []
|
||||
for itemName, props of propsByItem
|
||||
for prop, propIndex in props
|
||||
item = prop.item
|
||||
owner = prop.owner
|
||||
prop = prop.prop
|
||||
doc = _.find (allDocs['__' + prop] ? []), (doc) ->
|
||||
return true if doc.owner is owner
|
||||
return (owner is 'this' or owner is 'more') and (not doc.owner? or doc.owner is 'this')
|
||||
if not doc and not excludedDocs['__' + prop]
|
||||
console.log 'could not find doc for', prop, 'from', allDocs['__' + prop], 'for', owner, 'of', propGroups, 'with item', item
|
||||
doc ?= prop
|
||||
if doc
|
||||
@entries.push @addEntry(doc, shortenize, false, owner is 'snippets', item, propIndex > 0)
|
||||
@entryGroups = _.groupBy @entries, (entry) -> itemsByProp[entry.doc.name]?.get('name') ? 'Hero'
|
||||
iOSEntryGroups = {}
|
||||
for group, entries of @entryGroups
|
||||
iOSEntryGroups[group] = (entry.doc for entry in entries)
|
||||
Backbone.Mediator.publish 'tome:palette-updated', thangID: @thang.id, entryGroups: JSON.stringify(iOSEntryGroups)
|
||||
|
||||
addEntry: (doc, shortenize, tabbify, isSnippet=false, item=null, showImage=false) ->
|
||||
writable = (if _.isString(doc) then doc else doc.name) in (@thang.apiUserProperties ? [])
|
||||
new SpellPaletteEntryView doc: doc, thang: @thang, shortenize: shortenize, tabbify: tabbify, isSnippet: isSnippet, language: @options.language, writable: writable, level: @options.level
|
||||
new SpellPaletteEntryView doc: doc, thang: @thang, shortenize: shortenize, tabbify: tabbify, isSnippet: isSnippet, language: @options.language, writable: writable, level: @options.level, item: item, showImage: showImage
|
||||
|
||||
onDisableControls: (e) -> @toggleControls e, false
|
||||
onEnableControls: (e) -> @toggleControls e, true
|
||||
|
@ -181,4 +266,5 @@ module.exports = class SpellPaletteView extends CocoView
|
|||
destroy: ->
|
||||
entry.destroy() for entry in @entries
|
||||
@toggleBackground = null
|
||||
$(window).off 'resize', @onResize
|
||||
super()
|
||||
|
|
|
@ -65,6 +65,7 @@ module.exports = class SpellView extends CocoView
|
|||
@problems = []
|
||||
@writable = false unless me.team in @spell.permissions.readwrite # TODO: make this do anything
|
||||
@highlightCurrentLine = _.throttle @highlightCurrentLine, 100
|
||||
$(window).on 'resize', @onWindowResize
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
|
@ -208,8 +209,13 @@ module.exports = class SpellView extends CocoView
|
|||
addZatannaSnippets: (e) ->
|
||||
return unless @zatanna and @autocomplete
|
||||
snippetEntries = []
|
||||
for owner, props of e.propGroups
|
||||
for group, props of e.propGroups
|
||||
for prop in props
|
||||
if _.isString prop # organizePalette
|
||||
owner = group
|
||||
else # organizePaletteHero
|
||||
owner = prop.owner
|
||||
prop = prop.prop
|
||||
doc = _.find (e.allDocs['__' + prop] ? []), (doc) ->
|
||||
return true if doc.owner is owner
|
||||
return (owner is 'this' or owner is 'more') and (not doc.owner? or doc.owner is 'this')
|
||||
|
@ -281,6 +287,8 @@ module.exports = class SpellView extends CocoView
|
|||
|
||||
setThang: (thang) ->
|
||||
@focus()
|
||||
@lastScreenLineCount = null
|
||||
@updateLines()
|
||||
return if thang.id is @thang?.id
|
||||
@thang = thang
|
||||
@spellThang = @spell.thangs[@thang.id]
|
||||
|
@ -305,6 +313,31 @@ module.exports = class SpellView extends CocoView
|
|||
return if @aceDoc.undergoingFirepadOperation # from my Firepad ACE adapter
|
||||
Backbone.Mediator.publish 'tome:editing-began', {}
|
||||
|
||||
updateLines: =>
|
||||
# Make sure there are always blank lines for the player to type on, and that the editor resizes to the height of the lines.
|
||||
lineCount = @aceDoc.getLength()
|
||||
lastLine = @aceDoc.$lines[lineCount - 1]
|
||||
if lastLine isnt ''
|
||||
cursorPosition = @ace.getCursorPosition()
|
||||
wasAtEnd = cursorPosition.row is lineCount - 1 and cursorPosition.column is lastLine.length
|
||||
@aceDoc.insertNewLine row: lineCount, column: 0 #lastLine.length
|
||||
@ace.navigateLeft(1) if wasAtEnd
|
||||
++lineCount
|
||||
screenLineCount = @aceSession.getScreenLength()
|
||||
if screenLineCount isnt @lastScreenLineCount
|
||||
@lastScreenLineCount = screenLineCount
|
||||
lineHeight = @ace.renderer.lineHeight or 20
|
||||
tomeHeight = $('#tome-view').innerHeight()
|
||||
spellListTabEntryHeight = $('#spell-list-tab-entry-view').outerHeight()
|
||||
spellToolbarHeight = $('.spell-toolbar-view').outerHeight()
|
||||
spellPaletteHeight = $('#spell-palette-view').outerHeight()
|
||||
maxHeight = tomeHeight - spellListTabEntryHeight - spellToolbarHeight - spellPaletteHeight
|
||||
linesAtMaxHeight = Math.floor(maxHeight / lineHeight)
|
||||
lines = Math.max 8, Math.min(screenLineCount + 4, linesAtMaxHeight)
|
||||
# 2 lines buffer is nice, but 4 leaves room to put problem alerts.
|
||||
@ace.setOptions minLines: lines, maxLines: lines
|
||||
$('#spell-palette-view').css('top', 38 + 45 + lineHeight * lines) # Move spell palette up, slightly underlapping us.
|
||||
|
||||
onManualCast: (e) ->
|
||||
cast = @$el.parent().length
|
||||
@recompile cast, e.realTime
|
||||
|
@ -361,14 +394,16 @@ module.exports = class SpellView extends CocoView
|
|||
_.debounce @notifyEditingEnded, 1000
|
||||
_.throttle @notifyEditingBegan, 250
|
||||
_.throttle @notifySpellChanged, 300
|
||||
_.throttle @updateLines, 500
|
||||
]
|
||||
@onCodeChangeMetaHandler = =>
|
||||
return if @eventsSuppressed
|
||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'code-change', volume: 0.5
|
||||
@spell.hasChangedSignificantly @getSource(), @spellThang.aether.raw, (hasChanged) =>
|
||||
if not @spellThang or hasChanged
|
||||
callback() for callback in onSignificantChange # Do these first
|
||||
callback() for callback in onAnyChange # Then these
|
||||
if @spellThang
|
||||
@spell.hasChangedSignificantly @getSource(), @spellThang.aether.raw, (hasChanged) =>
|
||||
if not @spellThang or hasChanged
|
||||
callback() for callback in onSignificantChange # Do these first
|
||||
callback() for callback in onAnyChange # Then these
|
||||
@aceDoc.on 'change', @onCodeChangeMetaHandler
|
||||
|
||||
setRecompileNeeded: (@recompileNeeded) =>
|
||||
|
@ -695,7 +730,15 @@ module.exports = class SpellView extends CocoView
|
|||
@ace.setValue pretty
|
||||
|
||||
onMaximizeToggled: (e) ->
|
||||
_.delay (=> @ace?.resize true), 500 # Wait $level-resize-transition-time.
|
||||
_.delay (=> @resize()), 500 + 100 # Wait $level-resize-transition-time, plus a bit.
|
||||
|
||||
onWindowResize: (e) =>
|
||||
_.delay (=> @resize?()), 500 + 100 # Wait $level-resize-transition-time, plus a bit.
|
||||
|
||||
resize: ->
|
||||
@ace?.resize true
|
||||
@lastScreenLineCount = null
|
||||
@updateLines()
|
||||
|
||||
onChangeEditorConfig: (e) ->
|
||||
aceConfig = me.get('aceConfig') ? {}
|
||||
|
@ -739,4 +782,5 @@ module.exports = class SpellView extends CocoView
|
|||
@aceSession?.selection.off 'changeCursor', @onCursorActivity
|
||||
@destroyAceEditor(@ace)
|
||||
@debugView?.destroy()
|
||||
$(window).off 'resize', @onWindowResize
|
||||
super()
|
||||
|
|
|
@ -181,6 +181,7 @@ module.exports = class TomeView extends CocoView
|
|||
@spellTabView = null
|
||||
@removeSubView @spellPaletteView if @spellPaletteView
|
||||
@spellPaletteView = null
|
||||
@$el.find('#spell-palette-view').hide()
|
||||
@castButton?.$el.hide()
|
||||
@thangList?.$el.show()
|
||||
|
||||
|
@ -204,10 +205,10 @@ module.exports = class TomeView extends CocoView
|
|||
@castButton.attachTo @spellView
|
||||
@thangList?.$el.hide()
|
||||
Backbone.Mediator.publish 'tome:spell-shown', thang: thang, spell: spell
|
||||
@updateSpellPalette thang, spell
|
||||
@spellList.setThangAndSpell thang, spell
|
||||
@spellView?.setThang thang
|
||||
@spellTabView?.setThang thang
|
||||
@updateSpellPalette thang, spell
|
||||
|
||||
updateSpellPalette: (thang, spell) ->
|
||||
return unless thang and @spellPaletteView?.thang isnt thang and thang.programmableProperties or thang.apiProperties
|
||||
|
|
|
@ -48,9 +48,8 @@ module.exports = class AchievementsView extends UserView
|
|||
# After user is loaded
|
||||
if @user and not @user.isAnonymous()
|
||||
context.earnedAchievements = @earnedAchievements
|
||||
context.achievements = @achievements
|
||||
context.achievementsByCategory = {}
|
||||
for achievement in @achievements.models
|
||||
for achievement in @achievements.models when achievement.get('category')
|
||||
context.achievementsByCategory[achievement.get('category')] ?= []
|
||||
context.achievementsByCategory[achievement.get('category')].push achievement
|
||||
context
|
||||
|
|
|
@ -30,6 +30,7 @@ module.exports = class JobProfileView extends UserView
|
|||
id: 'profile-view'
|
||||
template: template
|
||||
showBackground: false
|
||||
usesSocialMedia: true
|
||||
|
||||
subscriptions:
|
||||
'auth:linkedin-api-loaded': 'onLinkedInLoaded'
|
||||
|
|
Loading…
Reference in a new issue