Add nascent version of the mod detail page

* Create a nascent version of the mod detail page
* Make the slug mandatory for Mod instead of name, and load the name
  from the data file
* Make the Feedback view universal on all pages
* Refactor the use of mod pack to have a single global object at the
  router level which is shared between pages. Further, make this one
  object load itself immediately and have it automatically load any
  activated mod version
* Refactor the use of Storage related to mod pack versions into the
  router as well.
* Add trace logging back in for events, but allow individual classes
  to suppress it (as opposed to actually supressing the events)
* Fix a bug in ModVersion.eachItem where it would suggest so-called
  items which are merely registered slugs without associated items
This commit is contained in:
Andrew Miner
2015-01-20 10:55:38 -08:00
parent d33723b3c2
commit 164c0d4892
25 changed files with 151 additions and 26 deletions
+5
View File
@@ -22,6 +22,11 @@ app.get '/item(/*)?', (request, response)->
response.set 'Content-Type', 'text/html' response.set 'Content-Type', 'text/html'
response.sendFile 'index.html', root:ROOT response.sendFile 'index.html', root:ROOT
app.get '/mod(/*)?', (request, response)->
console.log ">>> index.html (for #{request.path})"
response.set 'Content-Type', 'text/html'
response.sendFile 'index.html', root:ROOT
app.get '*', (request, response)-> app.get '*', (request, response)->
extension = path.extname(request.path) extension = path.extname(request.path)
contentType = { contentType = {
+1
View File
@@ -1,5 +1,6 @@
schema: 1 schema: 1
name: Applied Energistics 2
author: AlgorithmX2 author: AlgorithmX2
description: A technical mod which adds an advanced, computer-based storage system description: A technical mod which adds an advanced, computer-based storage system
url: http://www.mod-buildcraft.com url: http://www.mod-buildcraft.com
+2 -1
View File
@@ -1,6 +1,7 @@
schema: 1 schema: 1
author: Spacetoad name: Buildcraft
author: SpaceToad
description: A technical mod which adds power generation, mining, and building systems description: A technical mod which adds power generation, mining, and building systems
url: http://www.mod-buildcraft.com url: http://www.mod-buildcraft.com
+1
View File
@@ -1,5 +1,6 @@
schema: 1 schema: 1
name: Industrial Craft (classic)
author: Alblaka author: Alblaka
description: A technical mod adding multi-tiered power systems, mining and ore processing, and powered armor description: A technical mod adding multi-tiered power systems, mining and ore processing, and powered armor
url: http://http://wiki.industrial-craft.net/ url: http://http://wiki.industrial-craft.net/
+1
View File
@@ -1,5 +1,6 @@
schema: 1 schema: 1
name: Minecraft
author: Mojang author: Mojang
description: The basic game by itself description: The basic game by itself
url: http://www.minecraft.net url: http://www.minecraft.net
+1
View File
@@ -1,5 +1,6 @@
schema: 1 schema: 1
name: Thermal Expansion
author: Team CoFH author: Team CoFH
description: A technical mod which adds ore processing, item transportion, fluid handling, and many new ores. description: A technical mod which adds ore processing, item transportion, fluid handling, and many new ores.
url: http://teamcofh.com/thermal-expansion/ url: http://teamcofh.com/thermal-expansion/
-3
View File
@@ -10,9 +10,6 @@ extends ./layouts/basic
append styles append styles
link(rel="stylesheet", type="text/css", href="/css/jquery-ui.css") link(rel="stylesheet", type="text/css", href="/css/jquery-ui.css")
prepend body
.view__feedback
block content block content
.page .page
+1
View File
@@ -19,6 +19,7 @@ html
body body
block body block body
.view__feedback
.view__screen .view__screen
.content .content
include ../includes/_header.jade include ../includes/_header.jade
+1 -1
View File
@@ -6,7 +6,7 @@ All rights reserved.
### ###
# Minecraft must be first # Minecraft must be first
exports.DefaultMods = [ 'Minecraft', 'Applied Energistics 2', 'Buildcraft', 'IC2 Classic' ] exports.DefaultMods = [ 'minecraft', 'applied_energistics_2', 'buildcraft', 'ic2_classic' ]
exports.Duration = Duration = {} exports.Duration = Duration = {}
Duration.snap = 100 Duration.snap = 100
@@ -87,7 +87,7 @@ module.exports = class BaseController extends Backbone.View
logger.error "Default render called for #{@constructor.name} without a template" logger.error "Default render called for #{@constructor.name} without a template"
return this return this
logger.verbose "#{this} rendering with data: #{data}" logger.verbose "#{this} rendering with data: #{util.inspect(data)}"
@onWillRender() @onWillRender()
$oldEl = @$el $oldEl = @$el
$newEl = Backbone.$(@_template(data)) $newEl = Backbone.$(@_template(data))
@@ -20,7 +20,7 @@ Storage = require '../models/storage'
module.exports = class ItemPageController extends BaseController module.exports = class ItemPageController extends BaseController
constructor: (options={})-> constructor: (options={})->
options.model ?= new ItemPage options.model ?= new ItemPage modPack:options.modPack
options.imageLoader ?= new ImageLoader defaultUrl:'/images/unknown.png' options.imageLoader ?= new ImageLoader defaultUrl:'/images/unknown.png'
options.storage ?= new Storage storage:window.localStorage options.storage ?= new Storage storage:window.localStorage
options.templateName = 'item_page' options.templateName = 'item_page'
@@ -36,12 +36,6 @@ module.exports = class ModController extends BaseController
# BaseController Overrides ##################################################################### # BaseController Overrides #####################################################################
onWillRender: ->
@model.fetch()
if @_storage? then @_storage.register "mod:#{@model.slug}", @model, 'activeVersion'
@model.on Event.change + ':activeModVersion', (mod, modVersion)=>
if modVersion? then modVersion.fetch()
onDidRender: -> onDidRender: ->
@$enabled = @$('td:nth-child(1) input') @$enabled = @$('td:nth-child(1) input')
@$name = @$('td:nth-child(2) p') @$name = @$('td:nth-child(2) p')
@@ -33,10 +33,6 @@ module.exports = class ModPackController extends BaseController
# BaseController Overrides ##################################################################### # BaseController Overrides #####################################################################
onWillRender: ->
for name in DefaultMods
@model.addMod new Mod name:name
onDidRender: -> onDidRender: ->
@$table = @$('table') @$table = @$('table')
@$toolbar = @$('.toolbar') @$toolbar = @$('.toolbar')
@@ -0,0 +1,55 @@
###
Crafting Guide - mod_page_controller.coffee
Copyright (c) 2015 by Redwood Labs
All rights reserved.
###
BaseController = require './base_controller'
{Duration} = require '../constants'
ModPack = require '../models/mod_pack'
RecipeController = require './recipe_controller'
########################################################################################################################
module.exports = class ModPageController extends BaseController
constructor: (options={})->
if not options.modPack? then throw new Error 'options.modPack is required'
options.templateName = 'mod_page'
super options
@_modPack = options.modPack
@_recipeControllers = []
# BaseController Overrides #####################################################################
onDidRender: ->
@$title = @$('h1')
@$recipes = @$('.recipes')
super
refresh: ->
@$title.html if @model? then @model.name else ''
controllerIndex = 0
if @model?.activeModVersion?.isLoaded
@$recipes.show duration:Duration.fast
@model.eachItem (item)=>
controller = @_recipeControllers[controllerIndex]
if not controller?
controller = new RecipeController modPack:@_modPack
controller.render()
@_recipeControllers.push controller
@$recipes.append controller.$el
controller.model = item.getPrimaryRecipe()
controllerIndex += 1
else
@$recipes.hide duration:Duration.fast
while @_recipeControllers.length > controllerIndex
controller = @_recipeControllers.pop()
controller.$el.slideUp duration:Duration.fast, complete:-> @remove()
super
+31 -1
View File
@@ -5,10 +5,15 @@ Copyright (c) 2014-2015 by Redwood Labs
All rights reserved. All rights reserved.
### ###
{DefaultMods} = require './constants'
{Duration} = require './constants' {Duration} = require './constants'
{Event} = require './constants' {Event} = require './constants'
ItemPageController = require './controllers/item_page_controller' ItemPageController = require './controllers/item_page_controller'
Mod = require './models/mod'
ModPack = require './models/mod_pack'
ModPageController = require './controllers/mod_page_controller'
{Opacity} = require './constants' {Opacity} = require './constants'
Storage = require './models/storage'
UrlParams = require './url_params' UrlParams = require './url_params'
######################################################################################################################## ########################################################################################################################
@@ -21,6 +26,24 @@ module.exports = class CraftingGuideRouter extends Backbone.Router
@_lastReported = null @_lastReported = null
super options super options
@modPack = new ModPack
@storage = new Storage storage:window.localStorage
@_defaultOptions = modPack:@modPack, storage:@storage
# Public Methods ###############################################################################
loadDefaultModPack: ->
makeResponder = (m)-> return ->
m.activeModVersion.fetch() if m.activeModVersion?
for slug in DefaultMods
mod = new Mod slug:slug
mod.on Event.change + ':activeModVersion', makeResponder mod
@storage.register "mod:#{mod.slug}", mod, 'activeVersion'
mod.fetch()
@modPack.addMod mod
# Backbone.Router Overrides #################################################################### # Backbone.Router Overrides ####################################################################
navigate: -> navigate: ->
@@ -30,6 +53,7 @@ module.exports = class CraftingGuideRouter extends Backbone.Router
routes: routes:
'': 'root' '': 'root'
'item(/:name)': 'item' 'item(/:name)': 'item'
'mod/:slug': 'mod'
# Route Methods ################################################################################ # Route Methods ################################################################################
@@ -38,10 +62,16 @@ module.exports = class CraftingGuideRouter extends Backbone.Router
@item params.recipeName, params.count @item params.recipeName, params.count
item: (name, quantity=1)-> item: (name, quantity=1)->
@_pageControllers.item ?= new ItemPageController @_pageControllers.item ?= new ItemPageController @_defaultOptions
@_pageControllers.item.model.params = name:name, quantity:quantity @_pageControllers.item.model.params = name:name, quantity:quantity
@_setPage 'item' @_setPage 'item'
mod: (slug)->
@_pageControllers.mod ?= new ModPageController @_defaultOptions
logger.debug "setting up mod page wiht mod: #{@modPack.getMod slug} for slug: #{slug}"
@_pageControllers.mod.model = @modPack.getMod slug
@_setPage 'mod'
# Private Methods ############################################################################## # Private Methods ##############################################################################
_recordPageView: -> _recordPageView: ->
+8 -3
View File
@@ -13,14 +13,13 @@ FeedbackController = require './controllers/feedback_controller'
Logger = require './logger' Logger = require './logger'
CraftingGuideRouter = require './crafting_guide_router' CraftingGuideRouter = require './crafting_guide_router'
########################################################################################################################
if typeof(global) is 'undefined' if typeof(global) is 'undefined'
window.global = window window.global = window
global = window.global global = window.global
global.logger = new Logger global.logger = new Logger
global.router = new CraftingGuideRouter
global.util = require 'util'
global.views = views
switch window.location.hostname switch window.location.hostname
when 'localhost' when 'localhost'
@@ -33,8 +32,14 @@ switch window.location.hostname
global.env = 'production' global.env = 'production'
logger.level = Logger.INFO logger.level = Logger.INFO
global.router = new CraftingGuideRouter
global.util = require 'util'
global.views = views
global.feedbackController = new FeedbackController el:'.view__feedback' global.feedbackController = new FeedbackController el:'.view__feedback'
feedbackController.render() feedbackController.render()
global.router.loadDefaultModPack()
logger.info "CraftingGuide is ready" logger.info "CraftingGuide is ready"
Backbone.history.start pushState:true Backbone.history.start pushState:true
+7
View File
@@ -13,6 +13,7 @@ All rights reserved.
module.exports = class BaseModel extends Backbone.Model module.exports = class BaseModel extends Backbone.Model
constructor: (attributes={}, options={})-> constructor: (attributes={}, options={})->
options.logEvents ?= true
super attributes, options super attributes, options
makeGetter = (name)-> return -> @get name makeGetter = (name)-> return -> @get name
@@ -21,6 +22,7 @@ module.exports = class BaseModel extends Backbone.Model
continue if name is 'id' continue if name is 'id'
Object.defineProperty this, name, get:makeGetter(name), set:makeSetter(name) Object.defineProperty this, name, get:makeGetter(name), set:makeSetter(name)
@logEvents = options.logEvents or false
@state = ModelState.unloaded @state = ModelState.unloaded
@on 'request', => @state = ModelState.loading @on 'request', => @state = ModelState.loading
@@ -77,6 +79,11 @@ module.exports = class BaseModel extends Backbone.Model
sync: (method, model)-> sync: (method, model)->
throw new Error "#{@constructor.name}.#{@cid} is not permitted to #{method}" throw new Error "#{@constructor.name}.#{@cid} is not permitted to #{method}"
trigger: (name, model, args...)->
if @logEvents
logger.trace "#{@constructor.name}.#{@cid} triggered event #{name} with args: #{args}"
super
# Object Overrides ############################################################################# # Object Overrides #############################################################################
toString: -> toString: ->
+2 -1
View File
@@ -19,6 +19,7 @@ module.exports = class Item extends BaseModel
attributes.isGatherable ?= false attributes.isGatherable ?= false
attributes.slug ?= _.slugify attributes.name attributes.slug ?= _.slugify attributes.name
options.logEvents ?= false
super attributes, options super attributes, options
@_recipes = [] @_recipes = []
@@ -57,7 +58,7 @@ module.exports = class Item extends BaseModel
if _.slugify(@name) isnt @slug if _.slugify(@name) isnt @slug
result.push ', slug:'; result.push @slug result.push ', slug:'; result.push @slug
if @recipes.length > 0 if @_recipes.length > 0
result.push ', recipes:«' result.push ', recipes:«'
result.push @_recipes.length result.push @_recipes.length
result.push ' items»' result.push ' items»'
+2 -2
View File
@@ -15,11 +15,11 @@ BaseModel = require './base_model'
module.exports = class Mod extends BaseModel module.exports = class Mod extends BaseModel
constructor: (attributes={}, options={})-> constructor: (attributes={}, options={})->
if not attributes.name? then throw new Error 'attributes.name is required' if not attributes.slug? then throw new Error 'attributes.slug is required'
attributes.author ?= '' attributes.author ?= ''
attributes.description ?= '' attributes.description ?= ''
attributes.name ?= ''
attributes.primaryUrl ?= null attributes.primaryUrl ?= null
attributes.slug ?= _.slugify attributes.name
super attributes, options super attributes, options
@_activeModVersion = null @_activeModVersion = null
+6
View File
@@ -78,6 +78,7 @@ module.exports = class ModPack extends BaseModel
# Property Methods ############################################################################# # Property Methods #############################################################################
addMod: (mod)-> addMod: (mod)->
if not mod? then throw new Error 'mod is required'
return if @_mods.indexOf(mod) isnt -1 return if @_mods.indexOf(mod) isnt -1
@_mods.push mod @_mods.push mod
@@ -94,6 +95,11 @@ module.exports = class ModPack extends BaseModel
for mod in @_mods for mod in @_mods
callback mod callback mod
getMod: (slug)->
for mod in @_mods
return mod if mod.slug is slug
return null
getMods: -> getMods: ->
return @_mods[..] return @_mods[..]
+2
View File
@@ -46,6 +46,8 @@ module.exports = class ModVersion extends BaseModel
eachItem: (callback)-> eachItem: (callback)->
for slug in @_slugs for slug in @_slugs
item = @_items[slug]
continue unless item?
callback @_items[slug], slug callback @_items[slug], slug
return this return this
@@ -37,6 +37,11 @@ module.exports = class ModParserV2 extends CommandParserVersionBase
@_rawData.description = description @_rawData.description = description
_command_name: (name)->
if @_rawData.name? then throw new Error 'duplicate declaration of "name"'
if name.length is 0 then throw new Error '"name" cannot be empty'
@_rawData.name = name
_command_url: (url='')-> _command_url: (url='')->
if @_rawData.url? then throw new Error 'duplicate declaration of "url"' if @_rawData.url? then throw new Error 'duplicate declaration of "url"'
if url.length is 0 then throw new Error 'url cannot be empty' if url.length is 0 then throw new Error 'url cannot be empty'
@@ -52,11 +57,13 @@ module.exports = class ModParserV2 extends CommandParserVersionBase
# Object Building Methods ###################################################################### # Object Building Methods ######################################################################
_buildMod: (rawData, model)-> _buildMod: (rawData, model)->
if not rawData.name? then throw new Error 'the "name" declaration is required'
if not rawData.url? then throw new Error 'the "url" declaration is required' if not rawData.url? then throw new Error 'the "url" declaration is required'
if not rawData.versions? then throw new Error 'at least one "version" declaration is required' if not rawData.versions? then throw new Error 'at least one "version" declaration is required'
model.author = rawData.author if rawData.author? model.author = rawData.author if rawData.author?
model.description = rawData.description if rawData.description? model.description = rawData.description if rawData.description?
model.name = rawData.name
model.primaryUrl = rawData.url model.primaryUrl = rawData.url
for version in rawData.versions for version in rawData.versions
+1
View File
@@ -27,6 +27,7 @@ module.exports = class Recipe extends BaseModel
attributes.pattern = @_parsePattern attributes.pattern attributes.pattern = @_parsePattern attributes.pattern
attributes.slug ?= attributes.output[0].slug attributes.slug ?= attributes.output[0].slug
attributes.tools ?= [] attributes.tools ?= []
options.logEvents ?= false
super attributes, options super attributes, options
# Public Methods ############################################################################### # Public Methods ###############################################################################
+3 -2
View File
@@ -11,10 +11,11 @@ BaseModel = require './base_model'
module.exports = class Stack extends BaseModel module.exports = class Stack extends BaseModel
constructor: (attributes={})-> constructor: (attributes={}, options={})->
if not attributes.slug? then throw new Error 'attributes.slug is required' if not attributes.slug? then throw new Error 'attributes.slug is required'
attributes.quantity ?= 1 attributes.quantity ?= 1
super attributes options.logEvents ?= false
super attributes, options
# Object Overrides ############################################################################# # Object Overrides #############################################################################
+12
View File
@@ -0,0 +1,12 @@
//-
//- Crafting Guide - mod_page.jade
//-
//- Copyright (c) 2015 by Redwood Labs
//- All rights reserved.
//-
.view__mod_page
h1
.recipes
h2 Recipes