mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-23 15:48:11 -05:00
More work on the CampaignEditorView. Data gets saved to models now.
This commit is contained in:
parent
1cc6a97e43
commit
b63b4d64da
4 changed files with 204 additions and 41 deletions
|
@ -313,7 +313,7 @@ class InternationalizationNode extends TreemaNode.nodeMap.object
|
|||
|
||||
class LatestVersionCollection extends CocoCollection
|
||||
|
||||
class LatestVersionReferenceNode extends TreemaNode
|
||||
module.exports.LatestVersionReferenceNode = class LatestVersionReferenceNode extends TreemaNode
|
||||
searchValueTemplate: '<input placeholder="Search" /><div class="treema-search-results"></div>'
|
||||
valueClass: 'treema-latest-version'
|
||||
url: '/db/article'
|
||||
|
@ -383,7 +383,11 @@ class LatestVersionReferenceNode extends TreemaNode
|
|||
m = CocoModel.getReferencedModel(@getData(), @workingSchema)
|
||||
data = @getData()
|
||||
if _.isString data # LatestVersionOriginalReferenceNode just uses original
|
||||
m = @settings.supermodel.getModelByOriginal(m.constructor, data)
|
||||
if m.schema().properties.version
|
||||
m = @settings.supermodel.getModelByOriginal(m.constructor, data)
|
||||
else
|
||||
# get by id
|
||||
m = @settings.supermodel.getModel(m.constructor, data)
|
||||
else
|
||||
m = @settings.supermodel.getModelByOriginalAndMajorVersion(m.constructor, data.original, data.majorVersion)
|
||||
if @instance and not m
|
||||
|
@ -434,7 +438,7 @@ class LatestVersionReferenceNode extends TreemaNode
|
|||
selected = @getSelectedResultEl()
|
||||
return not selected.length
|
||||
|
||||
class LatestVersionOriginalReferenceNode extends LatestVersionReferenceNode
|
||||
module.exports.LatestVersionOriginalReferenceNode = class LatestVersionOriginalReferenceNode extends LatestVersionReferenceNode
|
||||
# Just for saving the original, not the major version.
|
||||
saveChanges: ->
|
||||
selected = @getSelectedResultEl()
|
||||
|
@ -443,6 +447,15 @@ class LatestVersionOriginalReferenceNode extends LatestVersionReferenceNode
|
|||
@data = fullValue.attributes.original
|
||||
@instance = fullValue
|
||||
|
||||
module.exports.IDReferenceNode = class IDReferenceNode extends LatestVersionReferenceNode
|
||||
# Just for saving the _id
|
||||
saveChanges: ->
|
||||
selected = @getSelectedResultEl()
|
||||
return unless selected.length
|
||||
fullValue = selected.data('value')
|
||||
@data = fullValue.attributes._id
|
||||
@instance = fullValue
|
||||
|
||||
class LevelComponentReferenceNode extends LatestVersionReferenceNode
|
||||
# HACK: this list of properties is needed by the thang components edit view and config views.
|
||||
# need a better way to specify this, or keep the search models from bleeding into those
|
||||
|
|
|
@ -83,22 +83,27 @@ _.extend CampaignSchema.properties, {
|
|||
}
|
||||
|
||||
requiredGear: { type: 'object', additionalProperties: {
|
||||
type: 'string' # should be an originalID, denormalized on the editor side
|
||||
type: 'array'
|
||||
items: { type: 'string', links: [{rel: 'db', href: '/db/thang.type/{($)}/version'}], format: 'latest-version-original-reference' }
|
||||
}}
|
||||
restrictedGear: { type: 'object', additionalProperties: {
|
||||
type: 'string' # should be an originalID, denormalized on the editor side
|
||||
type: 'array'
|
||||
items: { type: 'string', links: [{rel: 'db', href: '/db/thang.type/{($)}/version'}], format: 'latest-version-original-reference' }
|
||||
}}
|
||||
allowedHeroes: { type: 'array', items: {
|
||||
type: 'string' # should be an originalID, denormalized on the editor side
|
||||
allowedHeroes: { type: 'array', items: {
|
||||
type: 'string', links: [{rel: 'db', href: '/db/thang.type/{($)}/version'}], format: 'latest-version-original-reference'
|
||||
}}
|
||||
|
||||
#- denormalized from Achievements
|
||||
unlocks: { type: 'array', items: {
|
||||
rewards: { type: 'array', items: {
|
||||
type: 'object'
|
||||
additionalProperties: false
|
||||
properties:
|
||||
original: { type: 'string' }
|
||||
type: { enum: ['hero', 'item', 'level'] }
|
||||
achievement: { type: 'string' }
|
||||
achievement: { type: 'string', links: [{rel: 'db', href: '/db/achievement/{{$}}'}], format: 'achievement' }
|
||||
item: { type: 'string', links: [{rel: 'db', href: '/db/thang.type/{($)}/version'}], format: 'latest-version-original-reference' }
|
||||
hero: { type: 'string', links: [{rel: 'db', href: '/db/thang.type/{($)}/version'}], format: 'latest-version-original-reference' }
|
||||
level: { type: 'string', links: [{rel: 'db', href: '/db/level/{($)}/version'}], format: 'latest-version-original-reference' }
|
||||
type: { enum: ['heroes', 'items', 'levels'] }
|
||||
}}
|
||||
|
||||
#- normal properties
|
||||
|
|
|
@ -1,39 +1,157 @@
|
|||
RootView = require 'views/core/RootView'
|
||||
Campaign = require 'models/Campaign'
|
||||
Level = require 'models/Level'
|
||||
Achievement = require 'models/Achievement'
|
||||
ThangType = require 'models/ThangType'
|
||||
WorldMapView = require 'views/play/WorldMapView'
|
||||
CocoCollection = require 'collections/CocoCollection'
|
||||
treemaExt = require 'core/treema-ext'
|
||||
utils = require 'core/utils'
|
||||
|
||||
achievementProject = ['related', 'rewards', 'name', 'slug']
|
||||
thangTypeProject = ['name', 'original', 'slug']
|
||||
|
||||
module.exports = class CampaignEditorView extends RootView
|
||||
id: "campaign-editor-view"
|
||||
template: require 'templates/editor/campaign/campaign-editor-view'
|
||||
className: 'editor'
|
||||
|
||||
constructor: ->
|
||||
super(arguments...)
|
||||
constructor: (options, campaignHandle) ->
|
||||
super(options)
|
||||
|
||||
# TODO: move the outputted data to the db, and load the Campaign objects instead
|
||||
for level in levels
|
||||
_.extend level, options[level.id]
|
||||
level.slug = level.id
|
||||
delete level.id
|
||||
delete level.nextLevels
|
||||
level.position = { x: level.x, y: level.y }
|
||||
delete level.x
|
||||
delete level.y
|
||||
if level.unlocksHero
|
||||
level.unlocks = [{
|
||||
original: level.unlocksHero.originalID
|
||||
type: 'hero'
|
||||
}]
|
||||
delete level.unlocksHero
|
||||
campaign.levels[level.original] = level
|
||||
@campaign = new Campaign(campaign)
|
||||
# MIGRATION CODE
|
||||
# for level in levels
|
||||
# _.extend level, options[level.id]
|
||||
# level.slug = level.id
|
||||
# delete level.id
|
||||
# delete level.nextLevels
|
||||
# level.position = { x: level.x, y: level.y }
|
||||
# delete level.x
|
||||
# delete level.y
|
||||
# if level.unlocksHero
|
||||
# level.unlocks = [{
|
||||
# original: level.unlocksHero.originalID
|
||||
# type: 'hero'
|
||||
# }]
|
||||
# delete level.unlocksHero
|
||||
# campaign.levels[level.original] = level
|
||||
# @campaign = new Campaign(campaign)
|
||||
#------------------------------------------------
|
||||
|
||||
@campaign = new Campaign({_id:campaignHandle})
|
||||
|
||||
collection = new CocoCollection({model: Level, url})
|
||||
collection.ur
|
||||
#--------------- temporary migration to change thang type slugs to originals
|
||||
#- should keep around though for loading the names of items and heroes that are referenced
|
||||
#- just load names instead of slugs, though
|
||||
@sluggyThangs = new Backbone.Collection()
|
||||
@listenToOnce @campaign, 'sync', ->
|
||||
slugs = []
|
||||
for level in _.values(@campaign.get('levels'))
|
||||
slugs = slugs.concat(_.values(level.requiredGear)) if level.requiredGear
|
||||
slugs = slugs.concat(_.values(level.restrictedGear)) if level.restrictedGear
|
||||
slugs = slugs.concat(level.allowedHeroes) if level.allowedHeroes
|
||||
slugs = _.uniq _.flatten slugs
|
||||
for slug in slugs
|
||||
thangType = new ThangType()
|
||||
thangType.setProjection(thangTypeProject)
|
||||
if utils.isID slug
|
||||
thangType.setURL("/db/thang.type/#{slug}/version")
|
||||
else
|
||||
thangType.setURL("/db/thang.type/#{slug}")
|
||||
@supermodel.loadModel(thangType, 'thang')
|
||||
@sluggyThangs.add(thangType)
|
||||
#---------------
|
||||
@supermodel.loadModel(@campaign, 'campaign')
|
||||
|
||||
@levels = new CocoCollection([], {
|
||||
model: Level
|
||||
url: "/db/campaign/#{campaignHandle}/levels"
|
||||
project: Campaign.denormalizedLevelProperties
|
||||
})
|
||||
@supermodel.loadCollection(@levels, 'levels')
|
||||
|
||||
@achievements = new CocoCollection([], {
|
||||
model: Achievement
|
||||
url: "/db/campaign/#{campaignHandle}/achievements"
|
||||
project: achievementProject
|
||||
})
|
||||
@supermodel.loadCollection(@achievements, 'achievements')
|
||||
|
||||
@toSave = new Backbone.Collection()
|
||||
|
||||
onLoaded: ->
|
||||
campaignLevels = $.extend({}, @campaign.get('levels'))
|
||||
for level in @levels.models
|
||||
levelOriginal = level.get('original')
|
||||
campaignLevel = campaignLevels[levelOriginal] ? {}
|
||||
|
||||
#--------------- temporary migrations
|
||||
if campaignLevel.restrictedGear
|
||||
for slot, value of campaignLevel.restrictedGear
|
||||
if _.isString(value)
|
||||
campaignLevel.restrictedGear[slot] = [value]
|
||||
#
|
||||
if campaignLevel.requiredGear
|
||||
for slot, value of campaignLevel.requiredGear
|
||||
if _.isString(value)
|
||||
campaignLevel.requiredGear[slot] = [value]
|
||||
#
|
||||
if campaignLevel.requiredGear
|
||||
for gear in _.values(campaignLevel.requiredGear)
|
||||
for slug, index in gear
|
||||
thang = @sluggyThangs.findWhere({slug: slug})
|
||||
continue unless thang
|
||||
gear[index] = thang.get('original')
|
||||
#
|
||||
if campaignLevel.restrictedGear
|
||||
for gear in _.values(campaignLevel.restrictedGear)
|
||||
for slug, index in gear
|
||||
thang = @sluggyThangs.findWhere({slug: slug})
|
||||
continue unless thang
|
||||
gear[index] = thang.get('original')
|
||||
#
|
||||
if campaignLevel.allowedHeroes
|
||||
for slug, index in campaignLevel.allowedHeroes
|
||||
thang = @sluggyThangs.findWhere({slug: slug})
|
||||
continue unless thang
|
||||
level.allowedHeroes[index] = thang.get('original')
|
||||
#---------------
|
||||
|
||||
$.extend campaignLevel, _.omit(level.attributes, '_id')
|
||||
achievements = @achievements.where {'related': levelOriginal}
|
||||
rewards = []
|
||||
for achievement in achievements
|
||||
for rewardType, rewardArray of achievement.get('rewards')
|
||||
for reward in rewardArray
|
||||
rewardObject = { achievement: achievement.id }
|
||||
|
||||
if rewardType is 'heroes'
|
||||
rewardObject.hero = reward
|
||||
thangType = new ThangType({}, {project: thangTypeProject})
|
||||
thangType.setURL("/db/thang.type/#{reward}/version")
|
||||
@supermodel.loadModel(thangType, 'thang')
|
||||
|
||||
if rewardType is 'levels'
|
||||
rewardObject.level = reward
|
||||
if not @levels.findWhere({original: reward})
|
||||
level = new Level({}, {project: Campaign.denormalizedLevelProperties})
|
||||
level.setURL("/db/level/#{reward}/version")
|
||||
@supermodel.loadModel(level, 'level')
|
||||
|
||||
if rewardType is 'items'
|
||||
rewardObject.item = reward
|
||||
thangType = new ThangType({}, {project: thangTypeProject})
|
||||
thangType.setURL("/db/thang.type/#{reward}/version")
|
||||
@supermodel.loadModel(thangType, 'thang')
|
||||
|
||||
rewards.push rewardObject
|
||||
campaignLevel.rewards = rewards
|
||||
delete campaignLevel.unlocks
|
||||
campaignLevels[levelOriginal] = campaignLevel
|
||||
|
||||
@campaign.set('levels', campaignLevels)
|
||||
super()
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
c.campaign = @campaign
|
||||
|
@ -51,17 +169,47 @@ module.exports = class CampaignEditorView extends RootView
|
|||
nodeClasses:
|
||||
levels: LevelsNode
|
||||
level: LevelNode
|
||||
|
||||
achievement: AchievementNode
|
||||
supermodel: @supermodel
|
||||
|
||||
@treema = @$el.find('#campaign-treema').treema treemaOptions
|
||||
@treema.build()
|
||||
@treema.open()
|
||||
@treema.childrenTreemas.levels.open()
|
||||
@treema.childrenTreemas.levels?.open()
|
||||
|
||||
worldMapView = new WorldMapView({supermodel: @supermodel, editorMode: true}, 'dungeon')
|
||||
worldMapView.highlightElement = _.noop # make it stop
|
||||
@insertSubView worldMapView
|
||||
|
||||
onTreemaChanged: (e, nodes) =>
|
||||
for node in nodes
|
||||
path = node.getPath()
|
||||
if _.string.startsWith path, '/levels/'
|
||||
parts = path.split('/')
|
||||
original = parts[2]
|
||||
level = @supermodel.getModelByOriginal Level, original
|
||||
campaignLevel = @treema.get "/levels/#{original}"
|
||||
|
||||
if 'rewards' in parts
|
||||
rewardsData = @
|
||||
@updateRewardsForLevel level, campaignLevel.rewards
|
||||
|
||||
for key in Campaign.denormalizedLevelProperties
|
||||
level.set key, campaignLevel[key]
|
||||
@toSave.add level
|
||||
|
||||
@toSave.add @campaign
|
||||
|
||||
updateRewardsForLevel: (level, rewards) ->
|
||||
achievements = @supermodel.getModels(Achievement)
|
||||
achievements = (a for a in achievements when a.get('related') is level.get('original'))
|
||||
for achievement in achievements
|
||||
rewardSubset = (r for r in rewards when r.achievement is achievement._id)
|
||||
newRewards = {}
|
||||
newRewards.heroes = _.compact((r.hero for r in rewards))
|
||||
newRewards.items = _.compact((r.item for r in rewards))
|
||||
newRewards.levels = _.compact((r.level for r in rewards))
|
||||
achievement.set 'rewards', newRewards
|
||||
|
||||
class LevelsNode extends TreemaObjectNode
|
||||
valueClass: 'treema-levels'
|
||||
|
@ -73,15 +221,12 @@ class LevelsNode extends TreemaObjectNode
|
|||
childPropertiesAvailable: -> @childSource
|
||||
|
||||
childSource: (req, res) =>
|
||||
console.log 'calling child source!', req
|
||||
s = new Backbone.Collection([], {model:Level})
|
||||
s.url = '/db/level'
|
||||
s.fetch({data: {term:req.term, project: Campaign.denormalizedLevelProperties.join(',')}})
|
||||
s.once 'sync', (collection) ->
|
||||
LevelsNode.levels[level.get('original')] = level for level in collection.models
|
||||
console.log 'results!', collection.models
|
||||
mapped = ({label: r.get('name'), value: r.get('original')} for r in collection.models)
|
||||
console.log 'mapped', mapped
|
||||
res(mapped)
|
||||
|
||||
|
||||
|
@ -92,11 +237,11 @@ class LevelNode extends TreemaObjectNode
|
|||
|
||||
populateData: ->
|
||||
return if @data.name?
|
||||
console.log 'how do I do this?', @data, @keyForParent, LevelsNode.levels
|
||||
data = _.pick LevelsNode.levels[@keyForParent].attributes, Campaign.denormalizedLevelProperties
|
||||
_.extend @data, data
|
||||
console.log 'extended to data', data
|
||||
console.log 'now data is', @data
|
||||
|
||||
class AchievementNode extends treemaExt.IDReferenceNode
|
||||
buildSearchURL: (term) -> "#{@url}?term=#{term}&project=#{achievementProject.join(',')}"
|
||||
|
||||
campaign = {
|
||||
name: 'Dungeon'
|
||||
|
|
|
@ -36,7 +36,7 @@ CampaignHandler = class CampaignHandler extends Handler
|
|||
return @getRelatedAchievements(req, res, campaign, projection) if relationship is 'achievements'
|
||||
else
|
||||
super(arguments...)
|
||||
|
||||
|
||||
|
||||
getRelatedLevels: (req, res, campaign, projection) ->
|
||||
levels = campaign.get('levels') or []
|
||||
|
|
Loading…
Reference in a new issue