Merge branch 'master' into production

This commit is contained in:
Nick Winter 2014-04-27 13:20:21 -07:00
commit 14f2fd260e
8 changed files with 114 additions and 89 deletions

View file

@ -32,7 +32,7 @@ module.exports = class Simulator extends CocoClass
@simulateAnotherTaskAfterDelay() @simulateAnotherTaskAfterDelay()
handleNoGamesResponse: -> handleNoGamesResponse: ->
@trigger 'statusUpdate', 'There were no games to simulate--nice. Retrying in 10 seconds.' @trigger 'statusUpdate', 'There were no games to simulate--all simulations are done or in process. Retrying in 10 seconds.'
@simulateAnotherTaskAfterDelay() @simulateAnotherTaskAfterDelay()
simulateAnotherTaskAfterDelay: => simulateAnotherTaskAfterDelay: =>
@ -257,7 +257,7 @@ class SimulationTask
@spellKeyToTeamMap = {} @spellKeyToTeamMap = {}
getLevelName: -> getLevelName: ->
levelName = @rawData.sessions?[0]?.levelID levelName = @rawData.sessions?[0]?.levelID
return levelName if levelName? return levelName if levelName?
@throwMalformedTaskError "The level name couldn't be deduced from the task." @throwMalformedTaskError "The level name couldn't be deduced from the task."

View file

@ -3,29 +3,29 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
loading: "Chargement..." loading: "Chargement..."
saving: "Sauvegarde..." saving: "Sauvegarde..."
sending: "Envoi..." sending: "Envoi..."
# send: "Send" send: "Envoyer"
cancel: "Annuler" cancel: "Annuler"
save: "Sauvegarder" save: "Sauvegarder"
# publish: "Publish" publish: "Publier"
# create: "Create" create: "Creer"
delay_1_sec: "1 seconde" delay_1_sec: "1 seconde"
delay_3_sec: "3 secondes" delay_3_sec: "3 secondes"
delay_5_sec: "5 secondes" delay_5_sec: "5 secondes"
manual: "Manuel" manual: "Manuel"
fork: "Fork" fork: "Fork"
play: "Jouer" play: "Jouer"
# retry: "Retry" retry: "Reessayer"
# watch: "Watch" watch: "Regarder"
# unwatch: "Unwatch" # unwatch: "Unwatch"
# submit_patch: "Submit Patch" # submit_patch: "Submit Patch"
# units: units:
# second: "second" second: "seconde"
# seconds: "seconds" seconds: "secondes"
# minute: "minute" minute: "minute"
# minutes: "minutes" minutes: "minutes"
# hour: "hour" hour: "heure"
# hours: "hours" hours: "heures"
modal: modal:
close: "Fermer" close: "Fermer"
@ -39,7 +39,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
editor: "Éditeur" editor: "Éditeur"
blog: "Blog" blog: "Blog"
forum: "Forum" forum: "Forum"
# account: "Account" account: "Compte"
admin: "Admin" admin: "Admin"
home: "Accueil" home: "Accueil"
contribute: "Contribuer" contribute: "Contribuer"
@ -60,7 +60,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
login: login:
sign_up: "Créer un compte" sign_up: "Créer un compte"
log_in: "Connexion" log_in: "Connexion"
# logging_in: "Logging In" logging_in: "Connecter"
log_out: "Déconnexion" log_out: "Déconnexion"
recover: "récupérer son compte" recover: "récupérer son compte"
@ -77,7 +77,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
creating: "Création du compte en cours..." creating: "Création du compte en cours..."
sign_up: "S'abonner" sign_up: "S'abonner"
log_in: "se connecter avec votre mot de passe" log_in: "se connecter avec votre mot de passe"
# social_signup: "Or, you can sign up through Facebook or G+:" social_signup: "Ou, vous pouvez vous identifier avec Facecook ou G+:"
home: home:
slogan: "Apprenez à coder en JavaScript tout en jouant" slogan: "Apprenez à coder en JavaScript tout en jouant"
@ -133,12 +133,12 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
title: "Paramètres du Magicien" title: "Paramètres du Magicien"
customize_avatar: "Personnaliser votre avatar" customize_avatar: "Personnaliser votre avatar"
# active: "Active" # active: "Active"
# color: "Color" color: "Couleur"
# group: "Group" group: "Groupe"
clothes: "Vêtements" clothes: "Vêtements"
trim: "Tailleur" trim: "Tailleur"
cloud: "Nuage" cloud: "Nuage"
# team: "Team" team: "Equipe"
spell: "Sort" spell: "Sort"
boots: "Bottes" boots: "Bottes"
hue: "Teinte" hue: "Teinte"
@ -175,7 +175,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
# 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_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_explanation: "Hi! Fill this out, and we will get in touch about finding you a software developer job."
# sample_profile: "See a sample profile" # sample_profile: "See a sample profile"
# view_profile: "View Your Profile" view_profile: "Voir votre profile"
account_profile: account_profile:
edit_settings: "Éditer les préférences" edit_settings: "Éditer les préférences"
@ -183,10 +183,10 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
profile_for_suffix: "" profile_for_suffix: ""
# approved: "Approved" # approved: "Approved"
# not_approved: "Not Approved" # not_approved: "Not Approved"
# looking_for: "Looking for:" looking_for: "à la recherche de:"
# last_updated: "Last updated:" last_updated: "Last Mise à jour:"
# contact: "Contact" # contact: "Contact"
# work_experience: "Work Experience" work_experience: "Experience de travail"
# education: "Education" # education: "Education"
# our_notes: "Our Notes" # our_notes: "Our Notes"
# projects: "Projects" # projects: "Projects"
@ -256,8 +256,8 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
skip_tutorial: "Passer (esc)" skip_tutorial: "Passer (esc)"
editor_config: "Config de l'éditeur" editor_config: "Config de l'éditeur"
editor_config_title: "Configuration de l'éditeur" editor_config_title: "Configuration de l'éditeur"
# editor_config_language_label: "Programming Language" editor_config_language_label: "Langage de programmation"
# editor_config_language_description: "Define the programming language you want to code in." editor_config_language_description: "Définissez le langage de programmation avec lequel vous voulez coder."
editor_config_keybindings_label: "Raccourcis clavier" editor_config_keybindings_label: "Raccourcis clavier"
editor_config_keybindings_default: "Par défault (Ace)" editor_config_keybindings_default: "Par défault (Ace)"
editor_config_keybindings_description: "Ajouter de nouveaux raccourcis connus depuis l'éditeur commun." editor_config_keybindings_description: "Ajouter de nouveaux raccourcis connus depuis l'éditeur commun."
@ -267,21 +267,21 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
editor_config_indentguides_description: "Affiche des guides verticaux qui permettent de visualiser l'indentation." editor_config_indentguides_description: "Affiche des guides verticaux qui permettent de visualiser l'indentation."
editor_config_behaviors_label: "Auto-complétion" editor_config_behaviors_label: "Auto-complétion"
editor_config_behaviors_description: "Ferme automatiquement les accolades, parenthèses, et chaînes de caractères." editor_config_behaviors_description: "Ferme automatiquement les accolades, parenthèses, et chaînes de caractères."
# loading_ready: "Ready!" loading_ready: "Pret!"
# tip_insert_positions: "Shift+Click a point on the map to insert it into the spell editor." # 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_toggle_play: "Jouer/Pause avec Ctrl+P."
# tip_scrub_shortcut: "Ctrl+[ and Ctrl+] rewind and fast-forward." # 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_guide_exists: "Click the guide at the top of the page for useful info."
# tip_open_source: "CodeCombat is 100% open source!" tip_open_source: "CodeCombat est 100% open source!"
# tip_beta_launch: "CodeCombat launched its beta in October, 2013." # tip_beta_launch: "CodeCombat launched its beta in October, 2013."
# tip_js_beginning: "JavaScript is just the beginning." tip_js_beginning: "JavaScript n'est que le commencement."
# tip_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button." # tip_autocast_setting: "Adjust autocast settings by clicking the gear on the cast button."
# think_solution: "Think of the solution, not the problem." think_solution: "Reflechissez a propos de la solution et non du problème."
# tip_theory_practice: "In theory, there is no difference between theory and practice. But in practice, there is. - Yogi Berra" tip_theory_practice: "En théorie, il n'y a pas de différence entre la théorie et la pratique. Mais en pratique il y en a. - Yogi Berra"
# tip_error_free: "There are two ways to write error-free programs; only the third one works. - Alan Perlis" # 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_debugging_program: "Si débugger est l'art de corriger les bugs, alors programmer est l'art d'en créer. . - Edsger W. Dijkstra"
# tip_forums: "Head over to the forums and tell us what you think!" # 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_baby_coders: "Dans le futur, même les bébés seront des archimages."
# tip_morale_improves: "Loading will continue until morale improves." # tip_morale_improves: "Loading will continue until morale improves."
# tip_all_species: "We believe in equal opportunities to learn programming for all species." # tip_all_species: "We believe in equal opportunities to learn programming for all species."
# tip_reticulating: "Reticulating spines." # tip_reticulating: "Reticulating spines."
@ -296,12 +296,12 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
# tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" # 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_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_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay"
# time_current: "Now:" time_current: "Maintenant:"
# time_total: "Max:" # time_total: "Max:"
# time_goto: "Go to:" # time_goto: "Go to:"
# infinite_loop_try_again: "Try Again" infinite_loop_try_again: "Reessayer"
# infinite_loop_reset_level: "Reset Level" infinite_loop_reset_level: "Redemarrer le niveau"
# infinite_loop_comment_out: "Comment Out My Code" infinite_loop_comment_out: "Supprimez les commentaire de mon code"
admin: admin:
av_title: "Vues d'administrateurs" av_title: "Vues d'administrateurs"
@ -339,7 +339,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
revert_models: "Annuler les modèles" revert_models: "Annuler les modèles"
# fork_title: "Fork New Version" # fork_title: "Fork New Version"
# fork_creating: "Creating Fork..." # fork_creating: "Creating Fork..."
# more: "More" more: "Plus"
# wiki: "Wiki" # wiki: "Wiki"
# live_chat: "Live Chat" # live_chat: "Live Chat"
level_some_options: "Quelques options?" level_some_options: "Quelques options?"
@ -349,11 +349,11 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
level_tab_components: "Composants" level_tab_components: "Composants"
level_tab_systems: "Systèmes" level_tab_systems: "Systèmes"
level_tab_thangs_title: "Thangs actuels" level_tab_thangs_title: "Thangs actuels"
# level_tab_thangs_all: "All" level_tab_thangs_all: "Tout"
level_tab_thangs_conditions: "Conditions de départ" level_tab_thangs_conditions: "Conditions de départ"
level_tab_thangs_add: "ajouter des Thangs" level_tab_thangs_add: "ajouter des Thangs"
# delete: "Delete" delete: "Supprimer"
# duplicate: "Duplicate" duplicate: "Dupliquer"
level_settings_title: "Paramètres" level_settings_title: "Paramètres"
level_component_tab_title: "Composants actuels" level_component_tab_title: "Composants actuels"
level_component_btn_new: "Créer un nouveau composant" level_component_btn_new: "Créer un nouveau composant"
@ -372,13 +372,13 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
new_article_title: "Créer un nouvel article" new_article_title: "Créer un nouvel article"
new_thang_title: "Créer un nouveau Type Thang" new_thang_title: "Créer un nouveau Type Thang"
new_level_title: "Créer un nouveau niveau" new_level_title: "Créer un nouveau niveau"
# new_article_title_signup: "Sign Up to Create a New Article" new_article_title_signup: "Identifiez vous pour creer un nouvel article"
# new_thang_title_signup: "Sign Up to Create a New Thang Type" # new_thang_title_signup: "Sign Up to Create a New Thang Type"
# new_level_title_signup: "Sign Up to Create a New Level" new_level_title_signup: "Identifiez vous pour créer un Nouveau niveau"
article_search_title: "Rechercher dans les articles" article_search_title: "Rechercher dans les articles"
thang_search_title: "Rechercher dans les types Thang" thang_search_title: "Rechercher dans les types Thang"
level_search_title: "Rechercher dans les niveaux" level_search_title: "Rechercher dans les niveaux"
# read_only_warning2: "Note: you can't save any edits here, because you're not logged in." read_only_warning2: "Note: vous ne pouvez sauvegarder aucune édition, car vous n'êtes pas identifié."
article: article:
edit_btn_preview: "Prévisualiser" edit_btn_preview: "Prévisualiser"
@ -500,7 +500,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
contribute: contribute:
page_title: "Contribution" page_title: "Contribution"
# character_classes_title: "Character Classes" character_classes_title: "Classes du personnage"
introduction_desc_intro: "Nous avons beaucoup d'espoir pour CodeCombat." introduction_desc_intro: "Nous avons beaucoup d'espoir pour CodeCombat."
introduction_desc_pref: "Nous voulons être l'endroit où les développeurs de tous horizons viennent pour apprendre et jouer ensemble, présenter les autres au monde du développement, et refléter le meilleur de la communauté. Nous ne pouvons et ne voulons pas faire ça seuls ; ce qui rend super les projets comme GitHub, Stack Overflow et Linux, est que les gens qui l'utilisent le construisent. Dans ce but, " introduction_desc_pref: "Nous voulons être l'endroit où les développeurs de tous horizons viennent pour apprendre et jouer ensemble, présenter les autres au monde du développement, et refléter le meilleur de la communauté. Nous ne pouvons et ne voulons pas faire ça seuls ; ce qui rend super les projets comme GitHub, Stack Overflow et Linux, est que les gens qui l'utilisent le construisent. Dans ce but, "
introduction_desc_github_url: "CodeCombat est totalement open source" introduction_desc_github_url: "CodeCombat est totalement open source"

View file

@ -14,6 +14,8 @@ block content
i.icon-cog i.icon-cog
span(data-i18n='account_profile.approved').approved Approved span(data-i18n='account_profile.approved').approved Approved
span(data-i18n='account_profile.not_approved').not-approved Not Approved span(data-i18n='account_profile.not_approved').not-approved Not Approved
if user.id != me.id
button.btn.edit-settings-button#enter-espionage-mode 007
if user.get('jobProfile') if user.get('jobProfile')
- var profile = user.get('jobProfile'); - var profile = user.get('jobProfile');

View file

@ -11,6 +11,7 @@ module.exports = class ProfileView extends View
'click #toggle-job-profile-approved': 'toggleJobProfileApproved' 'click #toggle-job-profile-approved': 'toggleJobProfileApproved'
'keyup #job-profile-notes': 'onJobProfileNotesChanged' 'keyup #job-profile-notes': 'onJobProfileNotesChanged'
'click #contact-candidate': 'onContactCandidate' 'click #contact-candidate': 'onContactCandidate'
'click #enter-espionage-mode': 'enterEspionageMode'
constructor: (options, @userID) -> constructor: (options, @userID) ->
@onJobProfileNotesChanged = _.debounce @onJobProfileNotesChanged, 1000 @onJobProfileNotesChanged = _.debounce @onJobProfileNotesChanged, 1000
@ -52,6 +53,17 @@ module.exports = class ProfileView extends View
@user.save() @user.save()
@updateProfileApproval() @updateProfileApproval()
enterEspionageMode: ->
postData = emailLower: @user.get('email').toLowerCase(), usernameLower: @user.get('name').toLowerCase()
$.ajax
type: "POST",
url: "/auth/spy"
data: postData
success: @espionageSuccess
espionageSuccess: (model) ->
window.location.reload()
onJobProfileNotesChanged: (e) => onJobProfileNotesChanged: (e) =>
notes = @$el.find("#job-profile-notes").val() notes = @$el.find("#job-profile-notes").val()
@user.set 'jobProfileNotes', notes @user.set 'jobProfileNotes', notes

View file

@ -1,7 +1,6 @@
{backboneFailure, genericFailure} = require 'lib/errors' {backboneFailure, genericFailure} = require 'lib/errors'
View = require 'views/kinds/RootView' View = require 'views/kinds/RootView'
template = require 'templates/admin' template = require 'templates/admin'
storage = require 'lib/storage'
module.exports = class AdminView extends View module.exports = class AdminView extends View
id: "admin-view" id: "admin-view"
@ -14,7 +13,6 @@ module.exports = class AdminView extends View
userEmail = $("#user-email").val().toLowerCase() userEmail = $("#user-email").val().toLowerCase()
username = $("#user-username").val().toLowerCase() username = $("#user-username").val().toLowerCase()
userIdentifier = userEmail || username
postData = postData =
usernameLower: username usernameLower: username
emailLower: userEmail emailLower: userEmail
@ -27,10 +25,7 @@ module.exports = class AdminView extends View
error: @espionageFailure error: @espionageFailure
espionageSuccess: (model) -> espionageSuccess: (model) ->
storage.save('whoami',model)
window.location.reload() window.location.reload()
espionageFailure: (jqxhr, status,error)-> espionageFailure: (jqxhr, status,error)->
console.log "There was an error entering espionage mode: #{error}" console.log "There was an error entering espionage mode: #{error}"

View file

@ -18,10 +18,11 @@ module.exports = class Spell
p = options.programmableMethod p = options.programmableMethod
@name = p.name @name = p.name
@source = @session.getSourceFor(@spellKey) ? p.source
@originalSource = p.source
@parameters = p.parameters
@permissions = read: p.permissions?.read ? [], readwrite: p.permissions?.readwrite ? [] # teams @permissions = read: p.permissions?.read ? [], readwrite: p.permissions?.readwrite ? [] # teams
@source = @originalSource = p.source
@parameters = p.parameters
if @permissions.readwrite.length and sessionSource = @session.getSourceFor(@spellKey)
@source = sessionSource
@thangs = {} @thangs = {}
@view = new SpellView {spell: @, session: @session, worker: @worker} @view = new SpellView {spell: @, session: @session, worker: @worker}
@view.render() # Get it ready and code loaded in advance @view.render() # Get it ready and code loaded in advance
@ -30,7 +31,6 @@ module.exports = class Spell
@team = @permissions.readwrite[0] ? "common" @team = @permissions.readwrite[0] ? "common"
Backbone.Mediator.publish 'tome:spell-created', spell: @ Backbone.Mediator.publish 'tome:spell-created', spell: @
destroy: -> destroy: ->
@view.destroy() @view.destroy()
@tabView.destroy() @tabView.destroy()

View file

@ -51,19 +51,24 @@ module.exports = class SpellPaletteView extends View
allDocs['__' + doc.name].push doc allDocs['__' + doc.name].push doc
if doc.type is 'snippet' then doc.owner = 'snippets' if doc.type is 'snippet' then doc.owner = 'snippets'
propStorage = if @options.programmable
'this': 'programmableProperties' propStorage =
more: 'moreProgrammableProperties' 'this': 'programmableProperties'
Math: 'programmableMathProperties' more: 'moreProgrammableProperties'
Array: 'programmableArrayProperties' Math: 'programmableMathProperties'
Object: 'programmableObjectProperties' Array: 'programmableArrayProperties'
String: 'programmableStringProperties' Object: 'programmableObjectProperties'
Vector: 'programmableVectorProperties' String: 'programmableStringProperties'
snippets: 'programmableSnippets' Vector: 'programmableVectorProperties'
snippets: 'programmableSnippets'
else
propStorage =
'this': 'apiProperties'
count = 0 count = 0
propGroups = {} propGroups = {}
for owner, storage of propStorage for owner, storage of propStorage
added = propGroups[owner] = _.sortBy(@thang[storage] ? []).slice() props = _.reject @thang[storage] ? [], (prop) -> prop[0] is '_' # no private properties
added = propGroups[owner] = _.sortBy(props).slice()
count += added.length count += added.length
shortenize = count > 6 shortenize = count > 6
@ -78,7 +83,7 @@ module.exports = class SpellPaletteView extends View
doc ?= prop doc ?= prop
@entries.push @addEntry(doc, shortenize, tabbify, owner is 'snippets') @entries.push @addEntry(doc, shortenize, tabbify, owner is 'snippets')
groupForEntry = (entry) -> groupForEntry = (entry) ->
return 'more' if entry.doc.owner is 'this' and entry.doc.name in propGroups.more return 'more' if entry.doc.owner is 'this' and entry.doc.name in (propGroups.more ? [])
entry.doc.owner entry.doc.owner
@entries = _.sortBy @entries, (entry) -> @entries = _.sortBy @entries, (entry) ->
order = ['this', 'more', 'Math', 'Vector', 'snippets'] order = ['this', 'more', 'Math', 'Vector', 'snippets']

View file

@ -178,14 +178,12 @@ module.exports = class TomeView extends View
thang = e.thang thang = e.thang
spellName = e.spellName spellName = e.spellName
@spellList?.$el.hide() @spellList?.$el.hide()
return @clearSpellView() unless thang?.isProgrammable return @clearSpellView() unless thang
selectedThangSpells = (@spells[spellKey] for spellKey in @thangSpells[thang.id]) spell = @spellFor thang, spellName
if spellName unless spell?.canRead()
spell = _.find selectedThangSpells, {name: spellName} @clearSpellView()
else @updateSpellPalette thang, spell
spell = @thangList.topSpellForThang thang return
#spell = selectedThangSpells[0] # TODO: remember last selected spell for this thang
return @clearSpellView() unless spell?.canRead()
unless spell.view is @spellView unless spell.view is @spellView
@clearSpellView() @clearSpellView()
@spellView = spell.view @spellView = spell.view
@ -198,9 +196,22 @@ module.exports = class TomeView extends View
@spellList.setThangAndSpell thang, spell @spellList.setThangAndSpell thang, spell
@spellView?.setThang thang @spellView?.setThang thang
@spellTabView?.setThang thang @spellTabView?.setThang thang
if @spellPaletteView?.thang isnt thang @updateSpellPalette thang, spell
@spellPaletteView = @insertSubView new SpellPaletteView thang: thang, supermodel: @supermodel
@spellPaletteView.toggleControls {}, spell.view.controlsEnabled # TODO: know when palette should have been disabled but didn't exist updateSpellPalette: (thang, spell) ->
return unless thang and @spellPaletteView?.thang isnt thang and thang.programmableProperties or thang.apiProperties
@spellPaletteView = @insertSubView new SpellPaletteView thang: thang, supermodel: @supermodel, programmable: spell?.canRead()
@spellPaletteView.toggleControls {}, spell.view.controlsEnabled if spell # TODO: know when palette should have been disabled but didn't exist
spellFor: (thang, spellName) ->
return null unless thang?.isProgrammable
selectedThangSpells = (@spells[spellKey] for spellKey in @thangSpells[thang.id])
if spellName
spell = _.find selectedThangSpells, {name: spellName}
else
spell = @thangList.topSpellForThang thang
#spell = selectedThangSpells[0] # TODO: remember last selected spell for this thang
spell
reloadAllCode: -> reloadAllCode: ->
spell.view.reloadCode false for spellKey, spell of @spells when spell.team is me.team or (spell.team in ["common", "neutral", null]) spell.view.reloadCode false for spellKey, spell of @spells when spell.team is me.team or (spell.team in ["common", "neutral", null])