mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-02-17 17:02:18 -05:00
284 lines
No EOL
9.7 KiB
CoffeeScript
284 lines
No EOL
9.7 KiB
CoffeeScript
CocoView = require 'views/kinds/CocoView'
|
|
template = require 'templates/editor/components/main'
|
|
|
|
Level = require 'models/Level'
|
|
LevelComponent = require 'models/LevelComponent'
|
|
LevelSystem = require 'models/LevelSystem'
|
|
ComponentsCollection = require 'collections/ComponentsCollection'
|
|
ComponentConfigView = require './ThangComponentConfigView'
|
|
|
|
module.exports = class ThangComponentEditView extends CocoView
|
|
id: 'thang-components-edit-view'
|
|
template: template
|
|
|
|
constructor: (options) ->
|
|
super options
|
|
@components = options.components or []
|
|
@world = options.world
|
|
@level = options.level
|
|
@callback = options.callback
|
|
@componentCollection = @supermodel.loadCollection(new ComponentsCollection(), 'components').model
|
|
|
|
afterRender: ->
|
|
super()
|
|
return unless @supermodel.finished()
|
|
@buildExtantComponentTreema()
|
|
@buildAddComponentTreema()
|
|
|
|
buildExtantComponentTreema: ->
|
|
level = new Level()
|
|
treemaOptions =
|
|
supermodel: @supermodel
|
|
schema: level.schema().properties.thangs.items.properties.components
|
|
data: _.cloneDeep @components
|
|
callbacks: {select: @onSelectExtantComponent, change: @onChangeExtantComponents}
|
|
noSortable: true
|
|
nodeClasses:
|
|
'thang-components-array': ThangComponentsArrayNode
|
|
'thang-component': ThangComponentNode
|
|
|
|
@extantComponentsTreema = @$el.find('#extant-components-column .treema').treema treemaOptions
|
|
@extantComponentsTreema.build()
|
|
@$el.find('#extant-components-column .treema').droppable({
|
|
drop: =>
|
|
@onAddComponentEnterPressed @selectedRow
|
|
})
|
|
|
|
buildAddComponentTreema: ->
|
|
return unless @componentCollection and @extantComponentsTreema
|
|
extantComponents = @extantComponentsTreema.data
|
|
componentsUsedCount = extantComponents.length
|
|
return if @lastComponentsUsedCount is componentsUsedCount
|
|
@lastComponentsUsedCount = componentsUsedCount
|
|
components = (m.attributes for m in @componentCollection.models)
|
|
_.remove components, (comp) =>
|
|
_.find extantComponents, {original: comp.original} # already have this one added
|
|
components = _.sortBy components, (comp) -> comp.system + '.' + comp.name
|
|
|
|
treemaOptions =
|
|
supermodel: @supermodel
|
|
schema: {type: 'array', items: LevelComponent.schema}
|
|
data: ($.extend(true, {}, c) for c in components)
|
|
callbacks: {
|
|
select: @onSelectAddableComponent
|
|
enter: @onAddComponentEnterPressed
|
|
dblclick: @onAddComponentDoubleClicked
|
|
mouseenter: @onAddComponentMouseEnter
|
|
mouseleave: @onAddComponentMouseLeave
|
|
}
|
|
readOnly: true
|
|
noSortable: true
|
|
nodeClasses:
|
|
'array': ComponentArrayNode
|
|
'object': ComponentNode
|
|
# I have no idea why it's not building in the Thang Editor unless I defer
|
|
_.defer (=>
|
|
@addComponentsTreema = @$el.find('#add-component-column .treema').treema treemaOptions
|
|
@addComponentsTreema.build()
|
|
@$el.find('#add-component-column .treema-node').draggable({
|
|
revert: 'invalid'
|
|
helper: 'clone'
|
|
appendTo: 'body'
|
|
start: (e) ->
|
|
# Hack to ensure dragged treema node is selected
|
|
$(@).trigger('click') unless $(@).hasClass 'treema-selected'
|
|
})
|
|
@hideLoading()
|
|
), 500
|
|
|
|
onSelectAddableComponent: (e, selected) =>
|
|
@extantComponentsTreema.deselectAll()
|
|
@onComponentSelected(selected, false)
|
|
|
|
onSelectExtantComponent: (e, selected) =>
|
|
return if @updatingFromConfig
|
|
@addComponentsTreema.deselectAll()
|
|
@onComponentSelected(selected, true)
|
|
|
|
onComponentSelected: (selected, extant=true) ->
|
|
return if @alreadySaving # handle infinite loops
|
|
@alreadySaving = true
|
|
@closeExistingView()
|
|
@alreadySaving = false
|
|
|
|
return unless selected.length
|
|
|
|
# select dependencies.
|
|
node = selected[0]
|
|
original = node.data.original
|
|
|
|
toRemoveTreema = []
|
|
dependent_class = 'treema-dependent'
|
|
try
|
|
for index, child of @extantComponentsTreema.childrenTreemas
|
|
$(child.$el).removeClass(dependent_class)
|
|
|
|
for index, child of @extantComponentsTreema.childrenTreemas
|
|
if child.data.original == original # Here we assume that the treemas are sorted by their dependency.
|
|
break
|
|
|
|
dep_originals = (d.original for d in child.component.attributes.dependencies)
|
|
for dep_original in dep_originals
|
|
if original == dep_original
|
|
toRemoveTreema.push child
|
|
|
|
for dep_treema in toRemoveTreema
|
|
dep_treema.toggleSelect()
|
|
$(dep_treema.$el).addClass(dependent_class)
|
|
|
|
catch error
|
|
console.error error
|
|
|
|
return unless selected.length
|
|
row = selected[0]
|
|
@selectedRow = row
|
|
component = row.component?.attributes or row.data
|
|
config = if extant then row.data?.config else {}
|
|
@configView = new ComponentConfigView({
|
|
supermodel: @supermodel
|
|
level: @level
|
|
world: @world
|
|
config: config
|
|
component: component
|
|
editing: extant
|
|
callback: @onComponentConfigChanged
|
|
})
|
|
@insertSubView @configView
|
|
|
|
closeExistingView: ->
|
|
return unless @configView
|
|
data = @configView.data()
|
|
@selectedRow.set '/config', data if data and @configView.changed and @configView.editing
|
|
@removeSubView @configView
|
|
@configView = null
|
|
|
|
onComponentConfigChanged: (data) =>
|
|
@updatingFromConfig = true
|
|
@selectedRow.set '/config', data if data and @configView.changed and @configView.editing
|
|
@updatingFromConfig = false
|
|
|
|
onChangeExtantComponents: =>
|
|
@buildAddComponentTreema()
|
|
@reportChanges()
|
|
|
|
onAddComponentEnterPressed: (node) =>
|
|
if extantSystems
|
|
extantSystems =
|
|
(@supermodel.getModelByOriginalAndMajorVersion LevelSystem, sn.original, sn.majorVersion).attributes.name.toLowerCase() for idx, sn of @level.get('systems')
|
|
requireSystem = node.data.system.toLowerCase()
|
|
|
|
if requireSystem not in extantSystems
|
|
warn_element = 'Component <b>' + node.data.name + '</b> requires system <b>' + requireSystem + '</b> which is currently not specified in this level.'
|
|
noty({
|
|
text: warn_element,
|
|
layout: 'bottomLeft',
|
|
type: 'warning'
|
|
})
|
|
|
|
id = node.data._id
|
|
comp = _.find @componentCollection.models, id: id
|
|
unless comp
|
|
return console.error 'Couldn\'t find component for id', id, 'out of', @components.models
|
|
# Add all dependencies, recursively, unless we already have them
|
|
toAdd = comp.getDependencies(@componentCollection.models)
|
|
_.remove toAdd, (c1) =>
|
|
_.find @extantComponentsTreema.data, (c2) ->
|
|
c2.original is c1.get('original')
|
|
for c in toAdd.concat [comp]
|
|
@extantComponentsTreema.insert '/', {
|
|
original: c.get('original') ? id
|
|
majorVersion: c.get('version').major ? 0
|
|
}
|
|
|
|
# reselect newly added child treema in the extantComponentsTreema
|
|
for index, treema of @extantComponentsTreema.childrenTreemas
|
|
if treema.component.id is id
|
|
_.defer =>
|
|
treema.select()
|
|
@onSelectExtantComponent({}, [treema])
|
|
return
|
|
|
|
onAddComponentDoubleClicked: (e, treema) =>
|
|
@onAddComponentEnterPressed treema
|
|
|
|
onAddComponentMouseEnter: (e, treema) ->
|
|
treema.$el.find('.add-button').show()
|
|
|
|
onAddComponentMouseLeave: (e, treema) ->
|
|
treema.$el.find('.add-button').hide()
|
|
return
|
|
|
|
reportChanges: ->
|
|
@callback?($.extend(true, [], @extantComponentsTreema.data))
|
|
|
|
undo: ->
|
|
if @configView is null or @configView?.editing is false then @extantComponentsTreema.undo() else @configView.undo()
|
|
|
|
redo: ->
|
|
if @configView is null or @configView?.editing is false then @extantComponentsTreema.redo() else @configView.redo()
|
|
|
|
class ThangComponentsArrayNode extends TreemaArrayNode
|
|
valueClass: 'treema-thang-components-array'
|
|
editable: false
|
|
sort: true
|
|
canAddChild: -> false
|
|
|
|
sortFunction: (a, b) =>
|
|
a = @settings.supermodel.getModelByOriginalAndMajorVersion(LevelComponent, a.original, a.majorVersion)
|
|
b = @settings.supermodel.getModelByOriginalAndMajorVersion(LevelComponent, b.original, b.majorVersion)
|
|
return 1 if a.attributes.system > b.attributes.system
|
|
return -1 if a.attributes.system < b.attributes.system
|
|
return 1 if a.name > b.name
|
|
return -1 if a.name < b.name
|
|
return 0
|
|
|
|
class ThangComponentNode extends TreemaObjectNode
|
|
valueClass: 'treema-thang-component'
|
|
collection: false
|
|
|
|
constructor: ->
|
|
super(arguments...)
|
|
@grabDBComponent()
|
|
|
|
grabDBComponent: ->
|
|
@component = @settings.supermodel.getModelByOriginalAndMajorVersion LevelComponent, @data.original, @data.majorVersion
|
|
console.error 'Couldn\'t find comp for', @data.original, @data.majorVersion, 'from models', @settings.supermodel.models unless @component
|
|
|
|
buildValueForDisplay: (valEl) ->
|
|
return super valEl unless @data.original and @component
|
|
s = @component.get('system') + '.' + @component.get('name')
|
|
@buildValueForDisplaySimply valEl, s
|
|
|
|
class ComponentArrayNode extends TreemaArrayNode
|
|
editable: false
|
|
sort: true
|
|
canAddChild: -> false
|
|
|
|
sortFunction: (a, b) =>
|
|
return 1 if a.system > b.system
|
|
return -1 if a.system < b.system
|
|
return 1 if a.name > b.name
|
|
return -1 if a.name < b.name
|
|
return 0
|
|
|
|
class ComponentNode extends TreemaObjectNode
|
|
valueClass: 'treema-component'
|
|
addButtonTemplate: '<button type="button" class="add-button btn btn-default btn-xs"><span class="glyphicon glyphicon-plus"></span></button>'
|
|
collection: false
|
|
|
|
build: ->
|
|
super()
|
|
@$el.find('> .treema-row').append @addButtonTemplate
|
|
addButton = @$el.find('.add-button')
|
|
addButton.hide()
|
|
addButton.click =>
|
|
@callbacks.enter?(@)
|
|
@$el
|
|
|
|
buildValueForDisplay: (valEl) ->
|
|
s = @data.system + '.' + @data.name
|
|
@buildValueForDisplaySimply valEl, s
|
|
|
|
onEnterPressed: (args...) ->
|
|
super(args...)
|
|
@callbacks.enter?(@) |