First real version of item detail page
* Split the InventoryTable view/controller out from the existing inventory view/controller. This is a simpler component which only includes the table itself, and not the scrollbox, panel or header used on the crafting page. * Create the FullRecipe view/controller to represent the expanded version of a recipe shown on the item page (as compared to the terser version on the crafting page). * Rename the existing Recipe view/controller to MinimalRecipe to avoid confusing the two. * Refactor the CSS for the Stack view/controller so that it can be shared between the Inventory and InventoryTable views. * Incorporate all these new controllers into the item page and hook up the necessary model logic to drive them.
This commit is contained in:
@@ -44,7 +44,7 @@ module.exports = class CraftingTableController extends BaseController
|
||||
# BaseController Overrides #####################################################################
|
||||
|
||||
onDidRender: ->
|
||||
@recipeController = @addChild MinimalRecipeController, '.view__recipe', imageLoader:@_imageLoader, modPack:@_modPack
|
||||
@recipeController = @addChild MinimalRecipeController, '.view__minimal_recipe', imageLoader:@_imageLoader, modPack:@_modPack
|
||||
|
||||
@$next = @$('.next')
|
||||
@$prev = @$('.prev')
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
###
|
||||
Crafting Guide - full_recipe_controller.coffee
|
||||
|
||||
Copyright (c) 2015 by Redwood Labs
|
||||
All rights reserved.
|
||||
###
|
||||
|
||||
BaseController = require './base_controller'
|
||||
CraftingGridController = require './crafting_grid_controller'
|
||||
{Duration} = require '../constants'
|
||||
ImageLoader = require './image_loader'
|
||||
Inventory = require '../models/inventory'
|
||||
InventoryTableController = require './inventory_table_controller'
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
module.exports = class FullRecipeController extends BaseController
|
||||
|
||||
constructor: (options={})->
|
||||
if not options.modPack? then throw new Error 'options.modPack is required'
|
||||
options.imageLoader ?= new ImageLoader defaultUrl:'/images/unknown.png'
|
||||
options.templateName = 'full_recipe'
|
||||
super options
|
||||
|
||||
@_imageLoader = options.imageLoader
|
||||
@modPack = options.modPack
|
||||
|
||||
# BaseController Overrides #####################################################################
|
||||
|
||||
onDidRender: ->
|
||||
@gridController = @addChild CraftingGridController, '.view__crafting_grid',
|
||||
modPack: @modPack
|
||||
imageLoader: @_imageLoader
|
||||
|
||||
@inputController = @addChild InventoryTableController, '.input .view__inventory_table',
|
||||
editable: false
|
||||
model: new Inventory
|
||||
modPack: @modPack
|
||||
|
||||
@outputController = @addChild InventoryTableController, '.output .view__inventory_table',
|
||||
editable: false
|
||||
model: new Inventory
|
||||
modPack: @modPack
|
||||
|
||||
@$tool = @$('.tool p')
|
||||
super
|
||||
|
||||
refresh: ->
|
||||
@gridController.model = @model
|
||||
@$tool.html @_findToolNames().join ', '
|
||||
|
||||
@$el.tooltip show:{delay:Duration.fast, duration:Duration.fast}
|
||||
|
||||
@_refreshInputs()
|
||||
@_refreshOutputs()
|
||||
|
||||
super
|
||||
|
||||
# Backbone.View Methods ########################################################################
|
||||
|
||||
events: ->
|
||||
return _.extend super,
|
||||
'click a': 'routeLinkClick'
|
||||
|
||||
# Private Methods ##############################################################################
|
||||
|
||||
_findToolNames: ->
|
||||
result = []
|
||||
if @model?
|
||||
for stack in @model.tools
|
||||
name = @modPack.findName stack.slug
|
||||
result.push name if name?
|
||||
return result
|
||||
|
||||
_refreshInputs: ->
|
||||
inputs = @inputController.model
|
||||
inputs.clear()
|
||||
|
||||
if @model?
|
||||
for stack in @model.input
|
||||
inputs.add stack.slug, stack.quantity
|
||||
|
||||
|
||||
_refreshOutputs: ->
|
||||
outputs = @outputController.model
|
||||
outputs.clear()
|
||||
|
||||
if @model?
|
||||
for stack in @model.output
|
||||
outputs.add stack.slug, stack.quantity
|
||||
@@ -0,0 +1,183 @@
|
||||
###
|
||||
Crafting Guide - inventory_table_controller.coffee
|
||||
|
||||
Copyright (c) 2014-2015 by Redwood Labs
|
||||
All rights reserved.
|
||||
###
|
||||
|
||||
BaseController = require './base_controller'
|
||||
{Duration} = require '../constants'
|
||||
{Key} = require '../constants'
|
||||
ImageLoader = require './image_loader'
|
||||
NameFinder = require '../models/name_finder'
|
||||
StackController = require './stack_controller'
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
module.exports = class InventoryTableController 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'
|
||||
|
||||
@editable = options.editable ?= true
|
||||
@imageLoader = options.imageLoader ?= new ImageLoader defaultUrl:'/images/unknown.png'
|
||||
@modPack = options.modPack
|
||||
@nameFinder = options.nameFinder ?= new NameFinder options.modPack
|
||||
@onChange = options.onChange ?= -> # do nothing
|
||||
|
||||
options.templateName = 'inventory_table'
|
||||
super options
|
||||
|
||||
@_stackControllers = []
|
||||
|
||||
@listenTo @modPack, 'change', => @refresh()
|
||||
|
||||
# Event Methods ################################################################################
|
||||
|
||||
onAddButtonClicked: ->
|
||||
name = @$nameField.val()
|
||||
return unless @modPack.isValidName name
|
||||
|
||||
@model.add _.slugify(name), parseInt(@$quantityField.val())
|
||||
@$nameField.val ''
|
||||
@$quantityField.val '1'
|
||||
|
||||
@$scrollbox.scrollTop @$scrollbox.prop 'scrollHeight'
|
||||
@$nameField.autocomplete 'close'
|
||||
|
||||
@onChange()
|
||||
|
||||
onClearButtonClicked: ->
|
||||
@model.clear()
|
||||
@onChange()
|
||||
|
||||
onItemSelected: ->
|
||||
func = =>
|
||||
@onNameFieldChanged()
|
||||
@onAddButtonClicked()
|
||||
@$nameField.blur()
|
||||
|
||||
setTimeout func, 10 # needed to allow the autocomplete to finish
|
||||
return true
|
||||
|
||||
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'
|
||||
value = Math.min value, 64
|
||||
@$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()
|
||||
|
||||
onQuantityFieldFocused: ->
|
||||
@$quantityField.val ''
|
||||
|
||||
# BaseController Overrides #####################################################################
|
||||
|
||||
onDidRender: ->
|
||||
@$addButton = @$('button[name="add"]')
|
||||
@$clearButton = @$('button[name="clear"]')
|
||||
@$editPanel = @$('.edit')
|
||||
@$nameField = @$('input[name="name"]')
|
||||
@$quantityField = @$('input[name="quantity"]')
|
||||
@$scrollbox = @$('.scrollbox')
|
||||
@$table = @$('table')
|
||||
@$toolbar = @$('.toolbar')
|
||||
super
|
||||
|
||||
refresh: ->
|
||||
@$editPanel.css display:(if @editable then 'table-row' else 'none')
|
||||
@$toolbar.css display:(if @editable then 'block' else 'none')
|
||||
@$scrollbox.css bottom:(if @editable then @$toolbar.height() else '0')
|
||||
|
||||
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 =
|
||||
editable: @editable
|
||||
imageLoader: @imageLoader
|
||||
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: ->
|
||||
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 ##############################################################################
|
||||
|
||||
_removeStack: (stack)->
|
||||
@model.remove stack.slug, stack.quantity
|
||||
|
||||
_updateNameAutocomplete: ->
|
||||
onChanged = => @onNameFieldChanged()
|
||||
onSelected = => @onItemSelected()
|
||||
|
||||
@$nameField.autocomplete
|
||||
source: (request, callback)=> callback @nameFinder.search request.term
|
||||
delay: 0
|
||||
minLength: 0
|
||||
change: onChanged
|
||||
close: onChanged
|
||||
select: onSelected
|
||||
|
||||
_updateButtonState: ->
|
||||
if @model.isEmpty then @$clearButton.attr('disabled', 'disabled') else @$clearButton.removeAttr('disabled')
|
||||
|
||||
itemValid = @modPack.findItemByName(@$nameField.val())?
|
||||
quantityValid = @$quantityField.val().match(InventoryTableController.ONLY_DIGITS)
|
||||
disable = not (itemValid and quantityValid)
|
||||
if disable then @$addButton.attr('disabled', 'disabled') else @$addButton.removeAttr('disabled')
|
||||
@@ -5,14 +5,15 @@ Copyright (c) 2015 by Redwood Labs
|
||||
All rights reserved.
|
||||
###
|
||||
|
||||
BaseController = require './base_controller'
|
||||
{Duration} = require '../constants'
|
||||
{Event} = require '../constants'
|
||||
ImageLoader = require './image_loader'
|
||||
Item = require '../models/item'
|
||||
ItemGroupController = require './item_group_controller'
|
||||
ItemPage = require '../models/item_page'
|
||||
{Url} = require '../constants'
|
||||
BaseController = require './base_controller'
|
||||
{Duration} = require '../constants'
|
||||
{Event} = require '../constants'
|
||||
FullRecipeController = require './full_recipe_controller'
|
||||
ImageLoader = require './image_loader'
|
||||
Item = require '../models/item'
|
||||
ItemGroupController = require './item_group_controller'
|
||||
ItemPage = require '../models/item_page'
|
||||
{Url} = require '../constants'
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
@@ -32,25 +33,27 @@ module.exports = class ItemPageController extends BaseController
|
||||
@_itemSlug = options.itemSlug
|
||||
@_modPack = options.modPack
|
||||
|
||||
@_modPack.on Event.change, => @_resolveItemSlug()
|
||||
@_resolveItemSlug()
|
||||
@_modPack.on Event.change, => @refresh()
|
||||
|
||||
# BaseController Overrides #####################################################################
|
||||
|
||||
onDidRender: ->
|
||||
@_recipeController = @addChild FullRecipeController, '.view__full_recipe', modPack:@_modPack
|
||||
@_similarItemsController = @addChild ItemGroupController, '.similar .view__item_group', modPack:@_modPack
|
||||
@_usedInMakingController = @addChild ItemGroupController, '.usedInMaking .view__item_group', modPack:@_modPack
|
||||
@_usedInMakingController = @addChild ItemGroupController, '.usedInMaking .view__item_group', modPack:@_modPack
|
||||
|
||||
@$byline = @$('.byline')
|
||||
@$bylineLink = @$('.byline a')
|
||||
@$byline = @$('.byline')
|
||||
@$bylineLink = @$('.byline a')
|
||||
@$usedInMakingContainer = @$('.usedInMaking')
|
||||
@$name = @$('h1.name')
|
||||
@$recipeContainer = @$('.recipe')
|
||||
@$similarContainer = @$('.similar')
|
||||
@$titleImage = @$('.titleImage img')
|
||||
@$name = @$('h1.name')
|
||||
@$recipeContainer = @$('.recipe')
|
||||
@$similarContainer = @$('.similar')
|
||||
@$titleImage = @$('.titleImage img')
|
||||
super
|
||||
|
||||
refresh: ->
|
||||
@_resolveItemSlug()
|
||||
|
||||
display = @_modPack.findItemDisplay @model.item?.slug
|
||||
if display?
|
||||
@_imageLoader.load display.iconUrl, @$titleImage
|
||||
@@ -60,6 +63,7 @@ module.exports = class ItemPageController extends BaseController
|
||||
@$name.html ''
|
||||
|
||||
@_refreshByline()
|
||||
@_refreshRecipe()
|
||||
@_refreshSimilarItems()
|
||||
@_refreshComponentIn()
|
||||
|
||||
@@ -77,7 +81,7 @@ module.exports = class ItemPageController extends BaseController
|
||||
@$byline.fadeOut duration:Duration.fast
|
||||
|
||||
_refreshComponentIn: ->
|
||||
@_usedInMakingController.title = 'Used in Making'
|
||||
@_usedInMakingController.title = 'Used to Make'
|
||||
|
||||
@_usedInMakingController.model = @model.findComponentInItems()
|
||||
if @_usedInMakingController.model?
|
||||
@@ -85,6 +89,13 @@ module.exports = class ItemPageController extends BaseController
|
||||
else
|
||||
@$usedInMakingContainer.fadeOut duration:Duration.fast
|
||||
|
||||
_refreshRecipe: ->
|
||||
@_recipeController.model = @model.primaryRecipe
|
||||
if @_recipeController.model?
|
||||
@$recipeContainer.fadeIn duration:Duration.fast
|
||||
else
|
||||
@$recipeContainer.fadeOut duration:Duration.fast
|
||||
|
||||
_refreshSimilarItems: ->
|
||||
group = @model.item?.group
|
||||
if group? and group isnt Item.Group.Other
|
||||
@@ -99,5 +110,6 @@ module.exports = class ItemPageController extends BaseController
|
||||
@$similarContainer.fadeOut duration:Duration.fast
|
||||
|
||||
_resolveItemSlug: ->
|
||||
oldItem = @model.item
|
||||
@model.item = @_modPack.findItem @_itemSlug, includeDisabled:true
|
||||
|
||||
newItem = @model.item
|
||||
|
||||
@@ -35,6 +35,7 @@ module.exports = class StackController extends BaseController
|
||||
# BaseController Overrides #####################################################################
|
||||
|
||||
onDidRender: ->
|
||||
@$action = @$('.action')
|
||||
@$image = @$('.icon img')
|
||||
@$nameField = @$('.name p')
|
||||
@$quantityField = @$('.quantity p')
|
||||
@@ -49,6 +50,8 @@ module.exports = class StackController extends BaseController
|
||||
@$quantityField.html @model.quantity
|
||||
@$removeButton.css display:(if @editable then 'inherit' else 'none')
|
||||
|
||||
@$action.css display:(if @ediable then 'table-cell' else 'none')
|
||||
|
||||
super
|
||||
|
||||
# Backbone.View Overrides ######################################################################
|
||||
|
||||
Reference in New Issue
Block a user