From a1a7ee5dc9b953b5c16f1a7600e51f63f72cbf55 Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Tue, 6 Jan 2015 10:25:05 -0800 Subject: [PATCH] Initial implementation of the InventoryController --- Gruntfile.coffee | 1 - src/css/main.scss | 23 +-- src/css/reset.scss | 1 + src/css/templates/index.scss | 2 + src/css/templates/inventory.scss | 85 +++++++++ src/css/templates/item_page.scss | 19 ++ src/css/templates/stack.scss | 15 +- .../controllers/inventory_controller.coffee | 164 ++++++++++++++++++ .../controllers/item_page_controller.coffee | 16 +- src/scripts/models/crafting_table.coffee | 1 + src/scripts/models/inventory.coffee | 1 + src/templates/inventory.jade | 20 +++ src/templates/item_page.jade | 5 +- 13 files changed, 330 insertions(+), 23 deletions(-) create mode 100644 src/css/templates/inventory.scss create mode 100644 src/css/templates/item_page.scss create mode 100644 src/scripts/controllers/inventory_controller.coffee create mode 100644 src/templates/inventory.jade diff --git a/Gruntfile.coffee b/Gruntfile.coffee index afc52939c..e9356d034 100644 --- a/Gruntfile.coffee +++ b/Gruntfile.coffee @@ -92,7 +92,6 @@ module.exports = (grunt)-> options: client: true node: true - pretty: true processName: (f)-> f = f.replace './src/templates/', '' f = f.replace '_view', '' diff --git a/src/css/main.scss b/src/css/main.scss index b252e9e56..16ec412a7 100644 --- a/src/css/main.scss +++ b/src/css/main.scss @@ -25,21 +25,25 @@ $color-brick-dark: #7A7A7A; $color-brick-light: #D9D9D9; $color-content: rgba(230, 230, 230, 0.90); $color-dirt: #906647; +$color-error-new: #CD0000; +$color-error: #F3C2C2; $color-ice: #8AA7E6; $color-footer: #3D1D09; $color-footer-text: white; $color-gray-faint: #F2F2F2; $color-gray-light: #CCCCCC; $color-table-background: white; +$color-toolbar-background: rgba(255, 255, 255, 0.75); $font-family-header: 'PressStart'; $font-family-normal: sans-serif; $font-family-input: monospace; -$font-size-small: 1.1em; -$font-size-normal: 1.3em; -$font-size-large: 2.0em; -$font-size-x-large: 3.0em; +$font-size-small: 1.1em; +$font-size-normal: 1.3em; +$font-size-large: 1.6em; +$font-size-x-large: 2.0em; +$font-size-xx-large: 3.0em; // Common ////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -61,7 +65,7 @@ h1 { p { font-family: $font-family-header; - font-size: $font-size-x-large; + font-size: $font-size-xx-large; position: relative; top: -0.5em; } } @@ -79,7 +83,7 @@ h2 { p { font-family: $font-family-header; - font-size: $font-size-large; + font-size: $font-size-x-large; position: relative; top: -0.25em; } } @@ -119,12 +123,9 @@ label { width: 100%; } -.page > div { - position: relative; width: 100%; - padding: 2em 2em 0 2em; +.error { background: $color-error; } - &:first-child { padding-top: 0; } -} +.error-new { background: $color-error-new; } // Views /////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/css/reset.scss b/src/css/reset.scss index 439b93c34..eaaaa4f61 100644 --- a/src/css/reset.scss +++ b/src/css/reset.scss @@ -41,6 +41,7 @@ th,td,caption { font-weight: normal; vertical-align: top; text-align: left; + @include box-sizing(border-box); } q { diff --git a/src/css/templates/index.scss b/src/css/templates/index.scss index 2da3b46db..d15d1f2b9 100644 --- a/src/css/templates/index.scss +++ b/src/css/templates/index.scss @@ -6,5 +6,7 @@ All rights reserved. */ @import 'crafting_table'; +@import 'inventory'; +@import 'item_page'; @import 'mod_pack'; @import 'stack'; diff --git a/src/css/templates/inventory.scss b/src/css/templates/inventory.scss new file mode 100644 index 000000000..dd5131c1d --- /dev/null +++ b/src/css/templates/inventory.scss @@ -0,0 +1,85 @@ +/* +Crafting Guide - inventory.scss + +Copyright (c) 2014-2015 by Redwood Labs +All rights reserved. +*/ + +.view__inventory { + min-height: 14em; + width: 100%; + + .edit td { + padding-top: 1em; + } + + .panel { + position: absolute; top: 5em; right: 2em; bottom: 0; left: 2em; + background: $color-table-background; + text-align: right; + } + + .scrollbox { + position: absolute; top: 0em; right: 0em; bottom: 3em; left: 0em; + padding: 0.5em 1em; + overflow: auto; + } + + .toolbar { + position: absolute; right: 0; bottom: 0; left: 0; height: 3em; + background: $color-toolbar-background; + border-top: 1px solid $color-gray-light; + } + + button[name="clear"] { + position: absolute; bottom: 0.5em; right: 0.5em; + } + + input { + border: 1px solid $color-gray-light; + } + + table { + width: 100%; + } + + td { + height: 3.6em; + padding-bottom: 0.25em; + + &:nth-child(1) { + width: 3.6em; + + input { + border-radius: 0.75em; + margin: 0 auto; + text-align: center; + width: 90%; + } + } + + &:nth-child(2) { + @include box-sizing(content-box); + padding: 0 2.0em 0 1.0em; + + input { + height: 100%; width: 100%; + border: 0; + border-bottom: 1px dashed $color-gray-light; + outline: 0; + + &:focus { + border: 1px solid $color-gray-light; + } + } + } + + &:nth-child(3) { + width: 3.6em; + + button { + width: 100%; + } + } + } +} diff --git a/src/css/templates/item_page.scss b/src/css/templates/item_page.scss new file mode 100644 index 000000000..87a135f0f --- /dev/null +++ b/src/css/templates/item_page.scss @@ -0,0 +1,19 @@ +/* +Crafting Guide - item_page.scss + +Copyright (c) 2014-2015 by Redwood Labs +All rights reserved. +*/ + +.view__item_page { + & > div { + display: inline-block; + padding: 0 2em; + position: relative; + vertical-align: top; + } + + .view__inventory { width: 50%; height: 26em; } + + .view__crafting_table, .view__mod_pack { margin-top: 2em; width: 100%; } +} diff --git a/src/css/templates/stack.scss b/src/css/templates/stack.scss index 6b7262d76..0885220de 100644 --- a/src/css/templates/stack.scss +++ b/src/css/templates/stack.scss @@ -7,17 +7,14 @@ All rights reserved. .view__stack { font-family: $font-family-normal; - - td { border-left: 0 !important; padding-bottom: 0.25em; } - - td:nth-child(2) { padding-left: 0.5em; width: 100%; } - td:nth-child(3) { width: 1.6em; } + td { vertical-align: middle; } .quantity { border-radius: 0.75em; background: $color-ice; color: $color-table-background; - font-size: $font-size-small; + font-size: $font-size-large; + font-weight: bold; text-align: center; min-width: 3em; padding: 0.1em 0.5em; @@ -25,10 +22,12 @@ All rights reserved. } .name { - font-size: $font-size-small; + display: inline; + font-size: $font-size-large; } img { - height: 1.6em; width: 1.6em; + width: 100%; height: auto; + max-height: 4.8em; } } diff --git a/src/scripts/controllers/inventory_controller.coffee b/src/scripts/controllers/inventory_controller.coffee new file mode 100644 index 000000000..60a1c7333 --- /dev/null +++ b/src/scripts/controllers/inventory_controller.coffee @@ -0,0 +1,164 @@ +### +Crafting Guide - inventory_controller.coffee + +Copyright (c) 2014-2015 by Redwood Labs +All rights reserved. +### + +BaseController = require './base_controller' +{Duration} = require '../constants' +{Key} = require '../constants' +StackController = require './stack_controller' + +######################################################################################################################## + +module.exports = class InventoryController extends BaseController + + @ONLY_DIGITS = /^[0-9]*$/ + + constructor: (options={})-> + if not options.model? then throw new Error 'options.model is required' + if not options.modPack? then throw new Error 'options.modPack is required' + + options.icon ?= '/images/chest_front.png' + options.editable ?= true + options.templateName = 'inventory' + options.title ?= 'Inventory' + super options + + @editable = options.editable + @icon = options.icon + @modPack = options.modPack + @title = options.title + + @_stackControllers = [] + + @listenTo @modPack, 'change', => @refresh() + + # Event Methods ################################################################################ + + onAddButtonClicked: -> + item = @modPack.findItemByName @$nameField.val() + return unless item? + + @model.add item.slug, parseInt(@$quantityField.val()) + @$nameField.val '' + @$quantityField.val '1' + + @$scrollbox.scrollTop @$scrollbox.prop 'scrollHeight' + + onClearButtonClicked: -> + @model.clear() + + onNameFieldBlur: -> + item = @modPack.findItemByName @$nameField.val() + @$nameField.val if item? then item.name else '' + @onNameFieldChanged() + + onNameFieldChanged: -> + item = @modPack.findItemByName @$nameField.val() + @_updateButtonState() + + onNameFieldFocused: -> + @$nameField.val '' + @$nameField.autocomplete('search') + + onNameFieldKeyUp: (event)-> + if event.which is Key.Return + @onAddButtonClicked() + + onQuantityFieldBlur: -> + value = @$quantityField.val().replace /[^0-9]/g, '' + if value.length is 0 then value = '1' + @$quantityField.val value + @onQuantityFieldChanged() + + onQuantityFieldChanged: -> + if not @$quantityField.val().match /^[0-9]*$/ + @$quantityField.addClass 'error', 0 + @$quantityField.addClass 'error-new', 0 + @$quantityField.removeClass 'error-new', Duration.slow + @$quantityField.focus() + return + + @$quantityField.removeClass 'error', Duration.fast + @$quantityField.removeClass 'error-new', Duration.fast + @_updateButtonState() + + # BaseController Overrides ##################################################################### + + onDidRender: -> + @$addButton = @$('button[name="add"]') + @$clearButton = @$('button[name="clear"]') + @$icon = @$('.icon') + @$editPanel = @$('.edit') + @$nameField = @$('input[name="name"]') + @$quantityField = @$('input[name="quantity"]') + @$scrollbox = @$('.scrollbox') + @$table = @$('table') + @$title = @$('.title') + super + + refresh: -> + display = if @editable then 'block' else 'none' + @$clearButton.css display:(if @editable then 'block' else 'none') + @$editPanel.css display:(if @editable then 'table-row' else 'none') + + @$icon.attr 'src', @icon + @$title.html @title + + if _.isEmpty(@$quantityField.val()) then @$quantityField.val '1' + + @$table.find('tr:not(:last-child)').remove() + $lastRow = @$table.find 'tr:last-child' + @_stackControllers = [] + @model.each (stack)=> + options = + model: stack + modPack: @modPack + onRemove: if not @editable then null else (stack)=> @_removeStack(stack) + + controller = new StackController options + controller.render() + controller.$el.insertBefore $lastRow + @_stackControllers.push controller + + @_updateNameAutocomplete() + @_updateButtonState() + + super + + # Backbone.View Overrides ###################################################################### + + events: + 'blur input[name="name"]': 'onNameFieldBlur' + 'blur input[name="quantity"]': 'onQuantityFieldBlur' + 'click button[name="add"]': 'onAddButtonClicked' + 'click button[name="clear"]': 'onClearButtonClicked' + 'focus input[name="name"]': 'onNameFieldFocused' + 'input input[name="name"]': 'onNameFieldChanged' + 'input input[name="quantity"]': 'onQuantityFieldChanged' + 'keyup input[name="name"]': 'onNameFieldKeyUp' + + # Private Methods ############################################################################## + + _removeStack: (stack)-> + + _updateNameAutocomplete: -> + onChanged = => @onNameFieldChanged() + + @$nameField.autocomplete + source: @modPack.gatherRecipeNames() + delay: 0 + minLength: 0 + change: onChanged + close: onChanged + select: onChanged + + _updateButtonState: -> + if @model.isEmpty then @$clearButton.attr('disabled', 'disabled') else @$clearButton.removeAttr('disabled') + + itemValid = @modPack.findItemByName(@$nameField.val())? + quantityValid = @$quantityField.val().match(InventoryController.ONLY_DIGITS) + disable = not (itemValid and quantityValid) + if disable then @$addButton.attr('disabled', 'disabled') else @$addButton.removeAttr('disabled') diff --git a/src/scripts/controllers/item_page_controller.coffee b/src/scripts/controllers/item_page_controller.coffee index a058e4cb6..a3d981f7b 100644 --- a/src/scripts/controllers/item_page_controller.coffee +++ b/src/scripts/controllers/item_page_controller.coffee @@ -7,8 +7,9 @@ All rights reserved. BaseController = require './base_controller' CraftingTableController = require './crafting_table_controller' -ItemPage = require '../models/item_page' -ModPackController = require './mod_pack_controller' +InventoryController = require './inventory_controller' +ItemPage = require '../models/item_page' +ModPackController = require './mod_pack_controller' ######################################################################################################################## @@ -28,6 +29,17 @@ module.exports = class ItemPageController extends BaseController # BaseController Overrides ##################################################################### onDidRender: -> + options = model:@model.table.have, modPack:@model.modPack, editable:true + @haveController = @addChild InventoryController, '.view__inventory.have', options + + options = + editable: false + icon: '/images/workbench_top.png', + model: @model.table.want, + modPack: @model.modPack, + title: 'Items to Craft' + @wantController = @addChild InventoryController, '.view__inventory.want', options + @modPackController = @addChild ModPackController, '.view__mod_pack', model:@model.modPack @tableController = @addChild CraftingTableController, '.view__crafting_table', model:@model.table super diff --git a/src/scripts/models/crafting_table.coffee b/src/scripts/models/crafting_table.coffee index d3795285d..9bac60837 100644 --- a/src/scripts/models/crafting_table.coffee +++ b/src/scripts/models/crafting_table.coffee @@ -21,6 +21,7 @@ module.exports = class CraftingTable extends BaseModel attributes.includingTools ?= false attributes.have ?= new Inventory attributes.plan ?= null + attributes.want ?= new Inventory super attributes, options # Public Methods ############################################################################### diff --git a/src/scripts/models/inventory.coffee b/src/scripts/models/inventory.coffee index d9555a502..9bd90f373 100644 --- a/src/scripts/models/inventory.coffee +++ b/src/scripts/models/inventory.coffee @@ -44,6 +44,7 @@ module.exports = class Inventory extends BaseModel clear: -> @_stacks = {} @_slugs = [] + @trigger 'change', self clone: -> inventory = new Inventory diff --git a/src/templates/inventory.jade b/src/templates/inventory.jade new file mode 100644 index 000000000..ca88ac795 --- /dev/null +++ b/src/templates/inventory.jade @@ -0,0 +1,20 @@ +//- +//- Crafting Guide - inventory.jade +//- +//- Copyright (c) 2014-2015 by Redwood Labs +//- All rights reserved. +//- + +.view__inventory + h2 + img.icon + p.title + .panel + .scrollbox + table + tr.edit + td: input(name="quantity") + td(width="*"): input(name="name") + td: button(name="add") add + .toolbar + button(name="clear") clear diff --git a/src/templates/item_page.jade b/src/templates/item_page.jade index 9ae307748..784a18678 100644 --- a/src/templates/item_page.jade +++ b/src/templates/item_page.jade @@ -5,6 +5,9 @@ //- All rights reserved. //- -.view__landing_page +.view__item_page + .view__inventory.have + .view__inventory.want + .view__crafting_table .view__mod_pack