Files
website/src/client/site/item_page/item_page_controller.coffee
T

308 lines
12 KiB
CoffeeScript

#
# Crafting Guide - item_page_controller.coffee
#
# Copyright © 2014-2017 by Redwood Labs
# All rights reserved.
#
EditableFile = require "../../models/site/editable_file"
{Item} = require("crafting-guide-common").models
{ItemDetail} = require("crafting-guide-common").models
{ItemDetailJsonParser} = require("crafting-guide-common").parsing
ItemDisplay = require "../../models/site/item_display"
ItemGroupController = require "../common/item_group/item_group_controller"
ItemPage = require "../../models/site/item_page"
MarkdownSectionController = require "../common/markdown_section/markdown_section_controller"
PageController = require "../page_controller"
RecipeController = require "../common/recipe/recipe_controller"
RecipeDisplay = require "../../models/site/recipe_display"
VideoController = require "../common/video/video_controller"
w = require "when"
########################################################################################################################
module.exports = class ItemPageController extends PageController
@::FILE_UPLOAD_DELAY = 250
constructor: (options={})->
if not options.model?.constructor is ItemPage then throw new Error "options.model must be an ItemPage instance"
if not options.client? then throw new Error "options.client 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.templateName ?= "item_page"
super options
@_client = options.client
@_descriptionFile = null
@_enterFeedback = options.enterFeedback
@_imageLoader = options.imageLoader
@_modPack = options.modPack
@_router = options.router
@_triggerEditing = options.login
# Event Methods ################################################################################
craftingPlanButtonClicked: ->
tracker.trackEvent c.tracking.category.craft, "view-crafting-plan", @model.item.slug
@_router.navigate @model.itemDisplay.craftingUrl, trigger:true
return false
# PageController Overrides #####################################################################
getBreadcrumbs: ->
return [
$("<a href=\"/browse\">Browse</a>")
$("<a href=\"#{@model.itemDisplay.modUrl}\">#{@model.itemDisplay.mod.displayName}</a>")
$("<b>#{@model.itemDisplay.name}</b>")
]
getExtraNav: ->
item = @_modPack.chooseRandomItem()
return null unless item?
display = new ItemDisplay item
return $("<a href=\"#{display.url}\">Random Item</a>")
getMetaDescription: ->
data = itemName:@model.item.displayName, modName:@model.item.mod.displayName
return c.text.itemDescription data
getTitle: ->
return "#{@model.item.displayName} from #{@model.item.mod.displayName}"
# BaseController Overrides #####################################################################
onDidModelChange: ->
@trigger c.event.change
super
onDidRender: ->
options = imageLoader:@_imageLoader, modPack:@_modPack, router:@_router, show:false
@_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")
@$craftingPlanButton = @$(".button.craftingPlan")
@$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: ->
if @model.item?
@_imageLoader.load @model.itemDisplay.iconUrl, @$aboutImage
@$name.text @model.itemDisplay.name
@_descriptionController.imageBase = c.url.itemImageDir @model.itemDisplay
if @model.item.detail?.links.length > 0
@$officialLink.attr "href", @model.item.detail.links[0]
@show @$aboutLinks
else
@hide @$aboutLinks
if @model.item.isCraftable
@show @$craftingPlanButton
else
@hide @$craftingPlanButton
if @_triggerEditing
@_triggerEditing = false
@_descriptionController.onEditClicked {}
@show()
else
@hide()
@_refreshSourceMod()
@_refreshDescription()
@_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:@model.item.mod.id, itemSlug:@model.itemDisplay.itemSlug
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
parser = new ItemDetailJsonParser item:@model.item
parser.parse @_descriptionFile.getDecodedData "utf8"
else
@model.item.detail = new ItemDetail item:@model.item
@_descriptionController.model = @model.item.detail.description
_endEditingDescription: ->
oldDescription = @model.item.detail.description
promises = []
saveList = []
for imageFile in @_descriptionController.imageFiles
saveList.push
file: imageFile
message: "User-submitted image for #{@model.item.displayName} from #{global.hostName}"
@model.item.detail.description = @_descriptionController.model
parser = new ItemDetailJsonParser item:@model.item
@_descriptionFile.setDecodedData parser.format @model.item.detail
saveList.push
file: @_descriptionFile
message: "User-submitted text for #{@model.item.displayName} 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.detail.description = oldDescription
throw e
_refreshDescription: ->
if @model.item.detail?.description.length > 0
@_descriptionController.model = @model.item.detail.description
@_descriptionController.resetToDefaultState()
_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 recipes
controller = @_recipeControllers[index]
model = new RecipeDisplay
recipe: recipe
showInputInventory: true
showOutputInventory: true
if not controller?
controller = new RecipeController
imageLoader: @_imageLoader
modPack: @_modPack
model: model
router: @_router
@_recipeControllers.push controller
@$recipeContainer.append controller.$el
controller.render()
else
controller.model = model
index++
@show @$recipesSection
else
@hide @$recipesSection
while @_recipeControllers.length > index
@_recipeControllers.pop().remove()
_refreshSimilarItems: ->
groupName = @model.item.groupName
if groupName? and groupName isnt Item::DEFAULT_GROUP_NAME
@_similarItemsController.title = "Other #{groupName}"
@_similarItemsController.model = @model.findSimilarItems()
else
@_similarItemsController.model = null
_refreshSourceMod: ->
mod = @model.item.mod
@$sourceModLink.attr "href", c.url.mod @model.itemDisplay
@$sourceModLink.text mod.name
@show @$sourceModLink
_refreshUsedAsToolToMake: ->
@_usedAsToolToMakeController.title = "Used as Tool to Make"
@_usedAsToolToMakeController.model = @model.findToolForItems()
_refreshUsedToMake: ->
@_usedToMakeController.title = "Used to Make"
@_usedToMakeController.model = @model.findComponentInItems()
_refreshVideos: ->
@_videoControllers ?= []
index = 0
videos = @model.item.detail?.videos
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()