mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-03-27 21:31:16 -04:00
Work on the job profile view, initial work on the code modal.
This commit is contained in:
parent
51e63ddbc3
commit
45a8278e7e
12 changed files with 422 additions and 339 deletions
app
schemas/models
styles/common
templates
views
server/users
test/demo/views
|
@ -230,6 +230,7 @@ _.extend LevelSchema.properties,
|
|||
title: 'Next Level',
|
||||
description: 'Reference to the next level players will play after beating this one.'
|
||||
}
|
||||
employerDescription: { type:'string' }
|
||||
scripts: c.array {title: 'Scripts', description: 'An array of scripts that trigger based on what the player does and affect things outside of the core level simulation.', 'default': []}, ScriptSchema
|
||||
thangs: c.array {title: 'Thangs', description: 'An array of Thangs that make up the level.', 'default': []}, LevelThangSchema
|
||||
systems: c.array {title: 'Systems', description: 'Levels are configured by changing the Systems attached to them.', uniqueItems: true, default: []}, LevelSystemSchema # TODO: uniqueness should be based on 'original', not whole thing
|
||||
|
|
|
@ -13,7 +13,7 @@ LevelSessionPlayerSchema = c.object
|
|||
changes:
|
||||
type: 'Number'
|
||||
|
||||
LevelSessionLevelSchema = c.object {required: ['original', 'majorVersion']},
|
||||
LevelSessionLevelSchema = c.object {required: ['original', 'majorVersion'], links: [{rel: 'db', href: '/db/level/{(original)}/version/{(majorVersion)}'}]},
|
||||
original: c.objectId({})
|
||||
majorVersion:
|
||||
type: 'integer'
|
||||
|
|
19
app/styles/common/level_session_code_view.sass
Normal file
19
app/styles/common/level_session_code_view.sass
Normal file
|
@ -0,0 +1,19 @@
|
|||
.level-session-code-view
|
||||
#level-icon
|
||||
width: 100px
|
||||
margin-right: 10px
|
||||
display: inline-block
|
||||
float: left
|
||||
|
||||
#level-meta-data
|
||||
margin-left: 120px
|
||||
|
||||
#session-code
|
||||
clear: both
|
||||
|
||||
h3
|
||||
font-family: Arial
|
||||
|
||||
.code
|
||||
height: 600px
|
||||
border: 2px solid black
|
13
app/templates/account/job_profile_code_modal.jade
Normal file
13
app/templates/account/job_profile_code_modal.jade
Normal file
|
@ -0,0 +1,13 @@
|
|||
extends /templates/modal/modal_base
|
||||
|
||||
block modal-header-content
|
||||
.modal-header
|
||||
h3 Applicant Code
|
||||
|
||||
block modal-body-content
|
||||
.modal-body
|
||||
.level-session-code-view
|
||||
|
||||
block modal-footer
|
||||
.modal-footer
|
||||
button(data-dismiss="modal", data-i18n="modal.close").btn Close
|
|
@ -181,13 +181,14 @@ block content
|
|||
ul.sessions
|
||||
each session in sessions
|
||||
li
|
||||
- var sessionLink = "/play/level/" + session.levelID + "?team=" + (session.team || 'humans') + (myProfile ? '' : "&session=" + session._id);
|
||||
a(href=sessionLink)
|
||||
span= session.levelName
|
||||
if session.team
|
||||
span #{session.team}
|
||||
if session.codeLanguage != 'javascript'
|
||||
span - #{{coffeescript: 'CoffeeScript', python: 'Python', lua: 'Lua', io: 'Io', clojure: 'Clojure'}[session.codeLanguage]}
|
||||
span.session-link(data-session-id=session._id)= session.levelName
|
||||
//- var sessionLink = "/play/level/" + session.levelID + "?team=" + (session.team || 'humans') + (myProfile ? '' : "&session=" + session._id);
|
||||
//a(href=sessionLink)
|
||||
// span= session.levelName
|
||||
// if session.team
|
||||
// span #{session.team}
|
||||
//if session.codeLanguage != 'javascript'
|
||||
// span - #{{coffeescript: 'CoffeeScript', python: 'Python', lua: 'Lua', io: 'Io', clojure: 'Clojure'}[session.codeLanguage]}
|
||||
|
||||
.middle-column.full-height-column
|
||||
.sub-column
|
||||
|
|
13
app/templates/common/level_session_code.jade
Normal file
13
app/templates/common/level_session_code.jade
Normal file
|
@ -0,0 +1,13 @@
|
|||
div#session-info
|
||||
img(src='/file/'+levelIcon alt='levelIcon')#level-icon
|
||||
div#level-meta-data
|
||||
strong= levelName
|
||||
p!= levelDescription
|
||||
|
||||
div#session-code
|
||||
for spell in levelSpells
|
||||
.panel.panel-success
|
||||
.panel-heading
|
||||
h3= spell.name
|
||||
.panel-body
|
||||
.code= spell.code
|
19
app/views/account/JobProfileCodeModal.coffee
Normal file
19
app/views/account/JobProfileCodeModal.coffee
Normal file
|
@ -0,0 +1,19 @@
|
|||
ModalView = require 'views/kinds/ModalView'
|
||||
template = require 'templates/account/job_profile_code_modal'
|
||||
LevelSessionCodeView = require 'views/common/LevelSessionCodeView'
|
||||
console.log 'template', template
|
||||
|
||||
module.exports = class JobProfileCodeModal extends ModalView
|
||||
id: 'job_profile_code_modal'
|
||||
template: template
|
||||
|
||||
constructor: (options) ->
|
||||
super(arguments...)
|
||||
@session = options.session
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
return unless @session.loaded
|
||||
codeView = new LevelSessionCodeView({session:@session})
|
||||
@insertSubView(codeView)
|
||||
|
|
@ -9,6 +9,7 @@ JobProfileView = require 'views/account/job_profile_view'
|
|||
UserRemark = require 'models/UserRemark'
|
||||
forms = require 'lib/forms'
|
||||
ModelModal = require 'views/modal/model_modal'
|
||||
JobProfileCodeModal = require './JobProfileCodeModal'
|
||||
|
||||
class LevelSessionsCollection extends CocoCollection
|
||||
url: -> "/db/user/#{@userID}/level.sessions/employer"
|
||||
|
@ -51,6 +52,7 @@ module.exports = class ProfileView extends RootView
|
|||
'keyup .editable-profile .editable-array input': 'onEditArray'
|
||||
'click .editable-profile a': 'onClickLinkWhileEditing'
|
||||
'change #admin-contact': 'onAdminContactChanged'
|
||||
'click .session-link': 'onSessionLinkPressed'
|
||||
|
||||
constructor: (options, @userID) ->
|
||||
@userID ?= me.id
|
||||
|
@ -586,3 +588,9 @@ module.exports = class ProfileView extends RootView
|
|||
{name: t('account_profile.next_photo'), weight: 2, container: '#profile-photo-container', fn: modified 'photoURL'}
|
||||
{name: t('account_profile.next_active'), weight: 1, fn: modified 'active'}
|
||||
]
|
||||
|
||||
onSessionLinkPressed: (e) ->
|
||||
sessionID = $(e.target).data('session-id')
|
||||
session = _.find @sessions.models, (session) -> session.id is sessionID
|
||||
modal = new JobProfileCodeModal({session:session})
|
||||
@openModalView modal
|
46
app/views/common/LevelSessionCodeView.coffee
Normal file
46
app/views/common/LevelSessionCodeView.coffee
Normal file
|
@ -0,0 +1,46 @@
|
|||
CocoView = require 'views/kinds/CocoView'
|
||||
template = require 'templates/common/level_session_code'
|
||||
|
||||
Level = require 'models/Level'
|
||||
LevelSession = require 'models/LevelSession'
|
||||
|
||||
module.exports = class LevelSessionCodeView extends CocoView
|
||||
className: 'level-session-code-view'
|
||||
template: template
|
||||
modalWidthPercent: 80
|
||||
plain: true
|
||||
|
||||
constructor: (options) ->
|
||||
super(options)
|
||||
@session = options.session
|
||||
@level = LevelSession.getReferencedModel(@session.get('level'), LevelSession.schema.properties.level)
|
||||
@level.setProjection ['employerDescription', 'name', 'icon']
|
||||
@supermodel.loadModel @level, 'level'
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
c.levelIcon = @level.get('icon')
|
||||
c.levelName = @level.get('name')
|
||||
c.levelDescription = marked(@level.get('employerDescription') or '')
|
||||
c.levelSpells = @organizeCode()
|
||||
c
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
@$el.find('.code').each (index, codeEl) ->
|
||||
editor = ace.edit codeEl
|
||||
editor.setReadOnly true
|
||||
aceSession = editor.getSession()
|
||||
aceSession.setMode 'ace/mode/javascript'
|
||||
|
||||
organizeCode: ->
|
||||
team = @session.get('team') or 'humans'
|
||||
teamSpells = @session.get('teamSpells')[team] or []
|
||||
filteredSpells = []
|
||||
for spell in teamSpells
|
||||
code = @session.getSourceFor(spell)
|
||||
filteredSpells.push {
|
||||
code: code
|
||||
name: spell.split('/')[1]
|
||||
}
|
||||
filteredSpells
|
|
@ -233,7 +233,7 @@ UserHandler = class UserHandler extends Handler
|
|||
getLevelSessionsForEmployer: (req, res, userID) ->
|
||||
return @sendUnauthorizedError(res) unless req.user._id+'' is userID or req.user.isAdmin() or ('employer' in req.user.get('permissions'))
|
||||
query = creator: userID, levelID: {$in: ['gridmancer', 'greed', 'dungeon-arena', 'brawlwood', 'gold-rush']}
|
||||
projection = 'levelName levelID team playtime codeLanguage submitted code totalScore'
|
||||
projection = 'levelName levelID team playtime codeLanguage submitted code totalScore teamSpells level'
|
||||
LevelSession.find(query).select(projection).exec (err, documents) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
documents = (LevelSessionHandler.formatEntity(req, doc) for doc in documents)
|
||||
|
|
65
test/demo/views/common/LevelSessionCodeView.demo.coffee
Normal file
65
test/demo/views/common/LevelSessionCodeView.demo.coffee
Normal file
|
@ -0,0 +1,65 @@
|
|||
LevelSessionCodeView = require 'views/common/LevelSessionCodeView'
|
||||
LevelSession = require 'models/LevelSession'
|
||||
|
||||
levelSessionData = {
|
||||
"_id": "5334901f0a0f9b286f57382c",
|
||||
"level": {
|
||||
"original": "533353722a61b7ca6832840c",
|
||||
"majorVersion": 0
|
||||
},
|
||||
"team": "humans",
|
||||
"code": {
|
||||
"coin-generator-9000": {
|
||||
"chooseAction": "var buildOrder = ['coin2', 'coin3', 'coin4'];\n//if (Math.random() < 0.25)\n// this.build(buildOrder[this.built.length % buildOrder.length]);\nif (Math.random() < 0.05)\n this.build('gem');\nelse if (Math.random() < 0.25)\n this.build(buildOrder[this.built.length % buildOrder.length])\nelse if (Math.random() < 0.5)\n this.build('coin');\n\n\n\nvar human = this.getThangByID(\"Tharin\");\nvar ogre = this.getThangByID(\"Mak Fod\");\n\n//this.say(human.gold);\n\n//this.say(\"Humans: \" + human.gold + \", \" + \"Ogres: \" + ogre.gold);\n\nif(ogre.gold >= 150) {\n this.say(\"Ogres win!\");\n this.setGoalState(\"goldOgres\", \"success\");\n}\n\nelse if(human.gold >= 150) {\n this.say(\"Humans win!\");\n this.setGoalState(\"goldHumans\", \"success\");\n}"
|
||||
},
|
||||
"programmable-coin": {
|
||||
"chooseAction": "//this.say(\"Say, who's in charge around here?\"); // Should fill in some default source\n\n//var time = this.now();\n//if(Math.round(time) % 20 === 0) {\nif (typeof this.teleportOnce === 'undefined') {\n this.teleportRandom();\n this.teleportOnce = true;\n}\n//}"
|
||||
},
|
||||
"tharin": {
|
||||
"chooseAction": "var t = this;\nvar e = t.getNearestEnemy();\nvar vec = new Vector(0, 0);\n\nfunction item_worth(item) {\n return item.bountyGold/Math.pow(item.distance(e) - t.distance(item), 1.5);\n}\n\nvar items = this.getItems();\nfor (var i = 0; i < items.length; i++) {\n var item = items[i];\n var direction = Vector.normalize(Vector.subtract(item.pos, this.pos));\n var weighted_dir = Vector.multiply(direction, 1000 * item_worth(item));\n vec = Vector.add(vec, weighted_dir);\n}\n\nvar action = \"move\";\nif (typeof this.used_terrify == \"undefined\") {\n var enemy = this.getNearestEnemy();\n \n if (enemy.gold >= 140 || this.distance(enemy) <= 15) {\n action = \"terrify\";\n }\n}\n\nif (action == \"move\") {\n var best_item = null;\n var best_item_value = 0;\n for (var i = 0; i < items.length; i++) {\n var item = items[i];\n var direction = Vector.subtract(item.pos, this.pos);\n \n var angle = Math.acos(vec.dot(direction) / (vec.magnitude() * direction.magnitude()))\n if (angle < Math.PI / 16 || angle > Math.PI * (31/16)) {\n if (item_worth(item) > best_item_value) {\n best_item_value = item_worth(item);\n best_item = item;\n }\n }\n }\n \n if (best_item_value > 0.05) {\n this.move(best_item.pos);\n } else {\n this.say(\"Move to \" + Vector.add(this.pos, vec).x + \" \" + Vector.add(this.pos, vec).y);\n this.move(Vector.add(this.pos, vec));\n }\n} else if (action == \"terrify\") {\n //this.terrify();\n this.used_terrify = true;\n}\n/*\n\n// This code runs once per frame. Choose where to move to grab gold!\n// First player to 150 gold wins.\n\n// This is an example of grabbing the 0th coin from the items array.\nvar items = this.getItems();\nif (items[0]) {\n this.move(items[0].pos);\n} else {\n this.moveXY(18, 36);\n}\n\n\n// You can surely pick a better coin using the methods below.\n// Click on a coin to see its API.\n*/\n"
|
||||
},
|
||||
"wizard-purple": {
|
||||
"chooseAction": "//this.say(\"Say, who's in charge around here?\"); // Should fill in some default source\n\n//var time = this.now();\n\n//if(Math.round(time) % 20 == 0) {\n this.build('coin');\n// console.log(\"build coin\");\n//}"
|
||||
}
|
||||
},
|
||||
"teamSpells": {
|
||||
"common": [
|
||||
"coin-generator-9000/chooseAction"
|
||||
],
|
||||
"humans": [
|
||||
"tharin/chooseAction"
|
||||
],
|
||||
"ogres": [
|
||||
"mak-fod/chooseAction"
|
||||
]
|
||||
},
|
||||
"levelID": "gold-rush",
|
||||
"levelName": "Gold Rush",
|
||||
"totalScore": 39.23691444835561,
|
||||
"submitted": true,
|
||||
"submittedCodeLanguage": "javascript",
|
||||
"playtime": 1158,
|
||||
"codeLanguage": "javascript"
|
||||
}
|
||||
|
||||
levelData = {
|
||||
"_id": "53c71962587cd615bf404919",
|
||||
"name": "Dungeon Arena",
|
||||
"icon": "db/level/53173f76c269d400000543c2/11_dungeon.png",
|
||||
"description": "This level is indescribably flarmy!",
|
||||
"employerDescription": "A DotA-like level where players:\n* Take control of a hero with special abilities\n* Choose which sorts of troops to build.\n* Have limited control over their troops."
|
||||
"version": {
|
||||
"minor": 0,
|
||||
"major": 0,
|
||||
"isLatestMajor": true,
|
||||
"isLatestMinor": true
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ->
|
||||
session = new LevelSession(levelSessionData)
|
||||
v = new LevelSessionCodeView({session:session})
|
||||
request = jasmine.Ajax.requests.mostRecent()
|
||||
request.response({status: 200, responseText: JSON.stringify(levelData)})
|
||||
console.log 'okay should be fine'
|
||||
v
|
File diff suppressed because one or more lines are too long
Loading…
Add table
Reference in a new issue