2014-01-03 13:32:13 -05:00
View = require ' views/kinds/CocoView '
thangs_template = require ' templates/editor/level/thangs_tab '
Level = require ' models/Level '
ThangType = require ' models/ThangType '
LevelComponent = require ' models/LevelComponent '
CocoCollection = require ' models/CocoCollection '
{ isObjectID } = require ' models/CocoModel '
Surface = require ' lib/surface/Surface '
Thang = require ' lib/world/thang '
LevelThangEditView = require ' ./thang/edit '
2014-03-15 15:31:39 -04:00
ComponentsCollection = require ' collections/ComponentsCollection '
2014-01-03 13:32:13 -05:00
# Moving the screen while dragging thangs constants
MOVE_MARGIN = 0.15
MOVE_SPEED = 13
# Essential component original ids
componentOriginals =
" existence.Exists " : " 524b4150ff92f1f4f8000024 "
" physics.Physical " : " 524b75ad7fc0f6d519000001 "
class ThangTypeSearchCollection extends CocoCollection
2014-03-11 21:30:25 -04:00
url: ' /db/thang.type/search?project=true '
2014-01-03 13:32:13 -05:00
model: ThangType
module.exports = class ThangsTabView extends View
id: " editor-level-thangs-tab-view "
className: ' tab-pane active '
template: thangs_template
startsLoading: true
subscriptions:
' surface:sprite-selected ' : ' onExtantThangSelected '
' surface:mouse-moved ' : ' onSurfaceMouseMoved '
' surface:mouse-over ' : ' onSurfaceMouseOver '
' surface:mouse-out ' : ' onSurfaceMouseOut '
' level-loaded ' : ' onLevelLoaded '
' edit-level-thang ' : ' editThang '
' level-thang-edited ' : ' onLevelThangEdited '
' level-thang-done-editing ' : ' onLevelThangDoneEditing '
' level:view-switched ' : ' onViewSwitched '
' sprite:mouse-down ' : ' onSpriteMouseDown '
' sprite:dragged ' : ' onSpriteDragged '
' sprite:mouse-up ' : ' onSpriteMouseUp '
' sprite:double-clicked ' : ' onSpriteDoubleClicked '
2014-01-06 17:53:21 -05:00
' surface:stage-mouse-down ' : ' onStageMouseDown '
2014-01-31 13:21:32 -05:00
2014-01-21 13:42:09 -05:00
events:
' click # extant-thangs-filter button ' : ' onFilterExtantThangs '
2014-01-31 13:21:32 -05:00
2014-01-06 20:11:57 -05:00
shortcuts:
2014-02-24 12:58:12 -05:00
' esc ' : ' selectAddThang '
' delete, del, backspace ' : ' deleteSelectedExtantThang '
' left ' : -> @ moveAddThangSelection - 1
' right ' : -> @ moveAddThangSelection 1
2014-01-21 13:42:09 -05:00
2014-01-03 13:32:13 -05:00
constructor: (options) ->
super options
@world = options . world
@thangTypes = @ supermodel . getCollection new ThangTypeSearchCollection ( ) # should load depended-on Components, too
@ thangTypes . once ' sync ' , @ onThangTypesLoaded
@ thangTypes . fetch ( )
2014-03-15 15:31:39 -04:00
# just loading all Components for now: https://github.com/codecombat/codecombat/issues/405
@componentCollection = @ supermodel . getCollection new ComponentsCollection ( )
@ componentCollection . once ' sync ' , @ onComponentsLoaded
@ componentCollection . fetch ( )
2014-01-03 13:32:13 -05:00
onThangTypesLoaded: =>
2014-03-15 15:31:39 -04:00
return if @ destroyed
2014-01-03 13:32:13 -05:00
@ supermodel . addCollection @ thangTypes
@ supermodel . populateModel model for model in @ thangTypes . models
2014-03-15 15:31:39 -04:00
@startsLoading = not @ componentCollection . loaded
@ render ( ) # do it again but without the loading screen
@ onLevelLoaded level: @ level if @ level and not @ startsLoading
onComponentsLoaded: =>
return if @ destroyed
@ supermodel . addCollection @ componentCollection
@startsLoading = not @ thangTypes . loaded
2014-01-03 13:32:13 -05:00
@ render ( ) # do it again but without the loading screen
2014-03-15 15:31:39 -04:00
@ onLevelLoaded level: @ level if @ level and not @ startsLoading
2014-01-03 13:32:13 -05:00
2014-02-11 17:58:45 -05:00
getRenderData: (context={}) ->
2014-01-03 13:32:13 -05:00
context = super ( context )
2014-01-21 02:02:23 -05:00
thangTypes = ( thangType . attributes for thangType in @ supermodel . getModels ( ThangType ) )
thangTypes = _ . uniq thangTypes , false , ' original '
2014-01-31 13:21:32 -05:00
thangTypes = _ . reject thangTypes , kind: ' Mark '
2014-01-21 02:02:23 -05:00
groupMap = { }
for thangType in thangTypes
groupMap [ thangType . kind ] ? = [ ]
groupMap [ thangType . kind ] . push thangType
2014-01-31 13:21:32 -05:00
2014-01-21 02:02:23 -05:00
groups = [ ]
for groupName in Object . keys ( groupMap ) . sort ( )
someThangTypes = groupMap [ groupName ]
someThangTypes = _ . sortBy someThangTypes , ' name '
group =
name: groupName
thangs: someThangTypes
groups . push group
2014-01-31 13:21:32 -05:00
2014-01-21 02:02:23 -05:00
context.thangTypes = thangTypes
context.groups = groups
2014-01-03 13:32:13 -05:00
context
2014-03-18 00:47:53 -04:00
onWindowResize: (e) ->
$ ( ' # thangs-list ' ) . height ( ' 100% ' )
thangsHeaderHeight = $ ( ' # thangs-header ' ) . height ( )
oldHeight = $ ( ' # thangs-list ' ) . height ( )
$ ( ' # thangs-list ' ) . height ( oldHeight - thangsHeaderHeight )
2014-01-03 13:32:13 -05:00
afterRender: ->
return if @ startsLoading
super ( )
$ ( ' .tab-content ' ) . click @ selectAddThang
2014-01-20 06:15:20 -05:00
$ ( ' # thangs-list ' ) . bind ' mousewheel ' , @ preventBodyScrollingInThangList
2014-01-21 13:42:09 -05:00
@ $el . find ( ' # extant-thangs-filter button:first ' ) . button ( ' toggle ' )
2014-03-18 00:47:53 -04:00
$ ( window ) . resize @ onWindowResize
2014-01-31 13:21:32 -05:00
2014-02-24 12:58:12 -05:00
onFilterExtantThangs: (e) ->
2014-03-13 02:49:51 -04:00
@ $el . find ( ' # extant-thangs-filter button.active ' ) . button ( ' toggle ' )
2014-02-24 12:58:12 -05:00
button = $ ( e . target ) . closest ( ' button ' )
button . button ( ' toggle ' )
val = button . val ( )
@ thangsTreema . $el . removeClass ( @ lastHideClass ) if @ lastHideClass
@ thangsTreema . $el . addClass ( @lastHideClass = " hide-except- #{ val } " ) if val
2014-01-03 13:32:13 -05:00
2014-01-20 06:15:20 -05:00
preventBodyScrollingInThangList: (e) ->
@ scrollTop += ( if e . deltaY < 0 then 1 else - 1 ) * 30
e . preventDefault ( )
2014-01-03 13:32:13 -05:00
onLevelLoaded: (e) ->
@level = e . level
return if @ startsLoading
data = $ . extend ( true , { } , @ level . attributes )
treemaOptions =
schema: Level . schema . get ( ' properties ' ) . thangs
data: data . thangs
supermodel: @ supermodel
callbacks:
change: @ onThangsChanged
select: @ onTreemaThangSelected
dblclick: @ onTreemaThangDoubleClicked
readOnly: true
nodeClasses:
thang: ThangNode
array: ThangsNode
world: @ world
@thangsTreema = @ $el . find ( ' # thangs-treema ' ) . treema treemaOptions
@ thangsTreema . build ( )
@ thangsTreema . open ( )
@ onThangsChanged ( ) # Initialize the World with Thangs
@ initSurface ( )
2014-03-18 00:47:53 -04:00
thangsHeaderHeight = $ ( ' # thangs-header ' ) . height ( )
oldHeight = $ ( ' # thangs-list ' ) . height ( )
$ ( ' # thangs-list ' ) . height ( oldHeight - thangsHeaderHeight )
2014-01-03 13:32:13 -05:00
initSurface: ->
surfaceCanvas = $ ( ' canvas # surface ' , @ $el )
@surface = new Surface @ world , surfaceCanvas , {
wizards: false
paths: false
grid: true
navigateToSelection: false
thangTypes: @ supermodel . getModels ( ThangType )
showInvisible: true
2014-02-28 20:12:23 -05:00
frameRate: 15
2014-01-03 13:32:13 -05:00
}
@surface.playing = false
@ surface . setWorld @ world
@ surface . camera . zoomTo ( { x : 262 , y : - 164 } , 1.66 , 0 )
destroy: ->
@ selectAddThangType null
@ surface . destroy ( )
2014-02-14 13:57:47 -05:00
super ( )
2014-01-03 13:32:13 -05:00
onViewSwitched: (e) ->
2014-01-28 14:54:16 -05:00
@ selectAddThang ( )
2014-01-03 13:32:13 -05:00
@ surface ? . spriteBoss ? . selectSprite null , null
onSpriteMouseDown: (e) ->
2014-01-06 17:53:21 -05:00
# Sprite clicks happen after stage clicks, but we need to know whether a sprite is being clicked.
clearTimeout @ backgroundAddClickTimeout
onStageMouseDown: (e) ->
if @ addThangSprite
# If we click on the background, we need to add @addThangSprite, but not if onSpriteMouseDown will fire.
@backgroundAddClickTimeout = _ . defer => @ onExtantThangSelected { }
2014-01-03 13:32:13 -05:00
onSpriteDragged: (e) ->
return unless @ selectedExtantThang and e . thang ? . id is @ selectedExtantThang ? . id
2014-03-14 09:03:57 -04:00
@surface.camera.dragDisabled = true
2014-01-03 13:32:13 -05:00
{ stageX , stageY } = e . originalEvent
wop = @ surface . camera . canvasToWorld x: stageX , y: stageY
wop.z = @ selectedExtantThang . depth / 2
@ adjustThangPos @ selectedExtantSprite , @ selectedExtantThang , wop
[ w , h ] = [ @ surface . camera . canvasWidth , @ surface . camera . canvasHeight ]
@ calculateMovement ( stageX / w , stageY / h , w / h )
onSpriteMouseUp: (e) ->
clearInterval ( @ movementInterval ) if @ movementInterval ?
@movementInterval = null
2014-03-14 09:03:57 -04:00
@surface.camera.dragDisabled = false
2014-01-03 13:32:13 -05:00
return unless @ selectedExtantThang and e . thang ? . id is @ selectedExtantThang ? . id
pos = @ selectedExtantThang . pos
physicalOriginal = componentOriginals [ " physics.Physical " ]
path = " id= #{ @ selectedExtantThang . id } /components/original= #{ physicalOriginal } " # TODO: hack
physical = @ thangsTreema . get path
return if not physical or ( physical . config . pos . x is pos . x and physical . config . pos . y is pos . y )
@ thangsTreema . set path + ' /config/pos ' , x: pos . x , y: pos . y , z: pos . z
onSpriteDoubleClicked: (e) ->
return unless e . thang
@ editThang thangID: e . thang . id
# TODO: figure out a good way to have all Surface clicks and Treema clicks just proxy in one direction, so we can maintain only one way of handling selection and deletion
onExtantThangSelected: (e) ->
2014-03-22 15:17:15 -04:00
@ selectedExtantSprite ? . setNameLabel null unless @ selectedExtantSprite is e . sprite
2014-01-03 13:32:13 -05:00
@selectedExtantThang = e . thang
@selectedExtantSprite = e . sprite
if e . thang and ( key . alt or key . meta )
# We alt-clicked, so create a clone addThang
@ selectAddThangType e . thang . spriteName , @ selectedExtantThang
else if e . thang and not ( @ addThangSprite and @ addThangType is " Blood Torch Test " ) # TODO: figure out which Thangs can be placed on other Thangs
# We clicked on a Thang (or its Treema), so select the Thang
@ selectAddThang null
@selectedExtantThangClickTime = new Date ( )
treemaThang = _ . find @ thangsTreema . childrenTreemas , (treema) => treema . data . id is @ selectedExtantThang . id
if treemaThang
2014-03-22 15:17:15 -04:00
# Show the label above selected thang, notice that we may get here from thang-edit-view, so it will be selected but no label
# also covers selecting from Treema
@ selectedExtantSprite . setNameLabel @ selectedExtantSprite . thangType . get ( ' name ' ) + ' : ' + @ selectedExtantThang . id
2014-03-21 03:54:55 -04:00
if not treemaThang . isSelected ( )
treemaThang . select ( )
2014-03-21 05:45:56 -04:00
@ thangsTreema . $el . scrollTop ( @ thangsTreema . $el . find ( ' .treema-children .treema-selected ' ) [ 0 ] . offsetTop )
2014-01-03 13:32:13 -05:00
else if @ addThangSprite
# We clicked on the background when we had an add Thang selected, so add it
@ addThang @ addThangType , @ addThangSprite . thang . pos
2014-01-31 13:21:32 -05:00
2014-01-21 13:54:59 -05:00
# Commented out this bit so the extant thangs treema editor can select invisible thangs like arrows.
# Couldn't spot any bugs... But if there are any, better come up with a better solution.
# else
# # We clicked on the background, so deselect anything selected
# @thangsTreema.deselectAll()
2014-01-03 13:32:13 -05:00
selectAddThang: (e) =>
if e then target = $ ( e . target ) else target = @ $el . find ( ' .add-thangs-palette ' ) # pretend to click on background if no event
return true if target . attr ( ' id ' ) is ' surface '
2014-01-06 20:11:57 -05:00
target = target . closest ( ' .add-thang-palette-icon ' )
2014-01-03 13:32:13 -05:00
wasSelected = target . hasClass ' selected '
@ $el . find ( ' .add-thangs-palette .add-thang-palette-icon.selected ' ) . removeClass ( ' selected ' )
2014-01-28 12:22:23 -05:00
@ selectAddThangType ( if wasSelected then null else target . attr ' data-thang-type ' ) unless key . alt or key . meta
2014-01-03 13:32:13 -05:00
target . addClass ( ' selected ' ) if @ addThangType
false
moveAddThangSelection: (direction) ->
return unless @ addThangType
icons = $ ( ' .add-thangs-palette .add-thang-palette-icon ' )
selectedIcon = icons . filter ( ' .selected ' )
selectedIndex = icons . index selectedIcon
nextSelectedIndex = ( selectedIndex + direction + icons . length ) % icons . length
@ selectAddThang { target: icons [ nextSelectedIndex ] }
selectAddThangType: (type, @cloneSourceThang) ->
if _ . isString type
type = _ . find @ supermodel . getModels ( ThangType ) , (m) -> m . get ( " name " ) is type
pos = @ addThangSprite ? . thang . pos # Maintain old sprite's pos if we have it
@ surface . spriteBoss . removeSprite @ addThangSprite if @ addThangSprite
@addThangType = type
if @ addThangType
2014-01-28 12:22:23 -05:00
@ surface . camera . lock ( )
2014-01-03 13:32:13 -05:00
thang = @ createAddThang ( )
@addThangSprite = @ surface . spriteBoss . addThangToSprites thang , @ surface . spriteBoss . spriteLayers [ " Floating " ]
@addThangSprite.notOfThisWorld = true
@addThangSprite.displayObject.alpha = 0.75
@ addThangSprite . playSound ? ' selected '
pos ? = x: Math . round ( @ world . width / 2 ) , y: Math . round ( @ world . height / 2 )
@ adjustThangPos @ addThangSprite , thang , pos
else
@ surface . camera . unlock ( )
@addThangSprite = null
createEssentialComponents: ->
[
{ original: componentOriginals [ " existence.Exists " ] , majorVersion: 0 , config: { } }
{ original: componentOriginals [ " physics.Physical " ] , majorVersion: 0 , config: { pos: { x: 10 , y: 10 , z: 1 } , width: 2 , height: 2 , depth: 2 , shape: " box " } }
]
createAddThang: ->
allComponents = ( lc . attributes for lc in @ supermodel . getModels LevelComponent )
rawComponents = @ addThangType . get ( ' components ' ) ? [ ]
rawComponents = @ createEssentialComponents ( ) unless rawComponents . length
mockThang = { components: rawComponents }
@ level . sortThangComponents [ mockThang ] , allComponents
components = [ ]
for raw in mockThang . components
comp = _ . find allComponents , { original: raw . original }
continue if comp . name in [ ' Selectable ' , ' Attackable ' ] # Don't draw health bars or intercept clicks
componentClass = @ world . loadClassFromCode comp . js , comp . name , " component "
components . push [ componentClass , raw . config ]
thang = new Thang @ world , @ addThangType . get ( ' name ' ) , " Add Thang Phantom "
thang . addComponents components . . .
thang
adjustThangPos: (sprite, thang, pos) ->
snap = sprite ? . data ? . snap or sprite ? . thangType ? . get ( ' snap ' ) or { x: 0.01 , y: 0.01 } # Centimeter resolution by default
pos.x = Math . round ( ( pos . x - thang . width / 2 ) / snap . x ) * snap . x + thang . width / 2
pos.y = Math . round ( ( pos . y - thang . height / 2 ) / snap . y ) * snap . y + thang . height / 2
pos.z = thang . depth / 2
thang.pos = pos
@ surface . spriteBoss . update true # Make sure Obstacle layer resets cache
onSurfaceMouseMoved: (e) ->
return unless @ addThangSprite
wop = @ surface . camera . canvasToWorld x: e . x , y: e . y
wop.z = 0.5
@ adjustThangPos @ addThangSprite , @ addThangSprite . thang , wop
null
onSurfaceMouseOver: (e) ->
return unless @ addThangSprite
@addThangSprite.displayObject.visible = true
onSurfaceMouseOut: (e) ->
return unless @ addThangSprite
@addThangSprite.displayObject.visible = false
calculateMovement: (pctX, pctY, widthHeightRatio) ->
MOVE_TOP_MARGIN = 1.0 - MOVE_MARGIN
if MOVE_TOP_MARGIN > pctX > MOVE_MARGIN and MOVE_TOP_MARGIN > pctY > MOVE_MARGIN
clearInterval ( @ movementInterval ) if @ movementInterval ?
@movementInterval = null
return @moveLatitude = @moveLongitude = @speed = 0
# calculating speed to be 0.0 to 1.0 within the movement buffer on the outer edge
diff = ( MOVE_MARGIN * 2 ) # comments are assuming MOVE_MARGIN is 0.1
@speed = Math . max ( Math . abs ( pctX - 0.5 ) , Math . abs ( pctY - 0.5 ) ) * 2 # pct is now 0.8 - 1.0
@ speed -= 1.0 - diff # 0.0 - 0.2
@ speed *= ( 1.0 / diff ) # 0.0 - 1.0
@ speed *= MOVE_SPEED
@moveLatitude = pctX * 2 - 1
@moveLongitude = pctY * 2 - 1
@ moveLongitude /= widthHeightRatio if widthHeightRatio > 1.0
@ moveLatitude *= widthHeightRatio if widthHeightRatio < 1.0
@movementInterval = setInterval ( @ moveSide , 16 ) unless @ movementInterval ?
moveSide: =>
return unless @ speed
c = @ surface . camera
p = { x : c . target . x + @ moveLatitude * @ speed / c . zoom , y : c . target . y + @ moveLongitude * @ speed / c . zoom }
c . zoomTo ( p , c . zoom , 0 )
deleteSelectedExtantThang: (e) =>
return if $ ( e . target ) . hasClass ' treema-node '
@ thangsTreema . onDeletePressed e
@ onTreemaThangSelected null , @ thangsTreema . getSelectedTreemas ( )
Thang . resetThangIDs ( ) # TODO: find some way to do this when we delete from treema, too
onThangsChanged: (e) =>
@ level . set ' thangs ' , @ thangsTreema . data
2014-03-14 14:58:29 -04:00
return if @ editThangView
2014-01-03 13:32:13 -05:00
serializedLevel = @ level . serialize @ supermodel
2014-02-03 17:01:20 -05:00
try
@ world . loadFromLevel serializedLevel , false
catch error
console . error ' Catastrophic error loading the level: ' , error
2014-01-03 13:32:13 -05:00
thang.isSelectable = not thang . isLand for thang in @ world . thangs # let us select walls and such
@ surface ? . setWorld @ world
2014-01-28 12:22:23 -05:00
@ selectAddThangType @ addThangType , @ cloneSourceThang if @ addThangType # make another addThang sprite, since the World just refreshed
2014-01-03 13:32:13 -05:00
Backbone . Mediator . publish ' level-thangs-changed ' , thangsData: @ thangsTreema . data
null
onTreemaThangSelected: (e, selectedTreemas) =>
selectedThangID = _ . last ( selectedTreemas ) ? . data . id
if selectedThangID isnt @ selectedExtantThang ? . id
2014-03-14 16:27:29 -04:00
@ surface . spriteBoss . selectThang selectedThangID , null , true
2014-01-03 13:32:13 -05:00
onTreemaThangDoubleClicked: (e, treema) =>
id = treema ? . data ? . id
@ editThang thangID: id if id
addThang: (thangType, pos) ->
2014-01-29 13:14:12 -05:00
thangID = Thang . nextID ( thangType . get ( ' name ' ) , @ world ) until thangID and not @ thangsTreema . get " id= #{ thangID } "
2014-01-03 13:32:13 -05:00
if @ cloneSourceThang
components = _ . cloneDeep @ thangsTreema . get " id= #{ @ cloneSourceThang . id } /components "
@ selectAddThang null
else
components = _ . cloneDeep thangType . get ( ' components ' ) ? [ ]
components = @ createEssentialComponents ( ) unless components . length
physical = _ . find components , (c) -> c . config ? . pos ?
physical.config.pos = x: pos . x , y: pos . y , z: physical . config . pos . z if physical
thang = thangType: thangType . get ( ' original ' ) , id: thangID , components: components
@ thangsTreema . insert ' ' , thang
2014-01-21 00:19:54 -05:00
@ supermodel . populateModel thangType # Make sure we grab any new data for the thang we just added
2014-01-03 13:32:13 -05:00
editThang: (e) ->
if e . target # click event
thangData = $ ( e . target ) . data ' thang-data '
else # Mediator event
window . thangsTreema = @ thangsTreema
thangData = @ thangsTreema . get " id= #{ e . thangID } "
@editThangView = new LevelThangEditView thangData: thangData , supermodel: @ supermodel , level: @ level , world: @ world
@ insertSubView @ editThangView
2014-02-13 12:26:21 -05:00
@ $el . find ( ' .thangs-column ' ) . hide ( )
2014-01-03 13:32:13 -05:00
Backbone . Mediator . publish ' level:view-switched ' , e
onLevelThangEdited: (e) ->
newThang = e . thangData
@ thangsTreema . set " id= #{ e . id } " , newThang
onLevelThangDoneEditing: ->
@ removeSubView @ editThangView
2014-03-14 14:58:29 -04:00
@editThangView = null
@ onThangsChanged ( )
2014-02-13 12:26:21 -05:00
@ $el . find ( ' .thangs-column ' ) . show ( )
2014-01-03 13:32:13 -05:00
class ThangsNode extends TreemaNode . nodeMap . array
valueClass: ' treema-array-replacement '
getChildren: ->
children = super ( arguments . . . )
2014-01-21 00:19:54 -05:00
# TODO: add some filtering to only work with certain types of units at a time
2014-01-03 13:32:13 -05:00
return children
class ThangNode extends TreemaObjectNode
valueClass: ' treema-thang '
collection: false
2014-01-21 00:19:54 -05:00
@thangNameMap: { }
2014-01-21 13:42:09 -05:00
@thangKindMap: { }
2014-01-03 13:32:13 -05:00
buildValueForDisplay: (valEl) ->
pos = _ . find ( @ data . components , (c) -> c . config ? . pos ? ) ? . config . pos # TODO: hack
s = " #{ @ data . thangType } "
if isObjectID s
2014-01-21 00:19:54 -05:00
unless name = ThangNode . thangNameMap [ s ]
thangType = _ . find @ settings . supermodel . getModels ( ThangType ) , (m) -> m . get ( ' original ' ) is s
name = ThangNode . thangNameMap [ s ] = thangType . get ' name '
2014-01-21 13:42:09 -05:00
ThangNode . thangKindMap [ s ] = thangType . get ' kind '
kind = ThangNode . thangKindMap [ s ]
@ $el . addClass " treema- #{ kind } "
2014-01-21 00:19:54 -05:00
s = name
2014-01-03 13:32:13 -05:00
s += " - " + @ data . id if @ data . id isnt s
if pos
s += " ( #{ Math . round ( pos . x ) } , #{ Math . round ( pos . y ) } ) "
else
s += " (non-physical) "
@ buildValueForDisplaySimply valEl , s
onEnterPressed: ->
Backbone . Mediator . publish ' edit-level-thang ' , levelThang: @ data . id