More work on the CampaignEditorView. Data gets saved to models now.

This commit is contained in:
Scott Erickson 2014-12-17 22:53:04 -08:00
parent 1cc6a97e43
commit b63b4d64da
4 changed files with 204 additions and 41 deletions

View file

@ -313,7 +313,7 @@ class InternationalizationNode extends TreemaNode.nodeMap.object
class LatestVersionCollection extends CocoCollection 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>' searchValueTemplate: '<input placeholder="Search" /><div class="treema-search-results"></div>'
valueClass: 'treema-latest-version' valueClass: 'treema-latest-version'
url: '/db/article' url: '/db/article'
@ -383,7 +383,11 @@ class LatestVersionReferenceNode extends TreemaNode
m = CocoModel.getReferencedModel(@getData(), @workingSchema) m = CocoModel.getReferencedModel(@getData(), @workingSchema)
data = @getData() data = @getData()
if _.isString data # LatestVersionOriginalReferenceNode just uses original 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 else
m = @settings.supermodel.getModelByOriginalAndMajorVersion(m.constructor, data.original, data.majorVersion) m = @settings.supermodel.getModelByOriginalAndMajorVersion(m.constructor, data.original, data.majorVersion)
if @instance and not m if @instance and not m
@ -434,7 +438,7 @@ class LatestVersionReferenceNode extends TreemaNode
selected = @getSelectedResultEl() selected = @getSelectedResultEl()
return not selected.length return not selected.length
class LatestVersionOriginalReferenceNode extends LatestVersionReferenceNode module.exports.LatestVersionOriginalReferenceNode = class LatestVersionOriginalReferenceNode extends LatestVersionReferenceNode
# Just for saving the original, not the major version. # Just for saving the original, not the major version.
saveChanges: -> saveChanges: ->
selected = @getSelectedResultEl() selected = @getSelectedResultEl()
@ -443,6 +447,15 @@ class LatestVersionOriginalReferenceNode extends LatestVersionReferenceNode
@data = fullValue.attributes.original @data = fullValue.attributes.original
@instance = fullValue @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 class LevelComponentReferenceNode extends LatestVersionReferenceNode
# HACK: this list of properties is needed by the thang components edit view and config views. # 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 # need a better way to specify this, or keep the search models from bleeding into those

View file

@ -83,22 +83,27 @@ _.extend CampaignSchema.properties, {
} }
requiredGear: { type: 'object', additionalProperties: { 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: { 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: { allowedHeroes: { type: 'array', items: {
type: 'string' # should be an originalID, denormalized on the editor side type: 'string', links: [{rel: 'db', href: '/db/thang.type/{($)}/version'}], format: 'latest-version-original-reference'
}} }}
#- denormalized from Achievements #- denormalized from Achievements
unlocks: { type: 'array', items: { rewards: { type: 'array', items: {
type: 'object' type: 'object'
additionalProperties: false
properties: properties:
original: { type: 'string' } achievement: { type: 'string', links: [{rel: 'db', href: '/db/achievement/{{$}}'}], format: 'achievement' }
type: { enum: ['hero', 'item', 'level'] } item: { type: 'string', links: [{rel: 'db', href: '/db/thang.type/{($)}/version'}], format: 'latest-version-original-reference' }
achievement: { type: 'string' } 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 #- normal properties

View file

@ -1,39 +1,157 @@
RootView = require 'views/core/RootView' RootView = require 'views/core/RootView'
Campaign = require 'models/Campaign' Campaign = require 'models/Campaign'
Level = require 'models/Level' Level = require 'models/Level'
Achievement = require 'models/Achievement'
ThangType = require 'models/ThangType'
WorldMapView = require 'views/play/WorldMapView' WorldMapView = require 'views/play/WorldMapView'
CocoCollection = require 'collections/CocoCollection' 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 module.exports = class CampaignEditorView extends RootView
id: "campaign-editor-view" id: "campaign-editor-view"
template: require 'templates/editor/campaign/campaign-editor-view' template: require 'templates/editor/campaign/campaign-editor-view'
className: 'editor' className: 'editor'
constructor: -> constructor: (options, campaignHandle) ->
super(arguments...) super(options)
# TODO: move the outputted data to the db, and load the Campaign objects instead # MIGRATION CODE
for level in levels # for level in levels
_.extend level, options[level.id] # _.extend level, options[level.id]
level.slug = level.id # level.slug = level.id
delete level.id # delete level.id
delete level.nextLevels # delete level.nextLevels
level.position = { x: level.x, y: level.y } # level.position = { x: level.x, y: level.y }
delete level.x # delete level.x
delete level.y # delete level.y
if level.unlocksHero # if level.unlocksHero
level.unlocks = [{ # level.unlocks = [{
original: level.unlocksHero.originalID # original: level.unlocksHero.originalID
type: 'hero' # type: 'hero'
}] # }]
delete level.unlocksHero # delete level.unlocksHero
campaign.levels[level.original] = level # campaign.levels[level.original] = level
@campaign = new Campaign(campaign) # @campaign = new Campaign(campaign)
#------------------------------------------------ #------------------------------------------------
@campaign = new Campaign({_id:campaignHandle})
collection = new CocoCollection({model: Level, url}) #--------------- temporary migration to change thang type slugs to originals
collection.ur #- 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: -> getRenderData: ->
c = super() c = super()
c.campaign = @campaign c.campaign = @campaign
@ -51,17 +169,47 @@ module.exports = class CampaignEditorView extends RootView
nodeClasses: nodeClasses:
levels: LevelsNode levels: LevelsNode
level: LevelNode level: LevelNode
achievement: AchievementNode
supermodel: @supermodel
@treema = @$el.find('#campaign-treema').treema treemaOptions @treema = @$el.find('#campaign-treema').treema treemaOptions
@treema.build() @treema.build()
@treema.open() @treema.open()
@treema.childrenTreemas.levels.open() @treema.childrenTreemas.levels?.open()
worldMapView = new WorldMapView({supermodel: @supermodel, editorMode: true}, 'dungeon') worldMapView = new WorldMapView({supermodel: @supermodel, editorMode: true}, 'dungeon')
worldMapView.highlightElement = _.noop # make it stop worldMapView.highlightElement = _.noop # make it stop
@insertSubView worldMapView @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 class LevelsNode extends TreemaObjectNode
valueClass: 'treema-levels' valueClass: 'treema-levels'
@ -73,15 +221,12 @@ class LevelsNode extends TreemaObjectNode
childPropertiesAvailable: -> @childSource childPropertiesAvailable: -> @childSource
childSource: (req, res) => childSource: (req, res) =>
console.log 'calling child source!', req
s = new Backbone.Collection([], {model:Level}) s = new Backbone.Collection([], {model:Level})
s.url = '/db/level' s.url = '/db/level'
s.fetch({data: {term:req.term, project: Campaign.denormalizedLevelProperties.join(',')}}) s.fetch({data: {term:req.term, project: Campaign.denormalizedLevelProperties.join(',')}})
s.once 'sync', (collection) -> s.once 'sync', (collection) ->
LevelsNode.levels[level.get('original')] = level for level in collection.models 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) mapped = ({label: r.get('name'), value: r.get('original')} for r in collection.models)
console.log 'mapped', mapped
res(mapped) res(mapped)
@ -92,11 +237,11 @@ class LevelNode extends TreemaObjectNode
populateData: -> populateData: ->
return if @data.name? return if @data.name?
console.log 'how do I do this?', @data, @keyForParent, LevelsNode.levels
data = _.pick LevelsNode.levels[@keyForParent].attributes, Campaign.denormalizedLevelProperties data = _.pick LevelsNode.levels[@keyForParent].attributes, Campaign.denormalizedLevelProperties
_.extend @data, data _.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 = { campaign = {
name: 'Dungeon' name: 'Dungeon'

View file

@ -36,7 +36,7 @@ CampaignHandler = class CampaignHandler extends Handler
return @getRelatedAchievements(req, res, campaign, projection) if relationship is 'achievements' return @getRelatedAchievements(req, res, campaign, projection) if relationship is 'achievements'
else else
super(arguments...) super(arguments...)
getRelatedLevels: (req, res, campaign, projection) -> getRelatedLevels: (req, res, campaign, projection) ->
levels = campaign.get('levels') or [] levels = campaign.get('levels') or []