Refactor website with new design & structure
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
//-
|
||||
//- Crafting Guide - item_page.jade
|
||||
//-
|
||||
//- Copyright © 2014-2016 by Redwood Labs
|
||||
//- All rights reserved.
|
||||
//-
|
||||
|
||||
.content.view__item_page
|
||||
.left
|
||||
.view__adsense
|
||||
|
||||
.right
|
||||
.about
|
||||
.left
|
||||
img
|
||||
.center
|
||||
.title
|
||||
a.sourceMod
|
||||
.button-row
|
||||
.button.craftingPlan: .bezel: p View Crafting Plan
|
||||
.right
|
||||
p Official Link:
|
||||
a.officialLink project page
|
||||
|
||||
section.description.view__markdown_section
|
||||
|
||||
section.multiblock
|
||||
h2 Multiblock Construction
|
||||
.panel
|
||||
.view__multiblock_viewer
|
||||
|
||||
section.recipes
|
||||
h2 Recipes
|
||||
.panel
|
||||
|
||||
section.videos
|
||||
h2 Videos
|
||||
.panel
|
||||
|
||||
section.view__item_group.usedToMake
|
||||
|
||||
section.view__item_group.usedAsToolToMake
|
||||
|
||||
section.view__item_group.similar
|
||||
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// Crafting Guide - item_page.scss
|
||||
//
|
||||
// Copyright © 2014-2016 by Redwood Labs
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
.view__item_page {
|
||||
@include layout-body-with-sidebar;
|
||||
|
||||
.about {
|
||||
margin-bottom: $size-margin-large;
|
||||
display: flex;
|
||||
|
||||
& > .left {
|
||||
margin-right: $size-margin-large;
|
||||
|
||||
flex: 0 0 auto;
|
||||
|
||||
img {
|
||||
height: $size-minecraft-block * 5;
|
||||
width: $size-minecraft-block * 5;
|
||||
}
|
||||
}
|
||||
|
||||
& > .center {
|
||||
flex: 1 1 100%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.title {
|
||||
font-family: $font-family-header;
|
||||
font-size: $font-size-xxlarge;
|
||||
}
|
||||
|
||||
a.sourceMod {
|
||||
font-family: $font-family-text;
|
||||
font-size: $font-size-medium;
|
||||
}
|
||||
|
||||
.button-row {
|
||||
flex: 1 1 100%;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-end;
|
||||
|
||||
.button {
|
||||
flex: 1 1 100%;
|
||||
max-width: 66%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& > .right {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
#
|
||||
# Crafting Guide - item_page_controller.coffee
|
||||
#
|
||||
# Copyright © 2014-2016 by Redwood Labs
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
AdsenseController = require '../common/adsense/adsense_controller'
|
||||
EditableFile = require '../../models/site/editable_file'
|
||||
Item = require '../../models/game/item'
|
||||
ItemGroupController = require '../common/item_group/item_group_controller'
|
||||
ItemPage = require '../../models/site/item_page'
|
||||
ItemSlug = require '../../models/game/item_slug'
|
||||
MarkdownSectionController = require '../common/markdown_section/markdown_section_controller'
|
||||
MultiblockViewerController = require './multiblock_viewer/multiblock_viewer_controller'
|
||||
PageController = require '../page_controller'
|
||||
RecipeDetailController = require './recipe_detail/recipe_detail_controller'
|
||||
VideoController = require '../common/video/video_controller'
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
module.exports = class ItemPageController extends PageController
|
||||
|
||||
@::FILE_UPLOAD_DELAY = 250
|
||||
|
||||
constructor: (options={})->
|
||||
if not options.client? then throw new Error 'options.client is required'
|
||||
if not options.itemSlug? then throw new Error 'options.itemSlug is required'
|
||||
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.router? then throw new Error 'options.router is required'
|
||||
|
||||
options.model ?= new ItemPage modPack:options.modPack
|
||||
options.templateName ?= 'item_page'
|
||||
|
||||
super options
|
||||
|
||||
@_client = options.client
|
||||
@_descriptionFile = null
|
||||
@_enterFeedback = options.enterFeedback
|
||||
@_imageLoader = options.imageLoader
|
||||
@_itemSlug = options.itemSlug
|
||||
@_modPack = options.modPack
|
||||
@_router = options.router
|
||||
|
||||
@_modPack.on c.event.change, =>
|
||||
@tryRefresh()
|
||||
@trigger c.event.change
|
||||
|
||||
# Event Methods ################################################################################
|
||||
|
||||
craftingPlanButtonClicked: ->
|
||||
display = @_modPack.findItemDisplay @model.item.slug
|
||||
@_router.navigate display.craftingUrl, trigger:true
|
||||
return false
|
||||
|
||||
# PageController Overrides #####################################################################
|
||||
|
||||
getBreadcrumbs: ->
|
||||
return [] unless @_itemSlug?
|
||||
|
||||
display = @_modPack.findItemDisplay @_itemSlug
|
||||
return [] unless display.itemName? and display.modName
|
||||
|
||||
return [
|
||||
$("<a href='/browse'>Browse</a>")
|
||||
$("<a href='#{c.url.mod modSlug:display.modSlug}'>#{display.modName}</a>")
|
||||
$("<b>#{display.itemName}</b>")
|
||||
]
|
||||
|
||||
getMetaDescription: ->
|
||||
return null unless @_itemSlug?
|
||||
display = @_modPack.findItemDisplay @_itemSlug
|
||||
return c.text.itemDescription display
|
||||
|
||||
getTitle: ->
|
||||
return null unless @_itemSlug?
|
||||
|
||||
display = @_modPack.findItemDisplay @_itemSlug
|
||||
return null unless display.itemName? and display.modName?
|
||||
|
||||
return "#{display.itemName} from #{display.modName}"
|
||||
|
||||
# BaseController Overrides #####################################################################
|
||||
|
||||
onDidRender: ->
|
||||
@_adsenseController = @addChild AdsenseController, '.view__adsense', model:'skyscraper', router: @_router
|
||||
|
||||
options = imageLoader:@_imageLoader, modPack:@_modPack, router:@_router, show:false
|
||||
@_multiblockController = @addChild MultiblockViewerController, '.view__multiblock_viewer', options
|
||||
@_similarItemsController = @addChild ItemGroupController, '.view__item_group.similar', options
|
||||
@_usedAsToolToMakeController = @addChild ItemGroupController, '.view__item_group.usedAsToolToMake ', options
|
||||
@_usedToMakeController = @addChild ItemGroupController, '.view__item_group.usedToMake', options
|
||||
|
||||
@_descriptionController = @addChild MarkdownSectionController, '.view__markdown_section',
|
||||
client: @_client
|
||||
editable: true
|
||||
modPack: @_modPack
|
||||
router: @_router
|
||||
beginEditing: => @_beginEditingDescription()
|
||||
endEditing: => @_endEditingDescription()
|
||||
enterFeedback: @_enterFeedback
|
||||
|
||||
@$aboutImage = @$('.about img')
|
||||
@$name = @$('.about .title')
|
||||
@$officialLink = @$('.about a.officialLink')
|
||||
@$sourceModLink = @$('.about a.sourceMod')
|
||||
@$aboutLinks = @$('.about .right')
|
||||
|
||||
@$multiblockSection = @$('section.multiblock')
|
||||
@$recipeContainer = @$('section.recipes .panel')
|
||||
@$recipesSection = @$('section.recipes')
|
||||
@$recipesSectionTitle = @$('section.recipes h2')
|
||||
@$similarSection = @$('section.similar')
|
||||
@$usedAsToolToMakeSection = @$('section.usedAsToolToMake')
|
||||
@$usedToMakeSection = @$('section.usedToMake')
|
||||
@$videosContainer = @$('section.videos .panel')
|
||||
@$videosSection = @$('section.videos')
|
||||
@$videosSectionTitle = @$('section.videos h2')
|
||||
super
|
||||
|
||||
refresh: ->
|
||||
@_resolveItemSlug()
|
||||
|
||||
if @model.item?
|
||||
display = @_modPack.findItemDisplay @model.item.slug
|
||||
@_imageLoader.load display.iconUrl, @$aboutImage
|
||||
@$name.text display.itemName
|
||||
|
||||
@_descriptionController.imageBase = c.url.itemImageDir display
|
||||
|
||||
if @model.item.officialUrl?
|
||||
@$officialLink.attr 'href', @model.item.officialUrl
|
||||
@show @$aboutLinks
|
||||
else
|
||||
@hide @$aboutLinks
|
||||
|
||||
@show()
|
||||
else
|
||||
@hide()
|
||||
|
||||
@_refreshSourceMod()
|
||||
@_refreshDescription()
|
||||
@_refreshMultiblock()
|
||||
@_refreshRecipes()
|
||||
@_refreshSimilarItems()
|
||||
@_refreshUsedAsToolToMake()
|
||||
@_refreshUsedToMake()
|
||||
@_refreshVideos()
|
||||
|
||||
super
|
||||
|
||||
setUser: (user)->
|
||||
super user
|
||||
@_descriptionController.user = user if @_descriptionController?
|
||||
|
||||
# Backbone.View Overrides ######################################################################
|
||||
|
||||
events: ->
|
||||
return _.extend super,
|
||||
'click a.craftingPlan': 'routeLinkClick'
|
||||
'click a.sourceMod': 'routeLinkClick'
|
||||
'click .markdown a': 'routeLinkClick'
|
||||
'click .button.craftingPlan': 'craftingPlanButtonClicked'
|
||||
|
||||
# Private Methods ##############################################################################
|
||||
|
||||
_beginEditingDescription: ->
|
||||
if not @user?
|
||||
global.site.login()
|
||||
return w.reject new Error 'must be logged in to edit'
|
||||
|
||||
if not @model.item?
|
||||
return w.reject new Error 'must have an item'
|
||||
|
||||
pathArgs = modSlug:@_itemSlug.mod, itemSlug:@_itemSlug.item
|
||||
attributes =
|
||||
fileName: c.gitHub.file.itemDescription.fileName pathArgs
|
||||
path: c.gitHub.file.itemDescription.path pathArgs
|
||||
|
||||
@_descriptionFile = new EditableFile attributes, client:@_client
|
||||
@_descriptionFile.fetch()
|
||||
.then =>
|
||||
if @_descriptionFile.encodedData?.length > 0
|
||||
@model.item.parse @_descriptionFile.getDecodedData 'utf8'
|
||||
else
|
||||
@model.item.description = ''
|
||||
|
||||
@_descriptionController.model = @model.item.description
|
||||
|
||||
_endEditingDescription: ->
|
||||
oldDescription = @model.item.description
|
||||
promises = []
|
||||
|
||||
saveList = []
|
||||
for imageFile in @_descriptionController.imageFiles
|
||||
saveList.push
|
||||
file: imageFile
|
||||
message: "User-submitted image for #{@model.item.name} from #{global.hostName}"
|
||||
|
||||
@model.item.description = @_descriptionController.model
|
||||
@_descriptionFile.setDecodedData @model.item.unparse()
|
||||
saveList.push
|
||||
file: @_descriptionFile
|
||||
message: "User-submitted text for #{@model.item.name} from #{global.hostName}"
|
||||
|
||||
saveNextFile = (fileList)->
|
||||
return w(true) if fileList.length is 0
|
||||
{file, message} = fileList.shift()
|
||||
file.save message
|
||||
.delay @FILE_UPLOAD_DELAY
|
||||
.then ->
|
||||
saveNextFile fileList
|
||||
|
||||
saveNextFile saveList
|
||||
.catch (e)=>
|
||||
@model.item.description = oldDescription
|
||||
throw e
|
||||
|
||||
_refreshDescription: ->
|
||||
if @model.item?.description?.length > 0
|
||||
@_descriptionController.model = @model.item.description
|
||||
@_descriptionController.resetToDefaultState()
|
||||
|
||||
_refreshMultiblock: ->
|
||||
if @model.item?.multiblock?
|
||||
@_multiblockController.model = @model.item.multiblock
|
||||
@show @$multiblockSection
|
||||
else
|
||||
@hide @$multiblockSection
|
||||
|
||||
_refreshRecipes: ->
|
||||
@_recipeControllers ?= []
|
||||
index = 0
|
||||
|
||||
recipes = @model.findRecipes()
|
||||
if recipes?.length > 0
|
||||
@$recipesSectionTitle.html if recipes.length is 1 then 'Recipe' else 'Recipes'
|
||||
|
||||
for recipe in @model.findRecipes()
|
||||
controller = @_recipeControllers[index]
|
||||
if not controller?
|
||||
controller = new RecipeDetailController
|
||||
imageLoader: @_imageLoader
|
||||
modPack: @_modPack
|
||||
model: recipe
|
||||
router: @_router
|
||||
@_recipeControllers.push controller
|
||||
@$recipeContainer.append controller.$el
|
||||
controller.render()
|
||||
else
|
||||
controller.model = recipe
|
||||
index++
|
||||
|
||||
@show @$recipesSection
|
||||
else
|
||||
@hide @$recipesSection
|
||||
|
||||
while @_recipeControllers.length > index
|
||||
@_recipeControllers.pop().remove()
|
||||
|
||||
_refreshSimilarItems: ->
|
||||
group = @model.item?.group
|
||||
if group? and group isnt Item.Group.Other
|
||||
@_similarItemsController.title = "Other #{group}"
|
||||
@_similarItemsController.model = @model.findSimilarItems()
|
||||
else
|
||||
@_similarItemsController.model = null
|
||||
|
||||
_refreshSourceMod: ->
|
||||
mod = @model.item?.modVersion?.mod
|
||||
if mod?.name?.length > 0
|
||||
@$sourceModLink.attr 'href', c.url.mod modSlug:mod.slug
|
||||
@$sourceModLink.text mod.name
|
||||
|
||||
@show @$sourceModLink
|
||||
else
|
||||
@hide @$sourceModLink
|
||||
|
||||
_refreshUsedAsToolToMake: ->
|
||||
@_usedAsToolToMakeController.title = 'Used as Tool to Make'
|
||||
@_usedAsToolToMakeController.model = @model.findToolForRecipes()
|
||||
|
||||
_refreshUsedToMake: ->
|
||||
@_usedToMakeController.title = 'Used to Make'
|
||||
@_usedToMakeController.model = @model.findComponentInItems()
|
||||
|
||||
_refreshVideos: ->
|
||||
@_videoControllers ?= []
|
||||
index = 0
|
||||
|
||||
videos = @model?.item?.videos or []
|
||||
if videos? and videos.length > 0
|
||||
@$videosSectionTitle.html if videos.length is 1 then 'Video' else 'Videos'
|
||||
|
||||
for video in videos
|
||||
controller = @_videoControllers[index]
|
||||
if not controller?
|
||||
controller = new VideoController model:video
|
||||
@_videoControllers.push controller
|
||||
controller.render()
|
||||
@$videosContainer.append controller.$el
|
||||
else
|
||||
controller.model = video
|
||||
index++
|
||||
|
||||
@show @$videosSection
|
||||
else
|
||||
@hide @$videosSection
|
||||
|
||||
while @_videoControllers.length > index
|
||||
@_videoControllers.pop().remove()
|
||||
|
||||
_resolveItemSlug: ->
|
||||
return if @model.item?
|
||||
|
||||
item = @_modPack.findItem @_itemSlug, includeDisabled:true
|
||||
if item?
|
||||
if not ItemSlug.equal item.slug, @_itemSlug
|
||||
router.navigate c.url.item(modSlug:item.slug.mod, itemSlug:item.slug.item), trigger:true
|
||||
return
|
||||
|
||||
@model.item = item
|
||||
item.fetch()
|
||||
item.on c.event.sync, => @refresh()
|
||||
@@ -0,0 +1,9 @@
|
||||
//-
|
||||
//- Crafting Guide - multiblock.jade
|
||||
//-
|
||||
//- Copyright (c) 2015 by Redwood Labs
|
||||
//- All rights reserved.
|
||||
//-
|
||||
|
||||
.view__multiblock
|
||||
img.outline(src="/images/outline.png")
|
||||
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// Crafting Guide - multiblock.scss
|
||||
//
|
||||
// Copyright © 2014-2016 by Redwood Labs
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
$animate-slow: 400ms;
|
||||
$animate-fast: 100ms;
|
||||
|
||||
.view__multiblock {
|
||||
position: relative;
|
||||
|
||||
.block {
|
||||
position: absolute;
|
||||
transition: all $animate-slow cubic-bezier(0.615, -0.090, 0.010, 1.090);
|
||||
}
|
||||
|
||||
.outline {
|
||||
position: absolute;
|
||||
opacity: 0.0;
|
||||
transition: opacity $animate-fast;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
###
|
||||
Crafting Guide - multiblock_controller.coffee
|
||||
|
||||
Copyright (c) 2014-2015 by Redwood Labs
|
||||
All rights reserved.
|
||||
###
|
||||
|
||||
BaseController = require '../../../base_controller'
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
module.exports = class MultiblockController extends BaseController
|
||||
|
||||
@::HOVER_TIMEOUT = 5000 # ms
|
||||
|
||||
@::IMAGE_SIZE = 48 # px
|
||||
|
||||
@::X_LAYER_H_SHIFT = -24 # px
|
||||
@::Z_LAYER_H_SHIFT = +24 # px
|
||||
|
||||
@::X_LAYER_V_SHIFT = -12 # px
|
||||
@::Y_LAYER_V_SHIFT = -30 # px
|
||||
@::Z_LAYER_V_SHIFT = -12 # px
|
||||
|
||||
@::MAX_DROP_DELAY = 250 # ms
|
||||
|
||||
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'
|
||||
options.templateName = 'item_page/multiblock_viewer/multiblock'
|
||||
super options
|
||||
|
||||
@_currentLayer = 0
|
||||
@_blockCache = null
|
||||
@_imageLoader = options.imageLoader
|
||||
@_modPack = options.modPack
|
||||
@_onHovering = options.onHovering ?= (itemDisplay)-> # do nothing
|
||||
|
||||
# Public Methods ###############################################################################
|
||||
|
||||
goBackLayer: ->
|
||||
@_currentLayer = Math.max 0, @_currentLayer - 1
|
||||
@_refreshAllBlocks()
|
||||
|
||||
goNextLayer: ->
|
||||
@_currentLayer = Math.min @model.height - 1, @_currentLayer + 1
|
||||
@_refreshAllBlocks()
|
||||
|
||||
hasBackLayer: ->
|
||||
return false unless @model?
|
||||
return @_currentLayer > 0
|
||||
|
||||
hasNextLayer: ->
|
||||
return false unless @model?
|
||||
return @_currentLayer < @model.height - 1
|
||||
|
||||
# Property Methods #############################################################################
|
||||
|
||||
Object.defineProperties @prototype,
|
||||
currentLayer:
|
||||
get: -> return @_currentLayer
|
||||
|
||||
# BaseController Overrides #####################################################################
|
||||
|
||||
onDidRender: ->
|
||||
@$outline = @$('.outline')
|
||||
super
|
||||
|
||||
refresh: ->
|
||||
@$el.css 'height':@_computeMinHeight(), 'width':@_computeMinWidth()
|
||||
|
||||
@_refreshBlockCache()
|
||||
@_refreshAllBlocks()
|
||||
super
|
||||
|
||||
# Private Methods ##############################################################################
|
||||
|
||||
_computePosition: (x, y, z, options={})->
|
||||
if not @model? then return left:0, top:-@IMAGE_SIZE, 'z-index':0, opacity:0.0
|
||||
|
||||
options.hideUpperLayers ?= false
|
||||
pxWidth = @$el.width()
|
||||
pxHeight = @$el.height()
|
||||
|
||||
left = ((pxWidth - @IMAGE_SIZE) / 2) + (x * @X_LAYER_H_SHIFT) + (z * @Z_LAYER_H_SHIFT)
|
||||
|
||||
if options.hideUpperLayers and y > @_currentLayer
|
||||
top = 0
|
||||
opacity = 0.0
|
||||
else
|
||||
top = (pxHeight - @IMAGE_SIZE) + (x * @X_LAYER_V_SHIFT) + (z * @Z_LAYER_V_SHIFT) + (y * @Y_LAYER_V_SHIFT)
|
||||
opacity = 1.0
|
||||
|
||||
zindex = ((@model.width - x) + (@model.depth - z) + ((@model.width * @model.depth) * y)) * 2
|
||||
|
||||
return left:left, top:top, 'z-index':zindex, opacity:opacity
|
||||
|
||||
_computeMinHeight: ->
|
||||
return 0 unless @model?
|
||||
|
||||
minHeight = Math.max(Math.abs(@model.width * @X_LAYER_V_SHIFT), Math.abs(@model.depth * @Z_LAYER_V_SHIFT))
|
||||
minHeight += Math.abs(@model.height * @Y_LAYER_V_SHIFT)
|
||||
minHeight += 2 * @IMAGE_SIZE
|
||||
return minHeight
|
||||
|
||||
_computeMinWidth: ->
|
||||
return 0 unless @model?
|
||||
|
||||
leftPosition = @_computePosition @model.width, 0, 0
|
||||
rightPosition = @_computePosition 0, 0, @model.depth
|
||||
return rightPosition.left - leftPosition.left
|
||||
|
||||
_endHovering: ->
|
||||
@$outline.css opacity:0.0
|
||||
@_hoverTimer = null
|
||||
@_onHovering null
|
||||
|
||||
_randomDropDelay: ->
|
||||
return Math.random() * @MAX_DROP_DELAY
|
||||
|
||||
_refreshBlockCache: ->
|
||||
@_blockCache = null
|
||||
return unless @model?
|
||||
|
||||
@_blockCache = width:@model.width, height:@model.height, depth:@model.depth
|
||||
for x in [0...@model.width]
|
||||
@_blockCache[x] ?= {}
|
||||
for y in [0...@model.height]
|
||||
@_blockCache[x][y] ?= {}
|
||||
for z in [0...@model.depth]
|
||||
@_blockCache[x][y][z] ?= null
|
||||
|
||||
for el in @$('.block')
|
||||
$el = $(el)
|
||||
@_blockCache[$el.data('x')][$el.data('y')][$el.data('z')] = $el
|
||||
|
||||
_refreshBlock: (x, y, z)->
|
||||
return unless @model?
|
||||
|
||||
stack = @model.getStackAt x, y, z
|
||||
$block = @_blockCache[x][y][z]
|
||||
position = @_computePosition x, y, z, hideUpperLayers:true
|
||||
move = false
|
||||
|
||||
if stack?
|
||||
itemDisplay = @_modPack.findItemDisplay stack.itemSlug
|
||||
|
||||
if not $block?
|
||||
$block = $("<img alt='#{itemDisplay.itemName}' class='block' />")
|
||||
$block.css position, top:-@IMAGE_SIZE, opacity:0.0
|
||||
@_registerHoverHandlers $block, y, itemDisplay
|
||||
@_imageLoader.load itemDisplay.iconUrl, $block
|
||||
@_blockCache[x][y][z] = $block
|
||||
@$el.append $block
|
||||
move = true
|
||||
else
|
||||
$block.attr 'src', itemDisplay.iconUrl
|
||||
move = true
|
||||
else if $block?
|
||||
$block.attr 'src', ''
|
||||
move = true
|
||||
|
||||
if move then _.delay (-> $block.css position), @_randomDropDelay()
|
||||
|
||||
_refreshAllBlocks: ->
|
||||
return unless @model?
|
||||
if @_endHovering? then @_endHovering()
|
||||
|
||||
for x in [0...@model.width]
|
||||
for y in [0...@model.height]
|
||||
for z in [0...@model.depth]
|
||||
@_refreshBlock(x, y, z)
|
||||
|
||||
_registerHoverHandlers: ($el, y, itemDisplay)->
|
||||
startHovering = =>
|
||||
return unless y is @_currentLayer
|
||||
zIndex = parseInt($el.css('z-index')) + 1
|
||||
zIndex = if _.isNaN(zIndex) then 0 else zIndex
|
||||
|
||||
@$outline.css opacity:1.0, top:$el.css('top'), left:$el.css('left'), 'z-index':zIndex
|
||||
@_onHovering itemDisplay
|
||||
|
||||
if @_hoverTimer? then clearTimeout @_hoverTimer
|
||||
@_hoverTimer = setTimeout (=> @_endHovering()), @HOVER_TIMEOUT
|
||||
|
||||
$el.hover startHovering, (->)
|
||||
@@ -0,0 +1,22 @@
|
||||
//-
|
||||
//- Crafting Guide - multiblock_viewer.jade
|
||||
//-
|
||||
//- Copyright (c) 2015 by Redwood Labs
|
||||
//- All rights reserved.
|
||||
//-
|
||||
|
||||
.view__multiblock_viewer
|
||||
.left
|
||||
h3 Complete Materials
|
||||
.view__inventory.complete
|
||||
|
||||
h3 Current Layer
|
||||
.view__inventory.layer
|
||||
.right
|
||||
.buttons
|
||||
.button.back: .bezel: p back
|
||||
.button.next: .bezel: p next
|
||||
.view__multiblock
|
||||
.caption
|
||||
img
|
||||
p
|
||||
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// Crafting Guide - multiblock_viewer.scss
|
||||
//
|
||||
// Copyright © 2014-2016 by Redwood Labs
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
.view__multiblock_viewer {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
|
||||
h3 {
|
||||
margin-bottom: $size-margin-small;
|
||||
margin-left: 0;
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-top: $size-margin-large;
|
||||
}
|
||||
}
|
||||
|
||||
.left {
|
||||
border-right: 1px solid $color-gray-light;
|
||||
flex: 1 0 40%;
|
||||
|
||||
.view__inventory {
|
||||
margin-left: $size-margin-medium;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
flex: 0 1 60%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.buttons {
|
||||
flex: 0 0 auto;
|
||||
margin-bottom: $size-margin-medium;
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.button {
|
||||
flex: 1 1 50%;
|
||||
margin-left: $size-margin-medium;
|
||||
}
|
||||
}
|
||||
|
||||
.view__multiblock {
|
||||
flex: 0 0 auto;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.caption {
|
||||
flex: 0 0 auto;
|
||||
margin-top: $size-margin-medium;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
margin-right : $size-margin-medium;
|
||||
height : $size-minecraft-block;
|
||||
width : $size-minecraft-block;
|
||||
|
||||
|
||||
border : none;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: $font-family-text;
|
||||
font-size: $font-size-medium;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
#
|
||||
# Crafting Guide - multiblock_viewer_controller.coffee
|
||||
#
|
||||
# Copyright © 2014-2016 by Redwood Labs
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
BaseController = require '../../base_controller'
|
||||
InventoryController = require '../../common/inventory/inventory_controller'
|
||||
MultiblockController = require './multiblock/multiblock_controller'
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
module.exports = class MultiblockViewerController extends BaseController
|
||||
|
||||
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.router? then throw new Error 'options.router is required'
|
||||
options.templateName = 'item_page/multiblock_viewer'
|
||||
super options
|
||||
|
||||
@_imageLoader = options.imageLoader
|
||||
@_modPack = options.modPack
|
||||
@_hoverTimer = null
|
||||
@_router = options.router
|
||||
|
||||
# Event Methods ################################################################################
|
||||
|
||||
onBackClicked: ->
|
||||
return if @$backButton.hasClass 'disabled'
|
||||
@multiblockController.goBackLayer()
|
||||
@refresh()
|
||||
|
||||
onNextClicked: ->
|
||||
return if @$nextButton.hasClass 'disabled'
|
||||
@multiblockController.goNextLayer()
|
||||
@refresh()
|
||||
|
||||
onBlockHovered: (itemDisplay)->
|
||||
if itemDisplay?
|
||||
@$captionText.html itemDisplay.itemName
|
||||
@_imageLoader.load itemDisplay.iconUrl, @$captionIcon
|
||||
else
|
||||
@$captionText.html ' '
|
||||
@$captionIcon.attr 'src', '/images/empty.png'
|
||||
|
||||
# BaseController Overrides #####################################################################
|
||||
|
||||
onDidRender: ->
|
||||
@completeInventoryController = @addChild InventoryController, '.view__inventory.complete',
|
||||
editable: false
|
||||
imageLoader: @_imageLoader
|
||||
modPack: @_modPack
|
||||
router: @_router
|
||||
|
||||
@layerInventoryController = @addChild InventoryController, '.view__inventory.layer',
|
||||
editable: false
|
||||
imageLoader: @_imageLoader
|
||||
modPack: @_modPack
|
||||
router: @_router
|
||||
|
||||
@multiblockController = @addChild MultiblockController, '.view__multiblock',
|
||||
imageLoader: @_imageLoader
|
||||
modPack: @_modPack
|
||||
onHovering: (itemDisplay)=> @onBlockHovered(itemDisplay)
|
||||
|
||||
@$backButton = @$('.button.back')
|
||||
@$nextButton = @$('.button.next')
|
||||
@$captionText = @$('.caption p')
|
||||
@$captionIcon = @$('.caption img')
|
||||
super
|
||||
|
||||
refresh: ->
|
||||
if @model?
|
||||
@completeInventoryController.model = @model.inventory
|
||||
@layerInventoryController.model = @model.getLayerInventory @multiblockController.currentLayer
|
||||
@multiblockController.model = @model
|
||||
|
||||
if @multiblockController.hasBackLayer()
|
||||
@$backButton.removeClass 'disabled'
|
||||
else
|
||||
@$backButton.addClass 'disabled'
|
||||
|
||||
if @multiblockController.hasNextLayer()
|
||||
@$nextButton.removeClass 'disabled'
|
||||
else
|
||||
@$nextButton.addClass 'disabled'
|
||||
|
||||
super
|
||||
|
||||
# Backbone.View Overrides ######################################################################
|
||||
|
||||
events: ->
|
||||
_.extend super,
|
||||
'click .button.back': 'onBackClicked'
|
||||
'click .button.next': 'onNextClicked'
|
||||
@@ -0,0 +1,19 @@
|
||||
//-
|
||||
//- Crafting Guide - recipe_detail.jade
|
||||
//-
|
||||
//- Copyright © 2014-2016 by Redwood Labs
|
||||
//- All rights reserved.
|
||||
//-
|
||||
|
||||
.view__recipe_detail
|
||||
.input
|
||||
h3 Ingredients
|
||||
.view__inventory
|
||||
|
||||
.pattern
|
||||
.view__crafting_grid
|
||||
a.tool
|
||||
|
||||
.output
|
||||
h3 Produces
|
||||
.view__inventory
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Crafting Guide - recipe_detail.scss
|
||||
//
|
||||
// Copyright © 2014-2016 by Redwood Labs
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
.view__recipe_detail {
|
||||
display : flex;
|
||||
|
||||
.input, .output{
|
||||
flex : 0 1 33%;
|
||||
|
||||
h3 {
|
||||
margin-bottom : 1em;
|
||||
}
|
||||
|
||||
.view__inventory {
|
||||
margin-left: $size-margin-large;
|
||||
}
|
||||
}
|
||||
|
||||
.pattern {
|
||||
flex : 0 1 33%;
|
||||
|
||||
display : flex;
|
||||
flex-direction : column;
|
||||
align-items : center;
|
||||
|
||||
.tool {
|
||||
margin-top : $size-margin-small;
|
||||
|
||||
font-family : $font-family-text;
|
||||
font-size : $font-size-medium;
|
||||
text-align : center;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
border-top : 1px solid $color-gray-light;
|
||||
margin-top : $size-margin-medium;
|
||||
padding-top : $size-margin-large;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
#
|
||||
# Crafting Guide - recipe_detail_controller.coffee
|
||||
#
|
||||
# Copyright © 2014-2016 by Redwood Labs
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
BaseController = require '../../base_controller'
|
||||
CraftingGridController = require '../../common/crafting_grid/crafting_grid_controller'
|
||||
Inventory = require '../../../models/game/inventory'
|
||||
InventoryController = require '../../common/inventory/inventory_controller'
|
||||
{StringBuilder} = require 'crafting-guide-common'
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
module.exports = class RecipeDetailController extends BaseController
|
||||
|
||||
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.router? then throw new Error 'options.router is required'
|
||||
options.templateName = 'item_page/recipe_detail'
|
||||
super options
|
||||
|
||||
@_imageLoader = options.imageLoader
|
||||
@_modPack = options.modPack
|
||||
@_router = options.router
|
||||
|
||||
# BaseController Overrides #####################################################################
|
||||
|
||||
onDidRender: ->
|
||||
@gridController = @addChild CraftingGridController, '.view__crafting_grid',
|
||||
imageLoader: @_imageLoader
|
||||
modPack: @_modPack
|
||||
router: @_router
|
||||
|
||||
@inputController = @addChild InventoryController, '.input .view__inventory',
|
||||
editable: false
|
||||
imageLoader: @_imageLoader
|
||||
model: new Inventory
|
||||
modPack: @_modPack
|
||||
router: @_router
|
||||
|
||||
@outputController = @addChild InventoryController, '.output .view__inventory',
|
||||
editable: false
|
||||
imageLoader: @_imageLoader
|
||||
model: new Inventory
|
||||
modPack: @_modPack
|
||||
router: @_router
|
||||
|
||||
@$toolContainer = @$('.tool')
|
||||
super
|
||||
|
||||
refresh: ->
|
||||
if @model?
|
||||
@gridController.model = @model
|
||||
@_refreshInputs()
|
||||
@_refreshOutputs()
|
||||
@_refreshTools()
|
||||
@show()
|
||||
else
|
||||
@hide()
|
||||
|
||||
super
|
||||
|
||||
# Backbone.View Methods ########################################################################
|
||||
|
||||
events: ->
|
||||
return _.extend super,
|
||||
'click a': 'routeLinkClick'
|
||||
|
||||
# Private Methods ##############################################################################
|
||||
|
||||
_refreshInputs: ->
|
||||
inputs = @inputController.model
|
||||
inputs.clear()
|
||||
|
||||
if @model?
|
||||
for stack in @model.input
|
||||
inputs.add stack.itemSlug, @model.getQuantityRequired stack.itemSlug
|
||||
|
||||
|
||||
_refreshOutputs: ->
|
||||
outputs = @outputController.model
|
||||
outputs.clear()
|
||||
|
||||
if @model?
|
||||
for stack in @model.output
|
||||
outputs.add stack.itemSlug, @model.getQuantityProduced stack.itemSlug
|
||||
|
||||
_refreshTools: ->
|
||||
@$toolContainer.empty()
|
||||
return unless @model?
|
||||
|
||||
builder = new StringBuilder
|
||||
builder.loop @model.tools, delimiter:', ', onEach:(b, stack)=>
|
||||
display = @_modPack.findItemDisplay stack.itemSlug
|
||||
b.push "<a href=\"#{display.itemUrl}\">#{display.itemName}</a>"
|
||||
@$toolContainer.html builder.toString()
|
||||
Reference in New Issue
Block a user