Redesign the crafting page

This introduces the new crafting page design featuring a new vertical
layout and list display of all crafting steps. It also makes it easy
to move items between the have/need sections and even from each step
into your inventory (causing a new crafting plan to be created which
doesn't plan on making that item).

* Convert the `BaseController.hide` and `show` methods to be much
  more robust in the use of CSS transitions (using a timer in case a
  transition doesn't actually fire).
* Change `hide`/`show` to use events for communicating animation
  state instead of callbacks
* Convert several controllers to fire events for communication with
  parent controllers instead of accepting functions.
* Rewrite the `CraftPageController`, `CraftPage` model and related
  Jade/SCSS files to implement the new design.
* Alter the `InventoryController` and `StackController` to allow a
  variety of action buttons, and for the events from those action
  buttons to bubble up to parent controllers
* Add the `StepController` and its related model, template, and style
  sheet as part of the new craft page.
* Tweak the `ItemSelectorController` and related files to allow for
  a variety of styles for the launcher button
This commit is contained in:
Andrew Miner
2015-04-20 09:17:58 -07:00
parent daaeb523d9
commit 5b014c9921
61 changed files with 855 additions and 401 deletions
@@ -5,17 +5,13 @@ Copyright (c) 2014-2015 by Redwood Labs
All rights reserved.
###
CraftingTableController = require './crafting_table_controller'
CraftPage = require '../models/craft_page'
{Event} = require '../constants'
ImageLoader = require './image_loader'
InventoryController = require './inventory_controller'
ModPackController = require './mod_pack_controller'
NameFinder = require '../models/name_finder'
PageController = require './page_controller'
Storage = require '../models/storage'
{Text} = require '../constants'
{Url} = require '../constants'
AdsenseController = require './adsense_controller'
CraftPage = require '../models/craft_page'
InventoryController = require './inventory_controller'
PageController = require './page_controller'
StepController = require './step_controller'
{Event} = require '../constants'
{Url} = require '../constants'
########################################################################################################################
@@ -24,20 +20,56 @@ module.exports = class CraftPageController extends PageController
constructor: (options={})->
if not options.imageLoader? then throw new Error 'options.imageLoader is required'
if not options.modPack? then throw new Error 'options.modPack is required'
if not options.storage? then throw new Error 'options.storage is required'
options.model ?= new CraftPage modPack:options.modPack
options.storage ?= new Storage storage:window.localStorage
options.templateName = 'craft_page'
options.model ?= new CraftPage modPack:options.modPack
options.templateName = 'craft_page'
super options
@imageLoader = options.imageLoader
@modPack = options.modPack
@storage = options.storage
@model.plan.on Event.change, => @refresh()
# Event Methods ################################################################################
onToolsBoxToggled: ->
@model.plan.includingTools = @$('.includeTools:checked').length isnt 0
onCraftTool: (itemSlug)->
# TODO: implement this
onHaveInventoryChanged: ->
@storage.store 'crafting-plan:have', @model.plan.have.unparse()
onMoveNeedToHave: (itemSlug)->
quantity = @model.plan.need.quantityOf itemSlug
@model.plan.have.add itemSlug, quantity
@_saveHaveInventory()
onRemoveFromHaveInventory: (itemSlug)->
@model.plan.have.remove itemSlug
@onHaveInventoryChanged()
onRemoveFromWant: (itemSlug)->
@model.plan.want.remove itemSlug
@onWantInventoryChange()
onStopUsingTool: (itemSlug)->
# TODO: implement this
onStepComplete: (stepController)->
step = stepController.model
for stack in step.recipe.output
@model.plan.have.add stack.itemSlug, stack.quantity * step.multiplier
@onHaveInventoryChanged()
onWantInventoryChange: ->
text = @model.plan.want.unparse()
url = Url.crafting inventoryText:text
router.navigate url
if @model.plan.want.isEmpty
@model.plan.have.clear()
@onHaveInventoryChanged()
# PageController Overrides #####################################################################
@@ -46,69 +78,105 @@ module.exports = class CraftPageController extends PageController
# BaseController Overrides #####################################################################
onDidRender: ->
@adsenseController = @addChild AdsenseController, '.view__adsense', model:'sidebar_skyscraper'
@wantInventoryController = @addChild InventoryController, '.want .view__inventory',
imageLoader: @imageLoader
isAcceptable: (item)=> item.isCraftable
model: @model.plan.want
modPack: @modPack
firstButtonType: 'remove'
@wantInventoryController.on Event.button.first, (c, s)=> @onRemoveFromWant(s)
@wantInventoryController.on Event.change, (c)=> @onWantInventoryChange()
# @toolsInUseController = @addChild InventoryController, '.tools .view__inventory',
# imageLoader: @imageLoader
# model: @model.plan.toolsInUse
# modPack: @modPack
# firstButtonType: 'down'
# secondButtonType: 'up'
# @toolsInUseController.on Event.button.first, (c, s)=> @onStopUsingTool(s)
# @toolsInUseController.of Event.button.second, (c, s)=> @onCraftTool(s)
@haveInventoryController = @addChild InventoryController, '.have .view__inventory',
imageLoader: @imageLoader
model: @model.plan.have
modPack: @modPack
firstButtonType: 'down'
@haveInventoryController.on Event.button.first, (c, s)=>
@onRemoveFromHaveInventory(s)
@haveInventoryController.on Event.change, (c)=> @onHaveInventoryChanged()
@needInventoryController = @addChild InventoryController, '.need .view__inventory',
editable: false
imageLoader: @imageLoader
model: @model.plan.need
modPack: @modPack
firstButtonType: 'up'
@needInventoryController.on Event.button.first, (c, s)=> @onMoveNeedToHave(s)
@$instructionsSection = @$('.instructions.section')
@$makeSection = @$('.make.section')
@$toolsSection = @$('.tools.section')
@$ingredientsSection = @$('.ingredients.section')
@$stepsSection = @$('.steps.section')
@$stepsContainer = @$('.steps.section .panel')
super
onWillRender: ->
@storage.register 'crafting-plan', @model.plan, 'includingTools'
@model.plan.have.clear()
@model.plan.have.parse @storage.load('crafting-plan:have')
super
onDidRender: ->
@wantController = @addChild InventoryController, '.want',
editable: true
icon: '/images/fishing_rod.png'
imageLoader: @imageLoader
isAcceptable: (item)-> item.isCraftable
model: @model.plan.want
modPack: @model.modPack
onChange: => @_updateLocation()
title: 'Items you want'
@haveController = @addChild InventoryController, '.have',
editable: true,
imageLoader: @imageLoader
model: @model.plan.have
modPack: @model.modPack
onChange: => @_saveHaveInventory()
title: 'Items you have'
@needController = @addChild InventoryController, '.need',
editable: false
icon: '/images/boots.png'
imageLoader: @imageLoader
model: @model.plan.need
modPack: @model.modPack
title: "Items you'll need"
@craftingTableController = @addChild CraftingTableController, '.view__crafting_table',
imageLoader: @imageLoader
model: @model.table
modPack: @model.modPack
@$('.want .toolbar').append '<label><input class="includeTools" type="checkbox"> include tools</label>'
@$includeToolsBox = @$('.includeTools')
super
refresh: ->
if @model.plan.includingTools
@$includeToolsBox.attr 'checked', 'checked'
else
@$includeToolsBox.removeAttr 'checked'
@_refreshSectionVisibility()
@_refreshSteps()
super
# Backbone.View Overrides ######################################################################
# Backbone.View Overrides ########################################################################
events: ->
return _.extend super,
'change .includeTools': 'onToolsBoxToggled'
'click .instructions a': 'routeLinkClick'
# Private Methods ##############################################################################
# Private Methods ################################################################################
_saveHaveInventory: ->
@storage.store 'crafting-plan:have', @model.plan.have.unparse()
_isStepCompletable: (controller)->
return not @model.plan.want.hasAtLeast controller.model.outputItemSlug
_updateLocation: ->
text = @model.plan.want.unparse()
url = Url.crafting inventoryText:text
router.navigate url
_refreshSectionVisibility: ->
if @model.plan.want.isEmpty
for $el in [@$toolsSection, @$ingredientsSection, @$stepsSection]
@hide $el
@show @$instructionsSection
else
for $el in [@$toolsSection, @$ingredientsSection, @$stepsSection]
@show $el
@hide @$instructionsSection
_refreshSteps: ->
@_stepControllers ?= []
index = 0
for step in @model.plan.steps
controller = @_stepControllers[index]
if not controller?
controller = new StepController
canComplete: (controller)=> @_isStepCompletable(controller)
imageLoader: @imageLoader
model: step
modPack: @modPack
controller.on Event.button.complete, (c)=> @onStepComplete(c)
controller.render()
@$stepsContainer.append controller.$el
@_stepControllers.push controller
else
controller.model = step
index += 1
while @_stepControllers.length > index
@_stepControllers.pop().remove()