From c78828426f8acbc570af09b7f0724cf506258e30 Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Tue, 24 Feb 2015 19:45:12 -0800 Subject: [PATCH] Edit quantity per row in inventory view Change the inventory view to make editing of quantities happen on the individual rows instead of having to get the quantity right before adding the item. --- src/css/classes.scss | 4 +- src/css/templates/inventory.scss | 14 ---- src/css/templates/stack.scss | 42 +++++++++--- .../controllers/inventory_controller.coffee | 40 ++---------- .../controllers/stack_controller.coffee | 64 +++++++++++++++++-- src/scripts/models/inventory.coffee | 2 + src/templates/inventory.jade | 4 +- src/templates/stack.jade | 2 +- 8 files changed, 107 insertions(+), 65 deletions(-) diff --git a/src/css/classes.scss b/src/css/classes.scss index f4f907e55..afc0e7112 100644 --- a/src/css/classes.scss +++ b/src/css/classes.scss @@ -18,9 +18,9 @@ All rights reserved. width: 100%; } -.error { background: $color-error; } +.error { background: $color-error !important; } -.error-new { background: $color-error-new; } +.error-new { background: $color-error-new !important; } .section { margin-top: 3em; diff --git a/src/css/templates/inventory.scss b/src/css/templates/inventory.scss index 14a67f973..d4f793117 100644 --- a/src/css/templates/inventory.scss +++ b/src/css/templates/inventory.scss @@ -53,20 +53,6 @@ All rights reserved. vertical-align: middle; } - td.quantity { - position: relative; - width: 2.4em; - - input { - position: absolute; top: 50%; height: $font-size-small; width: 100%; - @include transform(translateY(-50%)); - border-radius: 0.75em; - margin: 0 auto; - text-align: center; - max-width: 2.8em; - } - } - td.icon { width: 4.8em; padding: 0 1em; diff --git a/src/css/templates/stack.scss b/src/css/templates/stack.scss index 3b3f3d57f..348ba2ab6 100644 --- a/src/css/templates/stack.scss +++ b/src/css/templates/stack.scss @@ -12,15 +12,39 @@ All rights reserved. padding: 0.2em 0; } - td.quantity p { - border-radius: 0.75em; - background: $color-ice; - color: $color-background-panel; - font-size: $font-size-normal; - font-weight: bold; - text-align: center; - min-width: 3em; - padding: 0.1em 0.5em; + td.quantity { + position: relative; + width: 4em; + + input { + position: absolute; top: 50%; height: $font-size-small; width: 100%; + @include transform(translateY(-50%)); + + border-radius: 0.75em; + background: $color-ice; + color: $color-background-panel; + font-family: $font-family-normal; + font-size: $font-size-normal; + font-weight: bold; + text-align: center; + + &.editable { + &:focus { + background: $color-background-panel; + color: $color-text; + font-family: $font-family-input; + font-weight: normal; + outline: none; + } + + &:hover { + background: $color-background-panel; + color: $color-text; + font-family: $font-family-input; + font-weight: normal; + } + } + } } td.icon { diff --git a/src/scripts/controllers/inventory_controller.coffee b/src/scripts/controllers/inventory_controller.coffee index 01ec6d37c..1f7e619ee 100644 --- a/src/scripts/controllers/inventory_controller.coffee +++ b/src/scripts/controllers/inventory_controller.coffee @@ -43,12 +43,15 @@ module.exports = class InventoryController extends BaseController # Event Methods ################################################################################ onAddButtonClicked: -> + if @$nameField.val().trim().length is 0 + @$nameField.focus() + return + item = @modPack.findItemByName @$nameField.val() return unless item? - @model.add item.slug, parseInt(@$quantityField.val()) + @model.add item.slug, 1 @$nameField.val '' - @$quantityField.val '1' @$scrollbox.scrollTop @$scrollbox.prop 'scrollHeight' @$nameField.autocomplete 'close' @@ -84,28 +87,6 @@ module.exports = class InventoryController extends BaseController if event.which is Key.Return @onAddButtonClicked() - onQuantityFieldBlur: -> - value = @$quantityField.val().replace /[^0-9]/g, '' - if value.length is 0 then value = '1' - value = Math.min value, InventoryController.MAX_QUANTITY - @$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.normal - @$quantityField.removeClass 'error-new', Duration.normal - @_refreshButtonState() - - onQuantityFieldFocused: -> - @$quantityField.val '' - # BaseController Overrides ##################################################################### onDidRender: -> @@ -114,7 +95,6 @@ module.exports = class InventoryController extends BaseController @$icon = @$('.icon') @$editPanel = @$('.edit') @$nameField = @$('input[name="name"]') - @$quantityField = @$('input[name="quantity"]') @$scrollbox = @$('.scrollbox') @$table = @$('table') @$toolbar = @$('.toolbar') @@ -129,8 +109,6 @@ module.exports = class InventoryController extends BaseController @$icon.attr 'src', @icon @$title.html @title - if _.isEmpty(@$quantityField.val()) then @$quantityField.val '1' - @_refreshStacks() @_refreshNameAutocomplete() @_refreshButtonState() @@ -142,13 +120,10 @@ module.exports = class InventoryController extends BaseController events: -> return _.extend super, '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' - 'focus input[name="quantity"]': 'onQuantityFieldFocused' 'input input[name="name"]': 'onNameFieldChanged' - 'input input[name="quantity"]': 'onQuantityFieldChanged' 'keyup input[name="name"]': 'onNameFieldKeyUp' # Private Methods ############################################################################## @@ -156,9 +131,9 @@ module.exports = class InventoryController extends BaseController _refreshButtonState: -> if @model.isEmpty then @$clearButton.attr('disabled', 'disabled') else @$clearButton.removeAttr('disabled') + noText = @$nameField.val().trim().length is 0 itemValid = @modPack.findItemByName(@$nameField.val())? - quantityValid = @$quantityField.val().match(InventoryController.ONLY_DIGITS) - disable = not (itemValid and quantityValid) + disable = not (itemValid or noText) if disable then @$addButton.attr('disabled', 'disabled') else @$addButton.removeAttr('disabled') _refreshNameAutocomplete: -> @@ -171,7 +146,6 @@ module.exports = class InventoryController extends BaseController minLength: 0 change: onChanged close: onChanged - minLength: 3 select: onSelected _refreshStacks: -> diff --git a/src/scripts/controllers/stack_controller.coffee b/src/scripts/controllers/stack_controller.coffee index c3e068f37..b29d637f5 100644 --- a/src/scripts/controllers/stack_controller.coffee +++ b/src/scripts/controllers/stack_controller.coffee @@ -6,13 +6,17 @@ All rights reserved. ### BaseController = require './base_controller' +{Duration} = require '../constants' {Event} = require '../constants' ImageLoader = require './image_loader' +{Key} = require '../constants' ######################################################################################################################## module.exports = class StackController extends BaseController + @MAX_QUANTITY = 9999 + constructor: (options={})-> if not options.imageLoader? then throw new Error 'options.imageLoader is required' if not options.model? then throw new Error 'options.model is required' @@ -32,6 +36,47 @@ module.exports = class StackController extends BaseController # Event Methods ################################################################################ + onQuantityFieldBlur: -> + quantityText = @$quantityField.val().trim() + if quantityText.length is 0 + quantity = @_priorValue + else if not quantityText.match /^[0-9]*$/ + quantity = 1 + else + quantity = parseInt quantityText, 10 + if _.isNaN quantity then quantity = 1 + + quantity = Math.min quantity, StackController.MAX_QUANTITY + quantity = Math.max 1, quantity + + if quantity? + @$quantityField.val "#{quantity}" + @$quantityField.removeClass 'error', Duration.snap + @$quantityField.removeClass 'error-new', Duration.snap + + @model.quantity = quantity + + onQuantityFieldChanged: -> + quantityText = @$quantityField.val().trim() + if not quantityText.match /^[0-9]*$/ + @$quantityField.addClass 'error', 0 + @$quantityField.addClass 'error-new', 0 + @$quantityField.removeClass 'error-new', Duration.fast + else + @$quantityField.removeClass 'error', Duration.snap + @$quantityField.removeClass 'error-new', Duration.snap + + onQuantityFieldFocused: -> + if @editable + @_priorValue = @model.quantity + @$quantityField.val '' + else + @$quantityField.blur() + + onQuantityKeyUp: (event)-> + if event.which is Key.Return + @$quantityField.blur() + onRemoveClicked: -> @onRemove @model @@ -41,7 +86,7 @@ module.exports = class StackController extends BaseController @$action = @$('.action') @$image = @$('.icon img') @$nameLink = @$('.name a') - @$quantityField = @$('.quantity p') + @$quantityField = @$('.quantity input') @$removeButton = @$('button.remove') super @@ -51,7 +96,14 @@ module.exports = class StackController extends BaseController @_imageLoader.load display.iconUrl, @$image @$nameLink.html display.itemName @$nameLink.attr 'href', display.itemUrl - @$quantityField.html @model.quantity + @$quantityField.val @model.quantity + + if @editable + @$quantityField.removeAttr 'readonly' + @$quantityField.addClass 'editable' + else + @$quantityField.attr 'readonly', 'readonly' + @$quantityField.removeClass 'editable' @$action.css display:(if @editable then 'table-cell' else 'none') @@ -61,5 +113,9 @@ module.exports = class StackController extends BaseController events: -> return _.extend super, - 'click button.remove': 'onRemoveClicked' - 'click .name a': 'routeLinkClick' + 'blur .quantity input': 'onQuantityFieldBlur' + 'click button.remove': 'onRemoveClicked' + 'click .name a': 'routeLinkClick' + 'focus .quantity input': 'onQuantityFieldFocused' + 'input .quantity input': 'onQuantityFieldChanged' + 'keyup .quantity input': 'onQuantityKeyUp' diff --git a/src/scripts/models/inventory.coffee b/src/scripts/models/inventory.coffee index e1ca99b56..40db95b05 100644 --- a/src/scripts/models/inventory.coffee +++ b/src/scripts/models/inventory.coffee @@ -115,6 +115,7 @@ module.exports = class Inventory extends BaseModel stack.quantity -= quantity if stack.quantity is 0 + @stopListening stack delete @_stacks[itemSlug] @_itemSlugs = _(@_itemSlugs).without itemSlug @@ -184,6 +185,7 @@ module.exports = class Inventory extends BaseModel stack = @_stacks[itemSlug] if not stack? stack = new Stack itemSlug:itemSlug, quantity:quantity + @listenTo stack, Event.change, => @trigger Event.change @_stacks[itemSlug] = stack @_itemSlugs.push itemSlug @_sort() diff --git a/src/templates/inventory.jade b/src/templates/inventory.jade index 255ea8729..9d5a132bd 100644 --- a/src/templates/inventory.jade +++ b/src/templates/inventory.jade @@ -13,8 +13,8 @@ .scrollbox table tr.edit - td.quantity: input(name="quantity") - td.icon: img(src="/images/unknown.png") + td.quantity + td.icon td.name(width="*"): input(name="name") td.action: button(name="add") add .toolbar diff --git a/src/templates/stack.jade b/src/templates/stack.jade index ef8399d1c..8909aaa0f 100644 --- a/src/templates/stack.jade +++ b/src/templates/stack.jade @@ -6,7 +6,7 @@ //- tr.view__stack - td.quantity: p + td.quantity: input td.icon: img(src='') td.name(width='*'): a td.action