From 827f6ee8b883187c262d3d55c93b25ac3db64a21 Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Thu, 14 Aug 2014 13:41:32 -0700 Subject: [PATCH] Added a swap button, as well as moving my testing to the demo view and adding some specifications, fixing bugs and tweaking interactions along the way. --- app/Router.coffee | 1 - app/styles/game-menu/inventory-view.sass | 44 +++--- app/templates/game-menu/inventory-view.jade | 4 +- app/views/DemoView.coffee | 1 + app/views/game-menu/InventoryView.coffee | 132 ++++++++++++------ .../views/game-menu/InventoryView.spec.coffee | 71 ++++++++++ .../views/game-menu/InventoryView.demo.coffee | 17 +++ 7 files changed, 204 insertions(+), 66 deletions(-) create mode 100644 test/app/views/game-menu/InventoryView.spec.coffee create mode 100644 test/demo/views/game-menu/InventoryView.demo.coffee diff --git a/app/Router.coffee b/app/Router.coffee index 98229b552..2fda8dbc7 100644 --- a/app/Router.coffee +++ b/app/Router.coffee @@ -15,7 +15,6 @@ module.exports = class CocoRouter extends Backbone.Router routes: '': go('HomeView') - 'items': go('game-menu/InventoryView') 'about': go('AboutView') diff --git a/app/styles/game-menu/inventory-view.sass b/app/styles/game-menu/inventory-view.sass index 3cec60ad8..afb9e6f02 100644 --- a/app/styles/game-menu/inventory-view.sass +++ b/app/styles/game-menu/inventory-view.sass @@ -1,17 +1,19 @@ $selected-area-height: 150px +@import "../bootstrap/mixins" + +//#inventory-view * + #inventory-view position: relative height: 600px - background-color: white - user-select: none + +user-select(none) h3 margin: 0 #equipped - padding: 10px - width: 74% + width: 75% position: absolute left: 0 top: 0 @@ -24,7 +26,7 @@ $selected-area-height: 150px .panel text-align: center - width: 31% + width: 31.3% margin: 5px 2% 5px 0 float: left cursor: pointer @@ -42,29 +44,23 @@ $selected-area-height: 150px font-size: 12px #available-equipment - width: 24% - padding: 10px + width: 25% position: absolute - right: 1% + right: 0 top: 0 bottom: $selected-area-height + 10 overflow: scroll - user-select: none h3 margin-bottom: 5px - + .list-group-item.active background-color: #e0f0f5 .list-group-item.equipped display: none - .item-mixin - &.active - background-color: lightblue - .well - padding: 5px + .item-view cursor: pointer #selected-items @@ -73,13 +69,17 @@ $selected-area-height: 150px left: 0 right: 0 bottom: 0 + text-align: center #selected-equipped-item, #selected-available-item + text-align: left position: absolute bottom: 0 top: 0 overflow: scroll padding: 10px + height: 100% + width: 49% img width: 100px @@ -90,8 +90,16 @@ $selected-area-height: 150px #selected-equipped-item left: 0 - width: 48.5% #selected-available-item - right: 2% - width: 48.5% + right: 0 + + $swap-item-height: 40px + + #swap-button + position: relative + top: ($selected-area-height / 2) - ($swap-item-height / 2) + height: $swap-item-height + font-size: 24px + line-height: 24px + display: inline-block \ No newline at end of file diff --git a/app/templates/game-menu/inventory-view.jade b/app/templates/game-menu/inventory-view.jade index 7bf5182ee..0f474aa01 100644 --- a/app/templates/game-menu/inventory-view.jade +++ b/app/templates/game-menu/inventory-view.jade @@ -16,7 +16,7 @@ div#equipped - } div#available-equipment - h3 Available + h3 Stash for item in items .list-group-item(class=item.classes, data-item-id=item.id) @@ -25,3 +25,5 @@ div#selected-items .item-view-stub #selected-available-item.well .item-view-stub + button#swap-button.btn.btn-danger + span.glyphicon.glyphicon-transfer diff --git a/app/views/DemoView.coffee b/app/views/DemoView.coffee index 24fe9090d..3e356e631 100644 --- a/app/views/DemoView.coffee +++ b/app/views/DemoView.coffee @@ -87,6 +87,7 @@ module.exports = DemoView = class DemoView extends RootView else @$el.find('#demo-area').empty().append(view.$el) view.afterInsert() + window.currentDemoView = view # TODO, maybe handle root views differently than modal views differently than everything else? getAllDemoFiles: -> diff --git a/app/views/game-menu/InventoryView.coffee b/app/views/game-menu/InventoryView.coffee index c327f9271..4ba26573d 100644 --- a/app/views/game-menu/InventoryView.coffee +++ b/app/views/game-menu/InventoryView.coffee @@ -5,13 +5,6 @@ ThangType = require 'models/ThangType' CocoCollection = require 'collections/CocoCollection' ItemView = require './ItemView' -DEFAULT_EQUIPMENT = { - 'right-hand': '53e21249b82921000051ce11' - 'feet':'53e214f153457600003e3eab' - 'eyes': '53e2167653457600003e3eb3' - 'left-hand': '53e22aa153457600003e3ef5' -} - module.exports = class InventoryView extends CocoView id: 'inventory-view' className: 'tab-pane' @@ -23,6 +16,7 @@ module.exports = class InventoryView extends CocoView 'click #available-equipment .list-group-item': 'onAvailableItemClick' 'dblclick #available-equipment .list-group-item': 'onAvailableItemDoubleClick' 'dblclick .item-slot .item-view': 'onEquippedItemDoubleClick' + 'click #swap-button': 'onClickSwapButton' shortcuts: 'esc': 'clearSelection' @@ -30,7 +24,7 @@ module.exports = class InventoryView extends CocoView initialize: (options) -> super(arguments...) @items = new CocoCollection([], { model: ThangType }) - @equipment = options.equipment or DEFAULT_EQUIPMENT + @equipment = options.equipment or {} @items.url = '/db/thang.type?view=items&project=name,description,components,original' @supermodel.loadCollection(@items, 'items') @@ -87,28 +81,64 @@ module.exports = class InventoryView extends CocoView onItemSlotClick: (e) -> slot = $(e.target).closest('.panel') wasActive = slot.hasClass('panel-info') - @$el.find('#equipped .panel').removeClass('panel-info') - @$el.find('#available-equipment .list-group-item').removeClass('active') if slot.hasClass('disabled') - slot.addClass('panel-info') # unless wasActive + @unselectAllSlots() + @unselectAllAvailableEquipment() if slot.hasClass('disabled') + @selectSlot(slot) unless wasActive and not $(e.target).closest('.item-view')[0] @onSelectionChanged() onAvailableItemClick: (e) -> - itemEl = $(e.target).closest('.list-group-item') - @$el.find('#available-equipment .list-group-item').removeClass('active') - itemEl.addClass('active') + itemContainer = $(e.target).closest('.list-group-item') + @unselectAllAvailableEquipment() + @selectAvailableItem(itemContainer) @onSelectionChanged() - onAvailableItemDoubleClick: -> - slot = @$el.find('#equipped .item-slot.panel-info') - slot = $('.panel:not(.disabled):first') if not slot.length + onAvailableItemDoubleClick: (e) -> + slot = @getSelectedSlot() + slot = @$el.find('.panel:not(.disabled):first') if not slot.length @unequipItemFromSlot(slot) @equipSelectedItemToSlot(slot) @onSelectionChanged() onEquippedItemDoubleClick: (e) -> + @unselectAllAvailableEquipment() slot = $(e.target).closest('.item-slot') - @unequipItemFromSlot(slot) + @selectAvailableItem(@unequipItemFromSlot(slot)) @onSelectionChanged() + + onClickSwapButton: -> + slot = @getSelectedSlot() + selectedItemContainer = @$el.find('#available-equipment .list-group-item.active') + return unless slot[0] or selectedItemContainer[0] + slot = @$el.find('.panel:not(.disabled):first') if not slot.length + itemContainer = @unequipItemFromSlot(slot) + @equipSelectedItemToSlot(slot) + @selectAvailableItem(itemContainer) + @selectSlot(slot) + @onSelectionChanged() + + getSelectedSlot: -> + @$el.find('#equipped .item-slot.panel-info') + + unselectAllAvailableEquipment: -> + @$el.find('#available-equipment .list-group-item').removeClass('active') + + unselectAllSlots: -> + @$el.find('#equipped .panel').removeClass('panel-info') + + selectSlot: (slot) -> + slot.addClass('panel-info') + + getSlot: (name) -> + @$el.find(".item-slot[data-slot=#{name}]") + + getSelectedAvailableItemContainer: -> + @$el.find('#available-equipment .list-group-item.active') + + getAvailableItemContainer: (itemID) -> + @$el.find("#available-equipment .list-group-item[data-item-id='#{itemID}']") + + selectAvailableItem: (itemContainer) -> + itemContainer?.addClass('active') unequipItemFromSlot: (slot) -> itemIDToUnequip = slot.find('.item-view').data('item-id') @@ -117,15 +147,15 @@ module.exports = class InventoryView extends CocoView for el in @$el.find('#available-equipment .list-group-item') itemID = $(el).find('.item-view').data('item-id') if itemID is itemIDToUnequip - $(el).removeClass('equipped') + return $(el).removeClass('equipped') equipSelectedItemToSlot: (slot) -> - selectedItemContainer = @$el.find('#available-equipment .list-group-item.active') + selectedItemContainer = @getSelectedAvailableItemContainer() newItemHTML = selectedItemContainer.html() - @$el.find('#available-equipment .list-group-item.active').addClass('equipped') - container = slot.find('.panel-body') - container.html(newItemHTML) - container.find('.item-view').data('item-id', selectedItemContainer.find('.item-view').data('item-id')) + selectedItemContainer .addClass('equipped') + slotContainer = slot.find('.panel-body') + slotContainer.html(newItemHTML) + slotContainer.find('.item-view').data('item-id', selectedItemContainer.find('.item-view').data('item-id')) @$el.find('.list-group-item').removeClass('active') onSelectionChanged: -> @@ -141,19 +171,10 @@ module.exports = class InventoryView extends CocoView selectedSlotItemID = selectedSlot.find('.item-view').data('item-id') if selectedSlotItemID item = _.find @items.models, {id:selectedSlotItemID} - - if not @selectedEquippedItemView - @selectedEquippedItemView = new ItemView({ - item: item, includes: {name: true, stats: true}}) - @insertSubView(@selectedEquippedItemView, @$el.find('#selected-equipped-item .item-view-stub')) - - else - @selectedEquippedItemView.$el.show() - @selectedEquippedItemView.item = item - @selectedEquippedItemView.render() + @showSelectedSlotItem(item) else - @selectedEquippedItemView?.$el.hide() + @hideSelectedSlotItem() else @$el.find('#available-equipment .list-group-item').show() @@ -170,21 +191,40 @@ module.exports = class InventoryView extends CocoView if slotName not in allowedSlots $(slotEl).addClass('disabled') - # updated selected item view - if not @selectedAvailableItemView - @selectedAvailableItemView = new ItemView({ - item: item, includes: {name: true, stats: true}}) - @insertSubView(@selectedAvailableItemView, @$el.find('#selected-available-item .item-view-stub')) - - else - @selectedAvailableItemView.$el.show() - @selectedAvailableItemView.item = item - @selectedAvailableItemView.render() + @showSelectedAvailableItem(item) else - @selectedAvailableItemView?.$el.hide() + @hideSelectedAvailableItem() @delegateEvents() + + showSelectedSlotItem: (item) -> + if not @selectedEquippedItemView + @selectedEquippedItemView = new ItemView({ + item: item, includes: {name: true, stats: true}}) + @insertSubView(@selectedEquippedItemView, @$el.find('#selected-equipped-item .item-view-stub')) + + else + @selectedEquippedItemView.$el.show() + @selectedEquippedItemView.item = item + @selectedEquippedItemView.render() + + hideSelectedSlotItem: -> + @selectedEquippedItemView?.$el.hide() + + showSelectedAvailableItem: (item) -> + if not @selectedAvailableItemView + @selectedAvailableItemView = new ItemView({ + item: item, includes: {name: true, stats: true}}) + @insertSubView(@selectedAvailableItemView, @$el.find('#selected-available-item .item-view-stub')) + + else + @selectedAvailableItemView.$el.show() + @selectedAvailableItemView.item = item + @selectedAvailableItemView.render() + + hideSelectedAvailableItem: -> + @selectedAvailableItemView?.$el.hide() getCurrentEquipmentConfig: -> config = {} diff --git a/test/app/views/game-menu/InventoryView.spec.coffee b/test/app/views/game-menu/InventoryView.spec.coffee new file mode 100644 index 000000000..3e66b5035 --- /dev/null +++ b/test/app/views/game-menu/InventoryView.spec.coffee @@ -0,0 +1,71 @@ +InventoryView = require 'views/game-menu/InventoryView' + +thangTypes = [ + {"_id":"boots-id","name":"Boots","original":"boots","components":[{"original":"524b85837fc0f6d519000020","majorVersion":0},{"original":"524b7b857fc0f6d519000012","majorVersion":0},{"original":"524b4150ff92f1f4f8000024","majorVersion":0},{"original":"53e12043b82921000051cdf9","majorVersion":0,"config":{"slots":["feet"],"programmableProperties":["move","targetPos"],"moreProgrammableProperties":[],"extraHUDProperties":["maxSpeed"],"stats":{"maxSpeed":{"factor":1}}}},{"original":"524b7b8c7fc0f6d519000013","majorVersion":0,"config":{"locomotionType":"running","maxSpeed":5,"maxAcceleration":100}},{"original":"524b75ad7fc0f6d519000001","majorVersion":0,"config":{"pos":{"x":39.08,"y":20.72,"z":0.5},"width":1,"height":1,"depth":1,"shape":"ellipsoid"}},{"original":"524b7b7c7fc0f6d519000011","majorVersion":0}]}, + {"_id":"boots-of-leaping-id","name":"Boots of Leaping","original":"boots-of-leaping","components":[{"original":"524b85837fc0f6d519000020","majorVersion":0},{"original":"524b7b857fc0f6d519000012","majorVersion":0},{"original":"524b4150ff92f1f4f8000024","majorVersion":0},{"original":"53e12043b82921000051cdf9","majorVersion":0,"config":{"ownerID":"Tharin","slots":["feet"],"programmableProperties":["move","targetPos","jumpTo"],"moreProgrammableProperties":["jump"],"extraHUDProperties":["maxSpeed"],"stats":{"maxSpeed":{"factor":1.2}}}},{"original":"524b7b8c7fc0f6d519000013","majorVersion":0,"config":{"locomotionType":"running","maxSpeed":6,"maxAcceleration":100}},{"original":"524b1f54d768d916b5000001","majorVersion":0,"config":{"jumpHeight":3}},{"original":"5275392d69abdcb12401441e","majorVersion":0,"config":{"jumpSpeedFactor":1.5}},{"original":"524b75ad7fc0f6d519000001","majorVersion":0,"config":{"pos":{"x":39.08,"y":20.72,"z":0.5},"width":1,"height":1,"depth":1,"shape":"ellipsoid"}},{"original":"524b7b7c7fc0f6d519000011","majorVersion":0}]}, + {"_id":"crossbow-id","name":"Crossbow","original":"crossbow","components":[{"original":"524b85837fc0f6d519000020","majorVersion":0},{"original":"524b517fff92f1f4f8000046","majorVersion":0},{"original":"524b7b747fc0f6d519000010","majorVersion":0,"config":{"team":"humans"}},{"original":"524b7bc67fc0f6d51900001a","majorVersion":0,"config":{"missileThangID":"Arrow"}},{"original":"524b7ba57fc0f6d519000016","majorVersion":0,"config":{"attackDamage":5,"attackRange":20,"cooldown":0.6,"chasesWhenAttackingOutOfRange":true}},{"original":"524b3e3fff92f1f4f800000d","majorVersion":0},{"original":"524cbdc03ea855e0ab0000bb","majorVersion":0},{"original":"524b4150ff92f1f4f8000024","majorVersion":0},{"original":"53e12043b82921000051cdf9","majorVersion":0,"config":{"slots":["right-hand"],"programmableProperties":["attack","target","attackRange"],"moreProgrammableProperties":["attackXY","targetPos"],"extraHUDProperties":["attackDamage","attackRange"]}},{"original":"524b75ad7fc0f6d519000001","majorVersion":0,"config":{"pos":{"x":41.105000000000004,"y":31.6,"z":0.125},"width":1.5,"height":0.75,"depth":0.25,"shape":"box"}},{"original":"524b7b7c7fc0f6d519000011","majorVersion":0},{"original":"524b457bff92f1f4f8000031","majorVersion":0}]}, + {"_id":"crude-glasses-id","name":"Crude Glasses","original":"crude-glasses","components":[{"original":"524b7b747fc0f6d519000010","majorVersion":0,"config":{"team":"humans"}},{"original":"524b4150ff92f1f4f8000024","majorVersion":0},{"original":"53e12043b82921000051cdf9","majorVersion":0,"config":{"slots":["eyes"],"programmableProperties":["pos","getEnemies"],"moreProgrammableProperties":["getItems","getFriends"]}},{"original":"524b75ad7fc0f6d519000001","majorVersion":0,"config":{"pos":{"x":33.230000000000004,"y":20.75,"z":2},"width":1,"height":2,"depth":1,"shape":"ellipsoid"}},{"original":"524b457bff92f1f4f8000031","majorVersion":0,"config":{"visualRange":50}}]} +] + +describe 'InventoryView', -> + inventoryView = null + + beforeEach (done) -> + equipment = { 'feet':'boots', 'eyes': 'crude-glasses' } + inventoryView = new InventoryView({ equipment: equipment }) + responses = + '/db/thang.type?view=items': thangTypes + jasmine.Ajax.requests.sendResponses(responses) + _.defer -> + inventoryView.render() + done() + + it 'selects a slot when you click it', -> + inventoryView.getSlot('eyes').click() + expect(inventoryView.getSelectedSlot().data('slot')).toBe('eyes') + + it 'unselects a selected slot when you click it', -> + inventoryView.getSlot('eyes').click().click() + expect(inventoryView.getSelectedSlot().data('slot')).toBeUndefined() + + it 'selects an available item when you click it', -> + inventoryView.getAvailableItemContainer('boots-of-leaping-id').click() + expect(inventoryView.getSelectedAvailableItemContainer().data('item-id')).toBe('boots-of-leaping-id') + + it 'equips an available item when you double click it', -> + inventoryView.getAvailableItemContainer('crossbow-id').click().dblclick() + expect(inventoryView.getCurrentEquipmentConfig()['right-hand']).toBeTruthy() + + it 'unequips an itm when you double click it', -> + inventoryView.getSlot('eyes').find('.item-view').click().dblclick() + expect(inventoryView.getCurrentEquipmentConfig().eyes).toBeUndefined() + + describe 'swap button', -> + it 'does nothing if nothing is selected', -> + inventoryView.$el.find('#swap-button').click() + expect(inventoryView.getSelectedSlot()[0]).toBeFalsy() + expect(inventoryView.getSelectedAvailableItemContainer()[0]).toBeFalsy() + + it 'unequips and selects the unequipped item if just an equipped slot is chosen', -> + expect(inventoryView.getCurrentEquipmentConfig().eyes).toBeTruthy() + slot = inventoryView.getSlot('eyes') + inventoryView.selectSlot(slot) + inventoryView.$el.find('#swap-button').click() + expect(inventoryView.getCurrentEquipmentConfig().eyes).toBeUndefined() + expect(inventoryView.getSelectedAvailableItemContainer().data('item-id')).toBe('crude-glasses-id') + + it 'equips the selected item if just an available item is selected', -> + expect(inventoryView.getCurrentEquipmentConfig()['right-hand']).toBeUndefined() + inventoryView.getAvailableItemContainer('crossbow-id').click() + inventoryView.$el.find('#swap-button').click() + expect(inventoryView.getCurrentEquipmentConfig()['right-hand']).toBeTruthy() + expect(inventoryView.getSelectedAvailableItemContainer().data('item-id')).toBeUndefined() + expect(inventoryView.getSelectedSlot().data('slot')).toBe('right-hand') + + it 'swaps items if both a slot and item are selected, and keeps them selected', -> + inventoryView.getAvailableItemContainer('boots-of-leaping-id').click() + inventoryView.getSlot('feet').click() + inventoryView.$el.find('#swap-button').click() + expect(inventoryView.getCurrentEquipmentConfig()['feet']).toBe('boots-of-leaping') + expect(inventoryView.getSelectedAvailableItemContainer().data('item-id')).toBe('boots-id') + expect(inventoryView.getSelectedSlot().data('slot')).toBe('feet') \ No newline at end of file diff --git a/test/demo/views/game-menu/InventoryView.demo.coffee b/test/demo/views/game-menu/InventoryView.demo.coffee new file mode 100644 index 000000000..3cf44ce7c --- /dev/null +++ b/test/demo/views/game-menu/InventoryView.demo.coffee @@ -0,0 +1,17 @@ +InventoryView = require 'views/game-menu/InventoryView' + +thangTypes = [ + {"_id":"53eb98ff1a100989a40ce46b","name":"Boots","original":"boots","components":[{"original":"524b85837fc0f6d519000020","majorVersion":0},{"original":"524b7b857fc0f6d519000012","majorVersion":0},{"original":"524b4150ff92f1f4f8000024","majorVersion":0},{"original":"53e12043b82921000051cdf9","majorVersion":0,"config":{"slots":["feet"],"programmableProperties":["move","targetPos"],"moreProgrammableProperties":[],"extraHUDProperties":["maxSpeed"],"stats":{"maxSpeed":{"factor":1}}}},{"original":"524b7b8c7fc0f6d519000013","majorVersion":0,"config":{"locomotionType":"running","maxSpeed":5,"maxAcceleration":100}},{"original":"524b75ad7fc0f6d519000001","majorVersion":0,"config":{"pos":{"x":39.08,"y":20.72,"z":0.5},"width":1,"height":1,"depth":1,"shape":"ellipsoid"}},{"original":"524b7b7c7fc0f6d519000011","majorVersion":0}]}, + {"_id":"53eb98851a100989a40ce460","name":"Boots of Leaping","original":"boots-of-leaping","components":[{"original":"524b85837fc0f6d519000020","majorVersion":0},{"original":"524b7b857fc0f6d519000012","majorVersion":0},{"original":"524b4150ff92f1f4f8000024","majorVersion":0},{"original":"53e12043b82921000051cdf9","majorVersion":0,"config":{"ownerID":"Tharin","slots":["feet"],"programmableProperties":["move","targetPos","jumpTo"],"moreProgrammableProperties":["jump"],"extraHUDProperties":["maxSpeed"],"stats":{"maxSpeed":{"factor":1.2}}}},{"original":"524b7b8c7fc0f6d519000013","majorVersion":0,"config":{"locomotionType":"running","maxSpeed":6,"maxAcceleration":100}},{"original":"524b1f54d768d916b5000001","majorVersion":0,"config":{"jumpHeight":3}},{"original":"5275392d69abdcb12401441e","majorVersion":0,"config":{"jumpSpeedFactor":1.5}},{"original":"524b75ad7fc0f6d519000001","majorVersion":0,"config":{"pos":{"x":39.08,"y":20.72,"z":0.5},"width":1,"height":1,"depth":1,"shape":"ellipsoid"}},{"original":"524b7b7c7fc0f6d519000011","majorVersion":0}]}, + {"_id":"53e2288553457600003e3ee2","name":"Crossbow","original":"crossbow","components":[{"original":"524b85837fc0f6d519000020","majorVersion":0},{"original":"524b517fff92f1f4f8000046","majorVersion":0},{"original":"524b7b747fc0f6d519000010","majorVersion":0,"config":{"team":"humans"}},{"original":"524b7bc67fc0f6d51900001a","majorVersion":0,"config":{"missileThangID":"Arrow"}},{"original":"524b7ba57fc0f6d519000016","majorVersion":0,"config":{"attackDamage":5,"attackRange":20,"cooldown":0.6,"chasesWhenAttackingOutOfRange":true}},{"original":"524b3e3fff92f1f4f800000d","majorVersion":0},{"original":"524cbdc03ea855e0ab0000bb","majorVersion":0},{"original":"524b4150ff92f1f4f8000024","majorVersion":0},{"original":"53e12043b82921000051cdf9","majorVersion":0,"config":{"slots":["right-hand"],"programmableProperties":["attack","target","attackRange"],"moreProgrammableProperties":["attackXY","targetPos"],"extraHUDProperties":["attackDamage","attackRange"]}},{"original":"524b75ad7fc0f6d519000001","majorVersion":0,"config":{"pos":{"x":41.105000000000004,"y":31.6,"z":0.125},"width":1.5,"height":0.75,"depth":0.25,"shape":"box"}},{"original":"524b7b7c7fc0f6d519000011","majorVersion":0},{"original":"524b457bff92f1f4f8000031","majorVersion":0}]}, + {"_id":"53ecec87415ce434054f6aac","name":"Crude Glasses","original":"crude-glasses","components":[{"original":"524b7b747fc0f6d519000010","majorVersion":0,"config":{"team":"humans"}},{"original":"524b4150ff92f1f4f8000024","majorVersion":0},{"original":"53e12043b82921000051cdf9","majorVersion":0,"config":{"slots":["eyes"],"programmableProperties":["pos","getEnemies"],"moreProgrammableProperties":["getItems","getFriends"]}},{"original":"524b75ad7fc0f6d519000001","majorVersion":0,"config":{"pos":{"x":33.230000000000004,"y":20.75,"z":2},"width":1,"height":2,"depth":1,"shape":"ellipsoid"}},{"original":"524b457bff92f1f4f8000031","majorVersion":0,"config":{"visualRange":50}}]} +] + +module.exports = -> + equipment = { 'feet':'boots', 'eyes': 'crude-glasses' } + view = new InventoryView({ equipment: equipment}) + view.render() + responses = + '/db/thang.type?view=items': thangTypes + jasmine.Ajax.requests.sendResponses(responses) + return view \ No newline at end of file