From 8b43c53a9ef264d10df96b692ce820289032138b Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Thu, 15 Jun 2017 22:39:17 -0700 Subject: [PATCH 01/21] WIP --- package.json | 2 +- src/client/client.coffee | 21 ++-- src/client/models/site/item_display.coffee | 54 ++++++++++ src/client/models/site/item_page.coffee | 85 +++++++++------ .../models/stores/mod_pack_store.coffee | 56 ---------- src/client/site/base_controller.coffee | 17 ++- .../browse_page/browse_page_controller.coffee | 3 +- .../mod_tile/mod_tile_controller.coffee | 8 +- .../item_tile/item_tile_controller.coffee | 28 +++-- .../mod_version_selector.jade | 3 - .../mod_version_selector_controller.coffee | 72 +++---------- .../item_page/item_page_controller.coffee | 58 ++++------ .../site/mod_page/mod_page_controller.coffee | 56 ++++------ src/client/site/router.coffee | 100 +++++++++--------- src/client/site/site_controller.coffee | 26 ++--- src/common/constants.coffee | 3 - 16 files changed, 267 insertions(+), 325 deletions(-) create mode 100644 src/client/models/site/item_display.coffee delete mode 100644 src/client/models/stores/mod_pack_store.coffee diff --git a/package.json b/package.json index 6bd28e8b6..b62a407e2 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "body-parser": "1.17.1", "client-sessions": "0.8.0", "cookie-parser": "1.4.3", - "crafting-guide-common": ">=3.0.0", + "crafting-guide-common": ">=5.0.0", "dotenv": "4.0.0", "express": "4.15.2", "express-session": "1.15.2", diff --git a/src/client/client.coffee b/src/client/client.coffee index 9c7bbc064..67822d11f 100644 --- a/src/client/client.coffee +++ b/src/client/client.coffee @@ -74,11 +74,18 @@ client.startMonitoringStatus() ######################################################################################################################## -SiteController = require './site/site_controller' -global.site = site = new SiteController client:client, storage:storage -site.render() -site.loadDefaultModPack() -site.loadCurrentUser() +{http, ModPackStore} = require("crafting-guide-common").api +modPackBaseUrl = "#{location.protocol}//#{location.hostname}:#{location.port}" +modPackStore = new ModPackStore http, modPackBaseUrl -Backbone.history.start pushState:true -logger.info -> "CraftingGuide is ready" +######################################################################################################################## + +modPackStore.load c.modPacks.default + .then (modPack)-> + SiteController = require './site/site_controller' + global.site = site = new SiteController client:client, storage:storage, modPack:modPack + site.render() + site.loadCurrentUser() + + Backbone.history.start pushState:true + logger.info -> "CraftingGuide is ready" diff --git a/src/client/models/site/item_display.coffee b/src/client/models/site/item_display.coffee new file mode 100644 index 000000000..a42b12cb6 --- /dev/null +++ b/src/client/models/site/item_display.coffee @@ -0,0 +1,54 @@ +# +# Crafting Guide - item_page.coffee +# +# Copyright © 2014-2017 by Redwood Labs +# All rights reserved. +# + +_ = require "../../../common/underscore" +c = require "../../../common/constants" +{Inventory} = require("crafting-guide-common").models + +######################################################################################################################## + +module.exports = class ItemDisplay + + constructor: (item)-> + @item = item + + # Properties ################################################################################### + + Object.defineProperties @prototype, + + craftingUrl: + get: -> + inventory = new Inventory + inventory.add @item + c.url.crafting inventoryText:inventory.unparse() + + iconUrl: + get: -> return c.url.itemIcon modId:@_item.mod.id, itemSlug:@slug + set: -> throw new Error "iconUrl cannot be assigned" + + item: + get: -> return @_item + set: (item)-> + if @_item? then throw new Error "item cannot be re-assigned" + if not item? then throw new Error "item is required" + @_item = item + + modUrl: + get: -> return c.url.mod modId:@item.mod.id + set: -> throw new Error "modUrl cannot be assigned" + + name: + get: -> return @item.displayName + set: -> throw new Error "name cannot be assigned" + + slug: + get: -> return _.slugify @name + set: -> throw new Error "slug cannot be assigned" + + url: + get: -> return c.url.item modId:@_item.mod.id, itemSlug:@slug + set: -> throw new Error "url cannot be assigned" diff --git a/src/client/models/site/item_page.coffee b/src/client/models/site/item_page.coffee index c0a812bd8..92b1388cf 100644 --- a/src/client/models/site/item_page.coffee +++ b/src/client/models/site/item_page.coffee @@ -5,53 +5,74 @@ # All rights reserved. # -{BaseModel} = require("crafting-guide-common").deprecated +{Item} = require("crafting-guide-common").models +ItemDisplay = require "../item_display" +{Observable} = require("crafting-guide-common").util ######################################################################################################################## -module.exports = class ItemPage extends BaseModel +module.exports = class ItemPage extends Observable - constructor: (attributes={}, options={})-> - if not attributes.modPack? then throw new Error 'attributes.modPack is required' - attributes.item ?= null - super attributes, options + constructor: (item)-> + if item.constructor isnt Item then throw new Error "item must be an Item instance" + @item = item + super + + # Properties ################################################################################### + + Object.defineProperties @prototype, + + item: + get: -> return @_item + set: (item)-> + if @_item? then throw new Error "item cannot be reassigned" + if not item? then throw new Error "item is required" + @_item = item + + itemDisplay: + get: -> return @_itemDisplay ?= new ItemDisplay @item + + mod: + get: -> return @_item.mod + set: -> throw new Error "mod cannot be assigned" + + modPack: + get: -> return @mod.modPack + set: -> throw new Error "modPack cannot be assigned" # Property Methods ############################################################################# findComponentInItems: -> - return @_findRecipesMatching (recipe)=> recipe.requires @item.slug + return @_findItemsWithMatchingRecipes (recipe)=> + recipe.computeQuantityRequired @item findSimilarItems: -> - return null unless @item?.modVersion? + group = @mod.itemGroups[@item.groupName] + return unless group? - result = [] - @item.modVersion.eachItemInGroup @item.group, (item)=> - result.push item + return null unless group.length > 0 + return group - return null unless result.length > 0 - return result - - findRecipes: -> - return @modPack.findRecipes @item?.slug, [], alwaysFromOwningMod:true - - findToolForRecipes: -> - return @_findRecipesMatching (recipe)=> recipe.requiresTool @item.slug + findToolForItem: -> + return @_findItemsWithMatchingRecipes (recipe)=> + return recipe.tools[@item.id]? # Private Methods ############################################################################## - _findRecipesMatching: (isAcceptable)-> - return null unless @item? - + _findItemsWithMatchingRecipes: (isMatching)-> result = {} - @modPack.eachMod (mod)=> - mod.eachRecipe (recipe)=> - if isAcceptable recipe - for outputStack in recipe.output - continue if recipe.isPassThroughFor outputStack.itemSlug - outputItem = @modPack.findItem outputStack.itemSlug, includeDisabled:true - result[outputItem.slug] = outputItem - result = _.values result - return null unless result.length > 0 + for modId, mod of @modPack.mods + for itemId, item of mod.items + for recipeId, recipe of item.recipes + if isMatching(recipe) + result[item.id] = item - return result.sort (a, b)-> a.compareTo b + result = (item for itemId, item of result) + result.sort (a, b)-> + if not a?.displayName? and not b?.displayName? then return 0 + if not b?.displayName? then return +1 + if not a?.displayName? then return +1 + return a.displayName.localeCompare b.displayName + + return result diff --git a/src/client/models/stores/mod_pack_store.coffee b/src/client/models/stores/mod_pack_store.coffee deleted file mode 100644 index 8184c3e3d..000000000 --- a/src/client/models/stores/mod_pack_store.coffee +++ /dev/null @@ -1,56 +0,0 @@ -# -# Crafting Guide - mod_pack_store.coffee -# -# Copyright © 2014-2017 by Redwood Labs -# All rights reserved. -# - -ModPackJsonParser = require "../parsing/mod_pack_json_parser" -w = require "when" - -######################################################################################################################## - -module.exports = class ModPackStore - - constructor: -> - @_data = {} - @_loading = {} - @_parser = new ModPackJsonParser - - # Class Methods ################################################################################ - - Object.defineProperties ModPackStore, - instance: - get: -> - @_instance ?= new ModPackStore - return @_instance - set: -> - throw new Error "cannot assign instance" - - # Public Methods ############################################################################### - - get: (modPackId)-> - return @_data[modPackId] - - load: (modPackId)-> - if not @_loading[modPackId]? - @_loading[modPackId] = w.promise (resolve, reject)-> - url = c.url.modPackArchive modPackId:modPackId - - onError = (xhr, status, message)=> - logger.error "failed to load mod pack #{modPackId}: #{status} — #{message}" - reject new Error message - - onSuccess = (data, status, xhr)=> - logger.info "laoded mod pack: #{modPackId}" - try - @_parser.reset() - modPack = @_parser.parse data, url - @_data[modPack.id] = modPack - resolve modPack - catch error - reject error - - $.ajax dataType: "text", error: onError, success: onSuccess, url: url - - return @_loading[modPackId] diff --git a/src/client/site/base_controller.coffee b/src/client/site/base_controller.coffee index 21564d860..c4fcff5ed 100644 --- a/src/client/site/base_controller.coffee +++ b/src/client/site/base_controller.coffee @@ -5,7 +5,8 @@ # All rights reserved. # -templates = require './templates' +{Observable} = require("crafting-guide-common").util +templates = require './templates' ######################################################################################################################## @@ -84,9 +85,6 @@ module.exports = class BaseController extends Backbone.View onDidModelChange: -> @tryRefresh() - onDidModelSync: -> - @tryRefresh() - onWillRender: -> # do nothing onDidRender: -> # do nothing @@ -96,11 +94,12 @@ module.exports = class BaseController extends Backbone.View onDidShow: -> # do nothing onWillChangeModel: (oldModel, newModel)-> - if oldModel?.on? - @stopListening oldModel - if newModel?.on? - @listenTo newModel, 'sync', (e)=> @onDidModelSync e - @listenTo newModel, 'change', (e)=> @onDidModelChange e + if oldModel?.isObservable + oldModel.off target:this + + if newModel?.isObservable + newModel.on Observable::ANY, this, "onDidModelChange" + return newModel # Property Methods ############################################################################# diff --git a/src/client/site/browse_page/browse_page_controller.coffee b/src/client/site/browse_page/browse_page_controller.coffee index 7baa67088..28c8a648a 100644 --- a/src/client/site/browse_page/browse_page_controller.coffee +++ b/src/client/site/browse_page/browse_page_controller.coffee @@ -28,7 +28,6 @@ module.exports = class BrowsePageController extends PageController @_tileControllers = [] @_client.on c.event.change, => @tryRefresh() - @_modPack.on c.event.change, => @tryRefresh() # Property Methods ############################################################################# @@ -81,7 +80,7 @@ module.exports = class BrowsePageController extends PageController _refreshModTiles: -> index = 0 - mods = @_modPack.getAllMods() + mods = (mod for modId, mod of @_modPack.mods) for mod in mods controller = @_tileControllers[index] if not controller diff --git a/src/client/site/browse_page/mod_tile/mod_tile_controller.coffee b/src/client/site/browse_page/mod_tile/mod_tile_controller.coffee index ecb42f375..9c3fe8640 100644 --- a/src/client/site/browse_page/mod_tile/mod_tile_controller.coffee +++ b/src/client/site/browse_page/mod_tile/mod_tile_controller.coffee @@ -29,12 +29,12 @@ module.exports = class ModTileController extends BaseController super refresh: -> - @$link.attr 'href', c.url.mod modSlug:@model.slug - @$logoImage.attr 'src', c.url.modIcon modSlug:@model.slug - @$title.text @model.name + @$link.attr 'href', c.url.mod modId:@model.id + @$logoImage.attr 'src', c.url.modIcon modId:@model.id + @$title.text @model.displayName @$description.text @model.description - if @model.enabled + if @model.isEnabled @$el.removeClass 'disabled' else @$el.addClass 'disabled' diff --git a/src/client/site/common/item_group/item_tile/item_tile_controller.coffee b/src/client/site/common/item_group/item_tile/item_tile_controller.coffee index ad867f32e..147ed405e 100644 --- a/src/client/site/common/item_group/item_tile/item_tile_controller.coffee +++ b/src/client/site/common/item_group/item_tile/item_tile_controller.coffee @@ -5,39 +5,37 @@ # All rights reserved. # -BaseController = require '../../../base_controller' +BaseController = require "../../../base_controller" +ItemDisplay = require "../../../../models/site/item_display" ######################################################################################################################## module.exports = class ItemTileController extends BaseController constructor: (options={})-> - if not options.imageLoader? then throw new Error 'options.imageLoader is required' - if not options.model? then throw new Error 'options.model is required' - if not options.modPack? then throw new Error 'options.modPack is required' - options.templateName = 'common/item_group/item_tile' + if not options.imageLoader? then throw new Error "options.imageLoader is required" + if not options.model? then throw new Error "options.model is required" + options.templateName = "common/item_group/item_tile" super options @_imageLoader = options.imageLoader - @_modPack = options.modPack + @_display = new ItemDisplay @model # BaseController Overrides ##################################################################### onDidRender: -> - @$icon = @$('img') - @$name = @$('.itemName') - @$nameLink = @$('a') + @$icon = @$("img") + @$name = @$(".itemName") + @$nameLink = @$("a") super refresh: -> - display = @_modPack.findItemDisplay @model.slug - - @_imageLoader.load display.iconUrl, @$icon - @$name.html display.itemName - @$nameLink.attr 'href', display.itemUrl + @_imageLoader.load @_display.iconUrl, @$icon + @$name.html @_display.name + @$nameLink.attr "href", @_display.url # Backbone.View Overrides ###################################################################### events: -> return _.extend super, - 'click a': 'routeLinkClick' + "click a": "routeLinkClick" diff --git a/src/client/site/common/mod_version_selector/mod_version_selector.jade b/src/client/site/common/mod_version_selector/mod_version_selector.jade index af77d0254..158b81d48 100644 --- a/src/client/site/common/mod_version_selector/mod_version_selector.jade +++ b/src/client/site/common/mod_version_selector/mod_version_selector.jade @@ -2,8 +2,5 @@ .toggle span.checkbox span.label I have this mod in my modpack - .version - span Version: - select .warning. PLEASE NOTE: Crafting plans, search, and other features will ignore items and recipes from this mod. diff --git a/src/client/site/common/mod_version_selector/mod_version_selector_controller.coffee b/src/client/site/common/mod_version_selector/mod_version_selector_controller.coffee index 125a8debd..b50805a05 100644 --- a/src/client/site/common/mod_version_selector/mod_version_selector_controller.coffee +++ b/src/client/site/common/mod_version_selector/mod_version_selector_controller.coffee @@ -5,97 +5,59 @@ # All rights reserved. # -BaseController = require '../../base_controller' -{Mod} = require('crafting-guide-common').deprecated.game +BaseController = require "../../base_controller" +{Mod} = require("crafting-guide-common").models ######################################################################################################################## module.exports = class ModVersionSelectorController extends BaseController constructor: (options={})-> - if not options.model? then throw new Error 'options.model is required' - options.templateName = 'common/mod_version_selector' + if options.model?.constructor isnt Mod then throw new Error "options.model must be a Mod" + options.templateName = "common/mod_version_selector" super options # Event Methods ################################################################################ onToggleEnabled: -> - if @model.activeVersion is Mod.Version.None - tracker.trackEvent c.tracking.category.modPack, 'toggle-on', @model.slug - @model.activeVersion = Mod.Version.Latest + if not @model.isEnabled + tracker.trackEvent c.tracking.category.modPack, "toggle-on", @model.id + @model.isEnabled = true else - tracker.trackEvent c.tracking.category.modPack, 'toggle-off', @model.slug - @model.activeVersion = Mod.Version.None + tracker.trackEvent c.tracking.category.modPack, "toggle-off", @model.id + @model.isEnabled = false return false - onVersionChanged: -> - @model.activeVersion = @$versionSelector.val() - tracker.trackEvent c.tracking.category.modPack, 'select-version', "#{@model.slug}@#{@model.activeVersion}" - return false - - # Property Methods ############################################################################# - - Object.defineProperties @prototype, - - effectiveModVersion: - get: -> - modVersion = @model.activeModVersion - modVersion ?= @model.getModVersion Mod.Version.Latest - modVersion.fetch() if modVersion? - return modVersion - # BaseController Overrides ##################################################################### onDidRender: -> - @$toggleSection = @$('.toggle') - @$versionSection = @$('.version') - @$versionSelector = @$('.version select') - @$warning = @$('.warning') + @$toggleSection = @$(".toggle") + @$warning = @$(".warning") super refresh: -> + console.log "refreshing" @_refreshEnabled() - @_refreshVersionSelector() super # Backbone.View Overrides ###################################################################### events: -> return _.extend super, - 'change .version select': 'onVersionChanged' - 'click .toggle': 'onToggleEnabled' + "click .toggle": "onToggleEnabled" # Private Methods ############################################################################## _refreshEnabled: -> - if @model.slug in c.requiredMods + if @model.id in c.requiredMods @hide @$toggleSection else @show @$toggleSection - if @model.activeVersion is Mod.Version.None - @$toggleSection.removeClass 'enabled' + if not @model.isEnabled + @$toggleSection.removeClass "enabled" @show @$warning else - @$toggleSection.addClass 'enabled' + @$toggleSection.addClass "enabled" @hide @$warning - - _refreshVersionSelector: -> - modVersions = @model.modVersions - - if (@model.activeVersion is Mod.Version.None) or modVersions.length < 2 - @hide @$versionSection - else - @show @$versionSection - - selectedModVersion = @effectiveModVersion - - @$versionSelector.empty() - - for modVersion in @model.modVersions - $option = $("") - if modVersion is selectedModVersion - $option.attr 'selected', 'true' - @$versionSelector.append $option - @$versionSelector.css display:'' diff --git a/src/client/site/item_page/item_page_controller.coffee b/src/client/site/item_page/item_page_controller.coffee index 3012c864b..13cb067d9 100644 --- a/src/client/site/item_page/item_page_controller.coffee +++ b/src/client/site/item_page/item_page_controller.coffee @@ -5,16 +5,16 @@ # All rights reserved. # -EditableFile = require '../../models/site/editable_file' -{Item} = require('crafting-guide-common').deprecated.game -ItemGroupController = require '../common/item_group/item_group_controller' -ItemPage = require '../../models/site/item_page' -{ItemSlug} = require('crafting-guide-common').deprecated.game -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' +EditableFile = require "../../models/site/editable_file" +{Item} = require("crafting-guide-common").models +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" +MultiblockViewerController = require "./multiblock_viewer/multiblock_viewer_controller" +PageController = require "../page_controller" +RecipeDetailController = require "./recipe_detail/recipe_detail_controller" +VideoController = require "../common/video/video_controller" w = require "when" ######################################################################################################################## @@ -24,34 +24,27 @@ 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' + 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 - @_itemSlug = options.itemSlug @_modPack = options.modPack @_router = options.router @_triggerEditing = options.login - @_modPack.on c.event.change, => - @tryRefresh() - @trigger c.event.change - # Event Methods ################################################################################ craftingPlanButtonClicked: -> - tracker.trackEvent c.tracking.category.craft, 'view-crafting-plan', @model.item.slug + tracker.trackEvent c.tracking.category.craft, "view-crafting-plan", @model.item.slug display = @_modPack.findItemDisplay @model.item.slug @_router.navigate display.craftingUrl, trigger:true return false @@ -59,23 +52,18 @@ module.exports = class ItemPageController extends PageController # PageController Overrides ##################################################################### getBreadcrumbs: -> - return [] unless @_itemSlug? - - display = @_modPack.findItemDisplay @_itemSlug - return [] unless display.itemName? and display.modName - return [ $("Browse") - $("#{display.modName}") - $("#{display.itemName}") + $("#{@model.display.modName}") + $("#{display.name}") ] getExtraNav: -> - itemSlug = @_modPack.chooseRandomItem() - return null unless itemSlug? + item = @_modPack.chooseRandomItem() + return null unless item? - itemDisplay = @_modPack.findItemDisplay itemSlug - return $("Random Item") + display = new ItemDisplay item + return $("Random Item") getMetaDescription: -> return null unless @_itemSlug? diff --git a/src/client/site/mod_page/mod_page_controller.coffee b/src/client/site/mod_page/mod_page_controller.coffee index e8380e89a..86f020672 100644 --- a/src/client/site/mod_page/mod_page_controller.coffee +++ b/src/client/site/mod_page/mod_page_controller.coffee @@ -27,27 +27,16 @@ module.exports = class ModPageController extends PageController @_modPack = options.modPack @_router = options.router - # Property Methods ############################################################################# - - Object.defineProperties @prototype, - - effectiveModVersion: - get: -> - modVersion = @model.activeModVersion - modVersion ?= @model.getModVersion Mod.Version.Latest - modVersion.fetch() if modVersion? - return modVersion - # PageController Overrides ##################################################################### getBreadcrumbs: -> return [ $('Browse') - $("#{@model.name}") + $("#{@model.displayName}") ] getTitle: -> - return @model.name + return @model.displayName # BaseController Overrides ##################################################################### @@ -87,8 +76,8 @@ module.exports = class ModPageController extends PageController @$documentationLink.attr 'href', @model.documentationUrl @$downloadLink.attr 'href', @model.downloadUrl @$homePageLink.attr 'href', @model.homePageUrl - @$logo.attr 'src', c.url.modIcon modSlug:@model.slug - @$title.text @model.name + @$logo.attr 'src', c.url.modIcon modId:@model.id + @$title.text @model.displayName else @$author.text '' @$description.text '' @@ -101,29 +90,24 @@ module.exports = class ModPageController extends PageController _refreshItemGroups: -> @_groupControllers ?= [] groupIndex = 0 - modVersion = @effectiveModVersion - if modVersion? - modVersion.eachGroup (group)=> - controller = @_groupControllers[groupIndex] - items = modVersion.allItemsInGroup group - if not controller? - controller = new ItemGroupController - imageLoader: @_imageLoader - model: items - modPack: @_modPack - router: @_router - title: if group is Item.Group.Other then 'Items' else group + for groupName, items of @model.itemGroups + controller = @_groupControllers[groupIndex] + if not controller? + controller = new ItemGroupController + imageLoader: @_imageLoader + model: items + modPack: @_modPack + router: @_router + title: groupName - _.defer => - @_groupControllers.push controller - @$itemGroups.append controller.$el - controller.render() - else - controller.modVersion = modVersion - controller.model = items - controller.refresh() - groupIndex++ + @_groupControllers.push controller + @$itemGroups.append controller.$el + controller.render() + else + controller.model = items + controller.refresh() + groupIndex++ while @_groupControllers.length > groupIndex + 1 @_groupControllers.pop().remove() diff --git a/src/client/site/router.coffee b/src/client/site/router.coffee index bec2bf4de..b7624a57a 100644 --- a/src/client/site/router.coffee +++ b/src/client/site/router.coffee @@ -5,15 +5,16 @@ # All rights reserved. # -BrowsePageController = require './browse_page/browse_page_controller' -CraftPageController = require './craft_page/craft_page_controller' -ItemPageController = require './item_page/item_page_controller' -{ItemSlug} = require('crafting-guide-common').deprecated.game -LoginPageController = require './login_page/login_page_controller' -ModPageController = require './mod_page/mod_page_controller' -NewsPageController = require './news_page/news_page_controller' -TutorialPageController = require './tutorial_page/tutorial_page_controller' -UrlParams = require './url_params' +BrowsePageController = require "./browse_page/browse_page_controller" +CraftPageController = require "./craft_page/craft_page_controller" +ItemPage = require "../models/site/item_page" +ItemPageController = require "./item_page/item_page_controller" +{ItemSlug} = require("crafting-guide-common").deprecated.game +LoginPageController = require "./login_page/login_page_controller" +ModPageController = require "./mod_page/mod_page_controller" +NewsPageController = require "./news_page/news_page_controller" +TutorialPageController = require "./tutorial_page/tutorial_page_controller" +UrlParams = require "./url_params" ######################################################################################################################## @@ -34,50 +35,50 @@ module.exports = class Router extends Backbone.Router tracker.trackPageView() routes: - '': 'route__home' - '/': 'route__home' - '/index.html': 'route__home' + '': 'route__home' + '/': 'route__home' + '/index.html': 'route__home' - 'browse': 'route__browse' - 'browse/': 'route__browse' - 'browse/index.html': 'route__browse' + 'browse': 'route__browse' + 'browse/': 'route__browse' + 'browse/index.html': 'route__browse' - 'browse/:modSlug': 'route__browseMod' - 'browse/:modSlug/': 'route__browseMod' - 'browse/:modSlug/index.html': 'route__browseMod' + 'browse/:modId': 'route__browseMod' + 'browse/:modId/': 'route__browseMod' + 'browse/:modId/index.html': 'route__browseMod' - 'browse/:modSlug/:itemSlug': 'route__browseModItem' - 'browse/:modSlug/:itemSlug/': 'route__browseModItem' - 'browse/:modSlug/:itemSlug/index.html': 'route__browseModItem' + 'browse/:modId/:itemSlug': 'route__browseModItem' + 'browse/:modId/:itemSlug/': 'route__browseModItem' + 'browse/:modId/:itemSlug/index.html': 'route__browseModItem' - 'browse/:modSlug/tutorials/:tutorialSlug': 'route__browseTutorial' - 'browse/:modSlug/tutorials/:tutorialSlug/': 'route__browseTutorial' - 'browse/:modSlug/tutorials/:tutorialSlug/index.html': 'route__browseTutorial' + 'browse/:modId/tutorials/:tutorialSlug': 'route__browseTutorial' + 'browse/:modId/tutorials/:tutorialSlug/': 'route__browseTutorial' + 'browse/:modId/tutorials/:tutorialSlug/index.html': 'route__browseTutorial' - 'configure': 'route__configure' - 'configure/': 'route__configure' - 'configure/index.html': 'route__configure' + 'configure': 'route__configure' + 'configure/': 'route__configure' + 'configure/index.html': 'route__configure' - 'craft': 'route__craft' - 'craft/': 'route__craft' - 'craft/index.html': 'route__craft' + 'craft': 'route__craft' + 'craft/': 'route__craft' + 'craft/index.html': 'route__craft' - 'craft/:text': 'route__craft' - 'craft/:text/': 'route__craft' - 'craft/:text/index.html': 'route__craft' + 'craft/:text': 'route__craft' + 'craft/:text/': 'route__craft' + 'craft/:text/index.html': 'route__craft' - 'login': 'route__login' - 'login/': 'route__login' - 'login/index.html': 'route__login' + 'login': 'route__login' + 'login/': 'route__login' + 'login/index.html': 'route__login' - 'news': 'route__news' - 'news/': 'route__news' - 'news/index.html': 'route__news' + 'news': 'route__news' + 'news/': 'route__news' + 'news/index.html': 'route__news' - 'item/:itemSlug': 'deprecated__item' - 'crafting/(:text)': 'deprecated__crafting' - 'mod/:modSlug': 'deprecated__mod' - 'mod/:modSlug/:itemSlug': 'deprecated__modItem' + 'item/:itemSlug': 'deprecated__item' + 'crafting/(:text)': 'deprecated__crafting' + 'mod/:modSlug': 'deprecated__mod' + 'mod/:modSlug/:itemSlug': 'deprecated__modItem' # Route Methods ################################################################################ @@ -92,15 +93,18 @@ module.exports = class Router extends Backbone.Router route__browse: -> @_siteController.setPage 'browse', new BrowsePageController @_makeOptions {} - route__browseMod: (modSlug)-> + route__browseMod: (modId)-> controller = new ModPageController @_makeOptions() - controller.model = @_siteController.modPack.getMod modSlug + controller.model = @_siteController.modPack.mods[modId] @_siteController.setPage 'browseMod', controller - route__browseModItem: (modSlug, itemSlug)-> + route__browseModItem: (modId, itemSlug)-> + item = @_siteController.modPack.findItemBySlug itemSlug, modId:modId + if not item? then throw new Error "could not find item #{modId}__#{itemSlug}" + + itemPage = new ItemPage item params = new UrlParams login:{type:'boolean', default:false} - slug = new ItemSlug modSlug, itemSlug - controller = new ItemPageController @_makeOptions {itemSlug:slug, login:params.login} + controller = new ItemPageController @_makeOptions {model:itemPage, login:params.login} @_siteController.setPage 'browseModItem', controller route__browseTutorial: (modSlug, tutorialSlug)-> diff --git a/src/client/site/site_controller.coffee b/src/client/site/site_controller.coffee index f44ef194b..c0bbeb6cc 100644 --- a/src/client/site/site_controller.coffee +++ b/src/client/site/site_controller.coffee @@ -7,6 +7,7 @@ AdsenseController = require './common/adsense/adsense_controller' BaseController = require './base_controller' +c = require "../../common/constants" FeedbackController = require './feedback/feedback_controller' FileCache = require '../models/site/file_cache' FooterController = require './footer/footer_controller' @@ -23,14 +24,14 @@ module.exports = class SiteController extends BaseController constructor: (options={})-> if not options.client? then throw new Error 'options.client 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.el = 'html' super options @client = options.client - @fileCache = new FileCache c.url.modpackArchive() @imageLoader = new ImageLoader defaultUrl:'/images/unknown.png' - @modPack = new ModPack {}, fileCache:@fileCache + @modPack = options.modPack @router = new Router this @storage = options.storage @@ -41,23 +42,6 @@ module.exports = class SiteController extends BaseController # Public Methods ############################################################################### - loadDefaultModPack: -> - makeResponder = (m)-> return -> - m.activeModVersion.fetch() if m.activeModVersion? - - for modSlug, modData of c.defaultMods - mod = new Mod {slug:modSlug}, {fileCache:@fileCache} - mod.on c.event.change + ':activeModVersion', makeResponder mod - @storage.register "mod:#{mod.slug}", mod, 'activeVersion', modData.defaultVersion - mod.fetch() - - @modPack.addMod mod - - if global.env isnt 'prerender' - @modPack.once c.event.sync, => - @$pageContent.removeClass 'hidden' - @$pageContentLoading.addClass 'hidden' - loadCurrentUser: -> @client.getCurrentUser() .then (response)=> @@ -129,6 +113,10 @@ module.exports = class SiteController extends BaseController @_feedbackController = @addChild FeedbackController, '.view__feedback' + if global.env isnt "prerender" + @$pageContent.removeClass "hidden" + @$pageContentLoading.addClass "hidden" + # Private Methods ############################################################################## setPage: (page, controller)-> diff --git a/src/common/constants.coffee b/src/common/constants.coffee index 9ba786139..8c1214f7a 100644 --- a/src/common/constants.coffee +++ b/src/common/constants.coffee @@ -99,9 +99,6 @@ login.clientIds = 'staging': '3d75ed772ce5004180d6' 'production': 'ce71be7f66926ff6ff38' -exports.modpack = modpack = {} -modpack.default = "crafting-guide-default" - exports.opacity = opacity = {} opacity.hidden = 1e-6 opacity.shown = 1 From 5f65f77222374f9c0bbe6428a53c130d0c057bc4 Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Sat, 17 Jun 2017 23:25:18 -0700 Subject: [PATCH 02/21] Add support for videos on mod pages --- src/client/site/mod_page/mod_page.jade | 4 ++ src/client/site/mod_page/mod_page.scss | 20 +++++++++ .../site/mod_page/mod_page_controller.coffee | 43 ++++++++++++++++--- 3 files changed, 61 insertions(+), 6 deletions(-) diff --git a/src/client/site/mod_page/mod_page.jade b/src/client/site/mod_page/mod_page.jade index 05d576281..0a3063794 100644 --- a/src/client/site/mod_page/mod_page.jade +++ b/src/client/site/mod_page/mod_page.jade @@ -24,6 +24,10 @@ a.documentation(target="documentation") documentation a.download(target="download") download + section.videos + h2 Videos + .panel + section.tutorials h2 Tutorials .panel diff --git a/src/client/site/mod_page/mod_page.scss b/src/client/site/mod_page/mod_page.scss index 93860be50..7bf50b17a 100644 --- a/src/client/site/mod_page/mod_page.scss +++ b/src/client/site/mod_page/mod_page.scss @@ -59,6 +59,18 @@ @include layout-link-list; } } + + section.videos { + .panel { + display: flex; + flex-wrap: wrap; + + .view__video { + flex: 0 0 50%; + margin-bottom: $size-margin-large; + } + } + } } @include screen-size(mobile) { @@ -97,5 +109,13 @@ margin-right: $size-margin-medium; } } + + section.videos { + .panel { + .view__video { + flex: 0 0 100%; + } + } + } } } diff --git a/src/client/site/mod_page/mod_page_controller.coffee b/src/client/site/mod_page/mod_page_controller.coffee index 86f020672..7feebe00f 100644 --- a/src/client/site/mod_page/mod_page_controller.coffee +++ b/src/client/site/mod_page/mod_page_controller.coffee @@ -5,12 +5,13 @@ # All rights reserved. # -{Item} = require('crafting-guide-common').deprecated.game -ItemGroupController = require '../common/item_group/item_group_controller' -{Mod} = require('crafting-guide-common').deprecated.game -ModVersionSelectorController = require '../common/mod_version_selector/mod_version_selector_controller' -PageController = require '../page_controller' -TutorialController = require './tutorial/tutorial_controller' +{Item} = require("crafting-guide-common").deprecated.game +ItemGroupController = require "../common/item_group/item_group_controller" +{Mod} = require("crafting-guide-common").deprecated.game +ModVersionSelectorController = require "../common/mod_version_selector/mod_version_selector_controller" +PageController = require "../page_controller" +TutorialController = require "./tutorial/tutorial_controller" +VideoController = require "../common/video/video_controller" ######################################################################################################################## @@ -53,12 +54,16 @@ module.exports = class ModPageController extends PageController @$title = @$('.about .title') @$tutorialsContainer = @$('section.tutorials .panel') @$tutorialsSection = @$('section.tutorials') + @$videosContainer = @$('section.videos .panel') + @$videosSection = @$('section.videos') + @$videosSectionTitle = @$('section.videos h2') super refresh: -> @_refreshAboutBlock() @_refreshItemGroups() @_refreshTutorials() + @_refreshVideos() super # Backbone.View Overrides ###################################################################### @@ -136,3 +141,29 @@ module.exports = class ModPageController extends PageController @show @$tutorialsSection else @hide @$tutorialsSection + + _refreshVideos: -> + @_videoControllers ?= [] + index = 0 + + videos = @model?.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() From b4cde5a37b10b828d688a646c429fef69f09775e Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Sun, 18 Jun 2017 10:15:12 -0700 Subject: [PATCH 03/21] Add Amazon ad unit --- src/client/site/common/amazon/amazon.jade | 8 ++++++++ src/client/site/common/amazon/amazon.scss | 10 ++++++++++ src/client/site/item_page/item_page.jade | 2 ++ 3 files changed, 20 insertions(+) create mode 100644 src/client/site/common/amazon/amazon.jade create mode 100644 src/client/site/common/amazon/amazon.scss diff --git a/src/client/site/common/amazon/amazon.jade b/src/client/site/common/amazon/amazon.jade new file mode 100644 index 000000000..c3ec7f43b --- /dev/null +++ b/src/client/site/common/amazon/amazon.jade @@ -0,0 +1,8 @@ +//- +//- Crafting Guide - amazon.jade +//- +//- Copyright © 2014-2017 by Redwood Labs +//- All rights reserved. +//- + +script(src="//z-na.amazon-adsystem.com/widgets/onejs?MarketPlace=US&adInstanceId=357573bb-98d8-4294-8cdf-4361dbf11cee") diff --git a/src/client/site/common/amazon/amazon.scss b/src/client/site/common/amazon/amazon.scss new file mode 100644 index 000000000..f63545227 --- /dev/null +++ b/src/client/site/common/amazon/amazon.scss @@ -0,0 +1,10 @@ +// +// Crafting Guide - amazon.scss +// +// Copyright © 2014-2017 by Redwood Labs +// All rights reserved. +// + +.view__amazon { + +} diff --git a/src/client/site/item_page/item_page.jade b/src/client/site/item_page/item_page.jade index 6a2c1f45d..a23e6e29b 100644 --- a/src/client/site/item_page/item_page.jade +++ b/src/client/site/item_page/item_page.jade @@ -24,6 +24,8 @@ section.description.view__markdown_section + include ../common/amazon/amazon.jade + section.multiblock h2 Multiblock Construction .panel From 6d62375c46f8b572201f788e5a27afaf56240609 Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Sun, 18 Jun 2017 10:35:44 -0700 Subject: [PATCH 04/21] Add ad unit div for amazon ads --- src/client/site/common/amazon/amazon.jade | 1 + 1 file changed, 1 insertion(+) diff --git a/src/client/site/common/amazon/amazon.jade b/src/client/site/common/amazon/amazon.jade index c3ec7f43b..8b18a0437 100644 --- a/src/client/site/common/amazon/amazon.jade +++ b/src/client/site/common/amazon/amazon.jade @@ -5,4 +5,5 @@ //- All rights reserved. //- +#amzn_assoc_ad_div_adunit0_0 script(src="//z-na.amazon-adsystem.com/widgets/onejs?MarketPlace=US&adInstanceId=357573bb-98d8-4294-8cdf-4361dbf11cee") From 997ff114b4f549f30d7f70cf480dbb3ece1e847f Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Fri, 23 Jun 2017 19:38:47 -0700 Subject: [PATCH 05/21] Move Amazon ad block lower on the page --- src/client/site/item_page/item_page.jade | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/site/item_page/item_page.jade b/src/client/site/item_page/item_page.jade index a23e6e29b..906d9ec96 100644 --- a/src/client/site/item_page/item_page.jade +++ b/src/client/site/item_page/item_page.jade @@ -24,8 +24,6 @@ section.description.view__markdown_section - include ../common/amazon/amazon.jade - section.multiblock h2 Multiblock Construction .panel @@ -39,6 +37,8 @@ h2 Videos .panel + include ../common/amazon/amazon.jade + section.view__item_group.usedToMake section.view__item_group.usedAsToolToMake From 20119cf8e4f679363d992c03709fb855d9970e14 Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Sat, 1 Jul 2017 18:04:38 -0700 Subject: [PATCH 06/21] Initial effort to convert craft page to new models --- src/client/models/site/craft_page.coffee | 104 ++++++++++---- src/client/models/site/item_display.coffee | 4 + src/client/models/site/item_page.coffee | 2 +- src/client/models/site/item_selector.coffee | 76 +++++----- src/client/site/base_controller.coffee | 3 +- .../crafting_grid_controller.coffee | 32 +++-- .../inventory/inventory_controller.coffee | 23 +-- .../element/element_controller.coffee | 71 ++++----- .../item_selector_controller.coffee | 92 ++++++------ .../common/recipe/recipe_controller.coffee | 50 +++---- .../site/common/slot/slot_controller.coffee | 37 ++--- .../site/common/stack/stack_controller.coffee | 9 +- src/client/site/craft_page/craft_page.jade | 2 +- .../craft_page/craft_page_controller.coffee | 135 +++++++++--------- .../craftsman_working_controller.coffee | 106 -------------- .../craft_page/step/step_controller.coffee | 27 ++-- .../working_panel.jade} | 0 .../working_panel.scss} | 0 .../working_panel_controller.coffee | 89 ++++++++++++ src/client/site/router.coffee | 3 +- 20 files changed, 459 insertions(+), 406 deletions(-) delete mode 100644 src/client/site/craft_page/craftsman_working/craftsman_working_controller.coffee rename src/client/site/craft_page/{craftsman_working/craftsman_working.jade => working_panel/working_panel.jade} (100%) rename src/client/site/craft_page/{craftsman_working/craftsman_working.scss => working_panel/working_panel.scss} (100%) create mode 100644 src/client/site/craft_page/working_panel/working_panel_controller.coffee diff --git a/src/client/models/site/craft_page.coffee b/src/client/models/site/craft_page.coffee index 4f2325d41..087b98f0d 100644 --- a/src/client/models/site/craft_page.coffee +++ b/src/client/models/site/craft_page.coffee @@ -5,45 +5,89 @@ # All rights reserved. # -CraftingGuideCommon = require "crafting-guide-common" - -{BaseModel} = CraftingGuideCommon.deprecated -{Craftsman} = CraftingGuideCommon.deprecated.crafting -{Inventory} = CraftingGuideCommon.deprecated.game -{ModPack} = CraftingGuideCommon.deprecated.game +{Inventory} = require("crafting-guide-common").models +{Observable} = require("crafting-guide-common").util +{PlanBuilder} = require("crafting-guide-common").crafting +{ResourcesEvaluator} = require("crafting-guide-common").crafting +{StepsEvaluator} = require("crafting-guide-common").crafting ######################################################################################################################## -module.exports = class CraftPage extends BaseModel +module.exports = class CraftPage extends Observable - constructor: (attributes={}, options={})-> - if not attributes.modPack then throw new Error 'attributes.modPack is required' - attributes.params ?= null - attributes.craftsman ?= new Craftsman attributes.modPack - super attributes, options + constructor: (attributes={})-> + super - @modPack.on c.event.change, => @_consumeParams() - @on c.event.change + ':params', => @_consumeParams() - @craftsman.on c.event.change + ':stage', => @trigger c.event.change, this - @craftsman.on c.event.change + ':complete', => @trigger c.event.change, this + @muted -> @modPack = attributes.modPack + + @_currentPlan = null + @_have = new Inventory + @_planBuilder = new PlanBuilder new StepsEvaluator + @_want = new Inventory + + @_consumeParams attributes.params + + @_have.on Observable::ANY, this, "_onHaveChanged" + @_want.on Observable::ANY, this, "_onWantChanged" + + # Properties ################################################################################### + + Object.defineProperties @prototype, + + currentPlan: + get: -> return @_currentPlan + set: -> throw new Error "currentPlan cannot be assigned" + + have: + get: -> return @_have + set: -> throw new "have cannot be assigned" + + isDirty: + get: -> return @_isDirty + set: -> throw new Error "isDirty cannot be assigned" + + isOutdated: + get: -> return @currentPlan? and @isDirty + set: -> throw new Error "isOutdated cannot be assigned" + + modPack: + get: -> return @_modPack + set: (modPack)-> + if @_modPack? then throw new Error "modPack cannot be reassigned" + if not modPack? then throw new Error "modPack is required" + @_modPack = modPack + + planBuilder: + get: -> return @_planBuilder + set: -> throw new Error "planBuilder cannot be assigned" + + want: + get: -> return @_want + set: -> throw new Error "want cannot be assigned" + + # Public Methods ############################################################################### + + createPlan: -> + newPlan = @_planBuilder.createPlan @_want, @_have + @triggerPropertyChange "currentPlan", @_currentPlan, newPlan, -> + @_currentPlan = newPlan + @triggerPropertyChange "isDirty", @_isDirty, false # Private Methods ############################################################################## - _consumeParams: -> - return unless @params? + _consumeParams: (params)-> + return unless params?.inventoryText? - @craftsman.want.clear() - if not @params.inventoryText? - @params = null - else - inventory = new Inventory - inventory.parse @params.inventoryText + newWant = Inventory.fromUrlString params.inventoryText, @modPack + @_want.clear() - inventory.each (stack)=> - item = @modPack.findItem stack.itemSlug, enableAsNeeded:true - return unless item? and item.isCraftable + for itemId, stack of newWant.stacks + continue unless stack.item.isCraftable + @_want.add stack.item, stack.quantity - @craftsman.want.add stack.itemSlug, stack.quantity - inventory.remove stack.itemSlug + _onHaveChanged: -> + @triggerPropertyChange "isDirty", @_isDirty, true - if inventory.isEmpty then @params = null + _onWantChanged: -> + @triggerPropertyChange "isDirty", @_isDirty, true, -> + if @want.isEmpty then @triggerPropertyChange "currentPlan", @_currentPlan, null diff --git a/src/client/models/site/item_display.coffee b/src/client/models/site/item_display.coffee index a42b12cb6..ac789c463 100644 --- a/src/client/models/site/item_display.coffee +++ b/src/client/models/site/item_display.coffee @@ -37,6 +37,10 @@ module.exports = class ItemDisplay if not item? then throw new Error "item is required" @_item = item + mod: + get: -> return @_item.mod + set: -> throw new Error "mod cannot be assigned" + modUrl: get: -> return c.url.mod modId:@item.mod.id set: -> throw new Error "modUrl cannot be assigned" diff --git a/src/client/models/site/item_page.coffee b/src/client/models/site/item_page.coffee index 92b1388cf..f7caffe7e 100644 --- a/src/client/models/site/item_page.coffee +++ b/src/client/models/site/item_page.coffee @@ -6,7 +6,7 @@ # {Item} = require("crafting-guide-common").models -ItemDisplay = require "../item_display" +ItemDisplay = require "./item_display" {Observable} = require("crafting-guide-common").util ######################################################################################################################## diff --git a/src/client/models/site/item_selector.coffee b/src/client/models/site/item_selector.coffee index 2c4f8beb9..00c07a1a2 100644 --- a/src/client/models/site/item_selector.coffee +++ b/src/client/models/site/item_selector.coffee @@ -5,52 +5,49 @@ # All rights reserved. # -{BaseModel} = require('crafting-guide-common').deprecated -{ItemSlug} = require('crafting-guide-common').deprecated.game +{Observable} = require("crafting-guide-common").util ######################################################################################################################## -module.exports = class ItemSelector extends BaseModel +module.exports = class ItemSelector extends Observable - constructor: (attributes={}, options={})-> - if not options.modPack? then throw new Error 'options.modPack is required' - options.isAcceptable ?= (item)-> return true # accept everything by default - super attributes, options + constructor: (modPack, options={})-> + super - @_isAcceptable = options.isAcceptable + @_isAcceptable = options.isAcceptable or (item)-> return true # accept everything by default @_maxResults = 100 @_minHintLength = 3 - @_modPack = options.modPack @_results = [] + @modPack = modPack + # Property Methods ############################################################################# Object.defineProperties @prototype, hint: - get: -> - return @_hint + get: -> return @_hint + set: (hint)-> + @triggerPropertyChange "hint", @_hint, hint, -> + @_hint = hint?.toLowerCase() + @_refreshResults() - set: (newHint)-> - oldHint = @_hint - return if newHint is oldHint - - @_hint = newHint.toLowerCase() - - @trigger c.event.change + ':hint', this, oldHint, newHint - @_refreshResults() - @trigger c.event.change, this + modPack: + get: -> return @_modPack + set: (modPack)-> + if not modPack? then throw new Error "modPack is required" + if @_modPack? then throw new Error "modPack cannot be reassigned" + @_modPack = modPack results: - get: -> - return @_results + get: -> return @_results # Private Methods ############################################################################## - _computeScore: (name, itemSlug)-> + _computeScore: (item)-> hintIndex = 0 hintLetter = @_hint[hintIndex] - name = name.toLowerCase() + name = item.displayName.toLowerCase() nextScore = 1 totalScore = 0 @@ -60,8 +57,6 @@ module.exports = class ItemSelector extends BaseModel nextScore += 1 hintIndex += 1 if hintIndex is @_hint.length - item = @_modPack.findItem itemSlug - return 0 unless item? return 0 unless @_isAcceptable item break @@ -75,29 +70,34 @@ module.exports = class ItemSelector extends BaseModel return totalScore _refreshResults: -> - oldResults = @_results scoredItems = [] count = 0 - logger.verbose => "Looking for items which match: #{@_hint}" if @_hint.length >= @_minHintLength - @_modPack.eachMod (mod)=> + for modId, mod of @_modPack.mods return if count >= @_maxResults - return unless mod.enabled + return unless mod.isEnabled - mod.eachName (name, itemSlug)=> + for itemId, item of mod.items return if scoredItems.length >= @_maxResults - return unless itemSlug.isQualified - score = @_computeScore name, itemSlug + score = @_computeScore item if score >= @_hint.length - scoredItems.push score:score, itemSlug:itemSlug + scoredItems.push score:score, item:item scoredItems.sort (a, b)-> if a.score isnt b.score return if a.score > b.score then -1 else +1 - return ItemSlug.compare a.itemSlug, b.itemSlug - newResults = (e.itemSlug for e in scoredItems) - @_results = newResults - @trigger c.event.change + ':results', this, oldResults, newResults + nameA = a.item.displayName + nameB = b.item.displayName + if nameA.length isnt nameB.length + return if nameA.length < nameB.length then -1 else +1 + + if nameA isnt nameB + return if nameA < nameB then -1 else +1 + + return 0 + + @_results = (e.item for e in scoredItems) + @trigger c.event.change + ':results', this diff --git a/src/client/site/base_controller.coffee b/src/client/site/base_controller.coffee index c4fcff5ed..31b43ac61 100644 --- a/src/client/site/base_controller.coffee +++ b/src/client/site/base_controller.coffee @@ -112,7 +112,7 @@ module.exports = class BaseController extends Backbone.View newModel = @onWillChangeModel @_model, newModel @_model = newModel - @tryRefresh() + @onDidModelChange() rendered: get: -> @_rendered @@ -149,6 +149,7 @@ module.exports = class BaseController extends Backbone.View @$el.data $renderedEl.data() @delegateEvents() + @$el.controller = this @_rendered = true @onDidRender() diff --git a/src/client/site/common/crafting_grid/crafting_grid_controller.coffee b/src/client/site/common/crafting_grid/crafting_grid_controller.coffee index ab87389b9..53a22709c 100644 --- a/src/client/site/common/crafting_grid/crafting_grid_controller.coffee +++ b/src/client/site/common/crafting_grid/crafting_grid_controller.coffee @@ -5,39 +5,47 @@ # All rights reserved. # -BaseController = require '../../base_controller' -SlotController = require '../slot/slot_controller' +BaseController = require "../../base_controller" +{Recipe} = require("crafting-guide-common").models +SlotController = require "../slot/slot_controller" ######################################################################################################################## module.exports = class CraftingGridController 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.model should be a recipe - options.templateName = 'common/crafting_grid' + 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 = "common/crafting_grid" super options @_imageLoader = options.imageLoader @_modPack = options.modPack @_router = options.router - @_modPack.on c.event.change, => @tryRefresh() - # BaseController Methods ####################################################################### + onWillChangeModel: (oldModel, newModel)-> + if newModel? and (newModel.constructor isnt Recipe) then throw new Error "options.model must be a Recipe" + super + onDidRender: -> @_slotControllers = [] - for el in @$('.view__slot') + for el in @$(".view__slot") controller = new SlotController el:el, imageLoader:@_imageLoader, modPack:@_modPack, router:@_router controller.render() @_slotControllers.push controller super refresh: -> - for controller, index in @_slotControllers - controller.model = @model?.getStackAtSlot(index) + index = 0 + for y in [0..2] + for x in [0..2] + controller = @_slotControllers[index++] + if @model? + controller.model = @model.getInputAt x, y + else + controller.model = null super diff --git a/src/client/site/common/inventory/inventory_controller.coffee b/src/client/site/common/inventory/inventory_controller.coffee index 9e2e4fe11..315e87d43 100644 --- a/src/client/site/common/inventory/inventory_controller.coffee +++ b/src/client/site/common/inventory/inventory_controller.coffee @@ -47,8 +47,6 @@ module.exports = class InventoryController extends BaseController @_stackControllers = [] - @listenTo @_modPack, c.event.change, => @tryRefresh() - # Event Methods ################################################################################ onClearButtonClicked: -> @@ -61,31 +59,33 @@ module.exports = class InventoryController extends BaseController @trigger c.event.change, this onFirstButtonClicked: (stackController)-> - tracker.trackEvent @_trackingContext, 'remove-from', "#{stackController?.model?.itemSlug}" - @trigger c.event.button.first, this, stackController?.model?.itemSlug + itemId = stackController.model?.item.id + tracker.trackEvent @_trackingContext, 'remove-from', itemId + @trigger c.event.button.first, this, itemId onItemSelectorButtonClicked: -> return unless @model? tracker.trackEvent @_trackingContext, 'launch-add-to' @_selector.launch() - .then (itemSlug)=> - if not itemSlug? + .then (item)=> + if not item? tracker.trackEvent @_trackingContext, 'cancel-add-to' return - tracker.trackEvent @_trackingContext, 'complete-add-to', "#{itemSlug}" - @model.add itemSlug, 1 - @trigger c.event.add, this, itemSlug + tracker.trackEvent @_trackingContext, 'complete-add-to', "#{item.id}" + @model.add item, 1 + @trigger c.event.add, this, item.id @trigger c.event.change, this onSecondButtonClicked: (stackController)-> + itemId = stackController.model?.item.id @trigger c.event.button.second, this, stackController?.model?.itemSlug # BaseController Overrides ##################################################################### onDidRender: -> - @_selector = @addChild ItemSelectorController, null, isAcceptable: @_isAcceptable, modPack: @_modPack + @_selector = @addChild ItemSelectorController, null, isAcceptable:@_isAcceptable, modPack:@_modPack @$clearButton = @$('.button.clear') @$emptyPlaceholder = @$('.empty_placeholder') @@ -131,7 +131,7 @@ module.exports = class InventoryController extends BaseController index = 0 if @model? - @model.each (stack)=> + for itemId, stack of @model.stacks controller = @_stackControllers[index] if not controller? controller = new StackController @@ -153,6 +153,7 @@ module.exports = class InventoryController extends BaseController @$itemContainer.append controller.$el else controller.model = stack + index += 1 while @_stackControllers.length > index diff --git a/src/client/site/common/item_selector/element/element_controller.coffee b/src/client/site/common/item_selector/element/element_controller.coffee index c1ccbe108..38dd56d6c 100644 --- a/src/client/site/common/item_selector/element/element_controller.coffee +++ b/src/client/site/common/item_selector/element/element_controller.coffee @@ -5,58 +5,63 @@ # All rights reserved. # -BaseController = require '../../../base_controller' +BaseController = require "../../../base_controller" +ItemDisplay = require "../../../../models/site/item_display" ######################################################################################################################## module.exports = class ElementController extends BaseController constructor: (options={})-> - if not options.model? then throw new Error 'options.model is required' - options.onClicked ?= (controller)-> # do nothing - options.onSelected ?= (controller)-> # do nothing - options.templateName = 'common/item_selector/element' + if not options.model? then throw new Error "options.model is required" + options.templateName = "common/item_selector/element" options.useAnimations = false super options - @onClicked = options.onClicked - @onSelected = options.onSelected + @onClicked = options.onClicked or (controller)-> # do nothing + @onSelected = options.onSelected or (controller)-> # do nothing # Property Methods ############################################################################# - isSelected: -> - return @_selected - - setSelected: (newSelected)-> - oldSelected = @_selected - return if newSelected is oldSelected - - @_selected = newSelected - @tryRefresh() - - @trigger c.event.change + ':selected', this, oldSelected, newSelected - @trigger c.event.change, this - Object.defineProperties @prototype, - selected: {get:@prototype.isSelected, set:@prototype.setSelected} + + display: + get: -> return @_display ?= new ItemDisplay @model + set: -> throw new Error "display cannot be assigned" + + isSelected: + get: -> return @_selected + set: (newSelected)-> + oldSelected = @_selected + return if newSelected is oldSelected + + @_selected = newSelected + @tryRefresh() + + @trigger c.event.change + ":selected", this, oldSelected, newSelected + @trigger c.event.change, this # BaseController Overrides ##################################################################### + onDidModelChange: -> + @_display = null + super + onDidRender: -> - @$icon = @$('img') - @$name = @$('.name') - @$modName = @$('.modName') + @$icon = @$("img") + @$name = @$(".name") + @$modName = @$(".modName") super refresh: -> - @$icon.attr 'src', @model.iconUrl - @$name.html @model.itemName - @$modName.html @model.modName + @$icon.attr "src", @display.iconUrl + @$name.html @model.displayName + @$modName.html @model.mod.displayName if @_selected - @$el.addClass 'selected' + @$el.addClass "selected" else - @$el.removeClass 'selected' + @$el.removeClass "selected" super @@ -64,15 +69,15 @@ module.exports = class ElementController extends BaseController events: -> return _.extend super, - 'click': '_onClick' - 'mouseenter': '_onMouseEnter' + "click": "_onClick" + "mouseenter": "_onMouseEnter" # Private Methods ############################################################################## _onClick: (event)-> - event.preventDefault() @onClicked this + return false _onMouseEnter: (event)-> - event.preventDefault() @onSelected this + return false diff --git a/src/client/site/common/item_selector/item_selector_controller.coffee b/src/client/site/common/item_selector/item_selector_controller.coffee index 33c634a7a..25f70433d 100644 --- a/src/client/site/common/item_selector/item_selector_controller.coffee +++ b/src/client/site/common/item_selector/item_selector_controller.coffee @@ -5,21 +5,22 @@ # All rights reserved. # -BaseController = require '../../base_controller' -ItemSelector = require '../../../models/site/item_selector' -ElementController = require './element/element_controller' +BaseController = require "../../base_controller" +ItemDisplay = require "../../../models/site/item_display" +ItemSelector = require "../../../models/site/item_selector" +ElementController = require "./element/element_controller" w = require "when" ######################################################################################################################## module.exports = class ItemSelectorController extends BaseController - constructor: (options)-> - if not options.modPack? then throw new Error 'options.modPack is required' + constructor: (options={})-> + if not options.modPack? then throw new Error "options.modPack is required" options.isAcceptable ?= null - options.model ?= new ItemSelector {}, modPack:options.modPack, isAcceptable:options.isAcceptable + options.model ?= new ItemSelector options.modPack, isAcceptable:options.isAcceptable options.onChoseItem ?= (item)-> # do nothing - options.templateName = 'common/item_selector' + options.templateName = "common/item_selector" super options @_modPack = options.modPack @@ -29,25 +30,25 @@ module.exports = class ItemSelectorController extends BaseController # Public Methods ############################################################################### - launch: (hint='')-> + launch: (hint="")-> @model.hint = hint if @rendered then @refresh() @_disableWindowScrolling() - @$page.addClass 'blur' + @$page.addClass "blur" @$screen.append @$popup - @$screen.css 'display', '' + @$screen.css "display", "" @$popup.off c.event.click @$popup.on c.event.click, (event)=> @onPopupClicked(event) - @$hintField.off 'keyup input' - @$hintField.on 'keyup', (event)=> @onHintKeyPress(event) - @$hintField.on 'input', (event)=> @onHintChanged(event) + @$hintField.off "keyup input" + @$hintField.on "keyup", (event)=> @onHintKeyPress(event) + @$hintField.on "input", (event)=> @onHintChanged(event) @$hintField.focus() - @$closeButton.one 'click', (event)=> @_close() + @$closeButton.one "click", (event)=> @_close() @$screen.one c.event.click, (event)=> @onScreenClicked(event) @@ -85,17 +86,17 @@ module.exports = class ItemSelectorController extends BaseController return false onResultClicked: (controller)-> - @_session.resolve controller.model.slug + @_session.resolve controller.model @_session = null @_close() return false onResultSelected: (controller)-> for c in @_elementControllers - c.selected = false + c.isSelected = false if controller? - controller.selected = true + controller.isSelected = true return false @@ -106,14 +107,14 @@ module.exports = class ItemSelectorController extends BaseController # BaseController Overrides ##################################################################### onDidRender: -> - @$page = $('.page') # find the shared, global page - @$screen = $('.view__screen') # find the shared, global screen + @$page = $(".page") # find the shared, global page + @$screen = $(".view__screen") # find the shared, global screen - @$closeButton = @$('img.close') - @$popup = @$('.view__item_selector_popup') - @$hintField = @$('.view__item_selector_popup input') - @$searchInput = @$('.search input') - @$resultsContainer = @$('.results') + @$closeButton = @$("img.close") + @$popup = @$(".view__item_selector_popup") + @$hintField = @$(".view__item_selector_popup input") + @$searchInput = @$(".search input") + @$resultsContainer = @$(".results") @$popup.detach() super @@ -127,16 +128,16 @@ module.exports = class ItemSelectorController extends BaseController _chooseSelected: -> for controller in @_elementControllers - if controller.selected + if controller.isSelected @onResultClicked controller return _close: -> @_enableWindowScrolling() - @$page.removeClass 'blur' - @$screen.css 'display', 'none' + @$page.removeClass "blur" + @$screen.css "display", "none" @$popup.detach() - @model.hint = '' + @model.hint = "" if @_session @_session.resolve null @@ -144,28 +145,27 @@ module.exports = class ItemSelectorController extends BaseController _disableWindowScrolling: -> @_windowScrollPosition = $(window).scrollTop() - $('body').addClass('scrollDisabled').css('margin-top', -@_windowScrollPosition) + $("body").addClass("scrollDisabled").css("margin-top", -@_windowScrollPosition) _enableWindowScrolling: -> - $('body').removeClass('scrollDisabled').css('margin-top', 0) + $("body").removeClass("scrollDisabled").css("margin-top", 0) $(window).scrollTop @_windowScrollPosition _refreshResults: -> index = 0 - for itemSlug in @model.results - displayModel = @_modPack.findItemDisplay itemSlug + for item in @model.results controller = @_elementControllers[index] if not controller? controller = new ElementController - model: displayModel + model: item onClicked: (c)=> @onResultClicked(c) onSelected: (c)=> @onResultSelected(c) controller.render show:false @_elementControllers[index] = controller @$resultsContainer.append controller.$el else - controller.model = displayModel + controller.model = item controller.show() index += 1 @@ -180,14 +180,17 @@ module.exports = class ItemSelectorController extends BaseController controller = @_elementControllers[i] nextController = @_elementControllers[i + 1] - if controller.selected - controller.selected = false - nextController.selected = true + if controller.isSelected + controller.isSelected = false + nextController.isSelected = true @_showElement nextController.$el return + [..., controller] = @_elementControllers + controller.isSelected = false + controller = @_elementControllers[0] - controller.selected = true + controller.isSelected = true @_showElement controller.$el _selectPrevious: -> @@ -197,14 +200,17 @@ module.exports = class ItemSelectorController extends BaseController previousController = @_elementControllers[i - 1] controller = @_elementControllers[i] - if controller.selected - previousController.selected = true - controller.selected = false + if controller.isSelected + previousController.isSelected = true + controller.isSelected = false @_showElement previousController.$el return - controller = @_elementControllers[@_elementControllers.length - 1] - controller.selected = true + controller = @_elementControllers[0] + controller.isSelected = false + + [..., controller] = @_elementControllers + controller.isSelected = true @_showElement controller.$el _showElement: ($el)-> diff --git a/src/client/site/common/recipe/recipe_controller.coffee b/src/client/site/common/recipe/recipe_controller.coffee index 9089af172..0d851b546 100644 --- a/src/client/site/common/recipe/recipe_controller.coffee +++ b/src/client/site/common/recipe/recipe_controller.coffee @@ -5,20 +5,21 @@ # All rights reserved. # -BaseController = require '../../base_controller' -CraftingGridController = require '../crafting_grid/crafting_grid_controller' -SlotController = require '../slot/slot_controller' -{StringBuilder} = require('crafting-guide-common').util +BaseController = require "../../base_controller" +CraftingGridController = require "../crafting_grid/crafting_grid_controller" +ItemDisplay = require "../../../models/site/item_display" +SlotController = require "../slot/slot_controller" +{StringBuilder} = require("crafting-guide-common").util ######################################################################################################################## module.exports = class RecipeController 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 = 'common/recipe' + 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 = "common/recipe" super options @_imageLoader = options.imageLoader @@ -29,26 +30,26 @@ module.exports = class RecipeController extends BaseController # BaseController Overrides ##################################################################### onDidRender: -> - @_gridController = @addChild CraftingGridController, '.view__crafting_grid', + @_gridController = @addChild CraftingGridController, ".view__crafting_grid", modPack: @_modPack imageLoader: @_imageLoader router: @_router - @_outputSlotController = @addChild SlotController, '.output .view__slot', + @_outputSlotController = @addChild SlotController, ".output .view__slot", imageLoader: @_imageLoader modPack: @_modPack router: @_router - @$multiplier = @$('.multiplier') - @$outputImg = @$('.output img') - @$outputLink = @$('.output a') - @$outputQuantity = @$('.quantity') - @$toolContainer = @$('.tool') + @$multiplier = @$(".multiplier") + @$outputImg = @$(".output img") + @$outputLink = @$(".output a") + @$outputQuantity = @$(".quantity") + @$toolContainer = @$(".tool") super refresh: -> @_gridController.model = @model - @_outputSlotController.model = @model?.output?[0] + @_outputSlotController.model = @model?.output @_refreshMultiplier() @_refreshTools() @@ -69,14 +70,14 @@ module.exports = class RecipeController extends BaseController @_multiplier = newMultiplier @_refreshMultiplier() - @trigger Event.change + ':multiplier', this, oldMultiplier, newMultiplier + @trigger Event.change + ":multiplier", this, oldMultiplier, newMultiplier @trigger Event.change, this # Backbone.View Methods ######################################################################## events: -> return _.extend super, - 'click a': 'routeLinkClick' + "click a": "routeLinkClick" # Private Methods ############################################################################## @@ -84,14 +85,15 @@ module.exports = class RecipeController extends BaseController if @multiplier > 1 @$multiplier.html "x#{@multiplier}" else - @$multiplier.html '' + @$multiplier.html "" _refreshTools: -> @$toolContainer.empty() return unless @model? - builder = new StringBuilder - builder.loop @model.tools, delimiter:', ', onEach:(b, stack)=> - display = @_modPack.findItemDisplay stack.itemSlug - b.push "#{display.itemName}" - @$toolContainer.html builder.toString() + toolLinks = [] + for itemId, item of @model.tools + display = new ItemDisplay item + toolLinks.push "#{display.name}" + + @$toolContainer.html toolLinks.join ", " diff --git a/src/client/site/common/slot/slot_controller.coffee b/src/client/site/common/slot/slot_controller.coffee index ecde0b23d..a5f710f25 100644 --- a/src/client/site/common/slot/slot_controller.coffee +++ b/src/client/site/common/slot/slot_controller.coffee @@ -5,18 +5,19 @@ # All rights reserved. # -BaseController = require '../../base_controller' +BaseController = require "../../base_controller" +ItemDisplay = require "../../../models/site/item_display" +{Stack} = require("crafting-guide-common").models ######################################################################################################################## module.exports = class SlotController 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.model should be a Stack - options.templateName = 'common/slot' + 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 = "common/slot" options.useAnimations = false super options @@ -27,27 +28,31 @@ module.exports = class SlotController extends BaseController # BaseController Overrides ##################################################################### onDidRender: -> - @$link = @$('a') - @$image = @$('img') - @$quantity = @$('.quantity') + @$link = @$("a") + @$image = @$("img") + @$quantity = @$(".quantity") + super + + onWillChangeModel: (oldModel, newModel)-> + if newModel? and (newModel.constructor isnt Stack) then throw new Error "newModel must be a Stack" super refresh: -> if @model? - display = @_modPack.findItemDisplay @model.itemSlug - @$link.attr 'href', display.itemUrl + display = new ItemDisplay @model.item + @$link.attr "href", display.url @_imageLoader.load display.iconUrl, @$image if @model.quantity > 1 @$quantity.html @model.quantity else - @$quantity.html '' + @$quantity.html "" else - @$link.removeAttr 'href' - @$quantity.html '' + @$link.removeAttr "href" + @$quantity.html "" - @$image.attr 'src', '/images/empty.png' + @$image.attr "src", "/images/empty.png" super @@ -55,4 +60,4 @@ module.exports = class SlotController extends BaseController events: -> return _.extend super, - 'click a': 'routeLinkClick' + "click a": "routeLinkClick" diff --git a/src/client/site/common/stack/stack_controller.coffee b/src/client/site/common/stack/stack_controller.coffee index 4e939ec36..7c8825877 100644 --- a/src/client/site/common/stack/stack_controller.coffee +++ b/src/client/site/common/stack/stack_controller.coffee @@ -6,6 +6,7 @@ # BaseController = require '../../base_controller' +ItemDisplay = require "../../../models/site/item_display" ######################################################################################################################## @@ -38,8 +39,6 @@ module.exports = class StackController extends BaseController @_shouldEnableButton = options.shouldEnableButton ?= (model, button)-> true @_trackingContext = options.trackingContext ?= null - @_modPack.on c.event.change, => @tryRefresh() - # Event Methods ################################################################################ onFirstButtonClicked: (event)-> @@ -71,7 +70,7 @@ module.exports = class StackController extends BaseController @trigger c.event.change + ':quantity', this, oldQuantity, newQuantity @trigger c.event.change, this - tracker.trackEvent @_trackingContext, 'update-quantity', @model.itemSlug, @model.quantity + tracker.trackEvent @_trackingContext, 'update-quantity', @model.item.id, @model.quantity onQuantityFieldChanged: -> return unless @_editable @@ -119,10 +118,10 @@ module.exports = class StackController extends BaseController refresh: -> if not @model? then throw new Error "must have a model to render" - display = @_modPack.findItemDisplay @model.itemSlug + display = new ItemDisplay @model.item @_imageLoader.load display.iconUrl, @$image - @$nameLink.html display.itemName + @$nameLink.html display.name @$nameLink.attr 'href', display.itemUrl quantityText = if @model.quantity > 10000 then "#{@model.quantity / 1000}k" else "#{@model.quantity}" diff --git a/src/client/site/craft_page/craft_page.jade b/src/client/site/craft_page/craft_page.jade index bcafb4bcf..32d51aec6 100644 --- a/src/client/site/craft_page/craft_page.jade +++ b/src/client/site/craft_page/craft_page.jade @@ -53,4 +53,4 @@ h2 Steps .panel - section.view__craftsman_working + section.view__working_panel diff --git a/src/client/site/craft_page/craft_page_controller.coffee b/src/client/site/craft_page/craft_page_controller.coffee index 48467c18c..1abc722c0 100644 --- a/src/client/site/craft_page/craft_page_controller.coffee +++ b/src/client/site/craft_page/craft_page_controller.coffee @@ -5,14 +5,13 @@ # All rights reserved. # -BaseController = require '../base_controller' -CraftPage = require '../../models/site/craft_page' -{Craftsman} = require('crafting-guide-common').deprecated.crafting -CraftsmanWorkingController = require './craftsman_working/craftsman_working_controller' -InventoryController = require '../common/inventory/inventory_controller' -PageController = require '../page_controller' -{SimpleInventory} = require('crafting-guide-common').deprecated.crafting -StepController = require './step/step_controller' +CraftPage = require "../../models/site/craft_page" +WorkingPanelController = require "./working_panel/working_panel_controller" +{Inventory} = require("crafting-guide-common").models +InventoryController = require "../common/inventory/inventory_controller" +{Observable} = require("crafting-guide-common").util +PageController = require "../page_controller" +StepController = require "./step/step_controller" ######################################################################################################################## @@ -21,12 +20,12 @@ module.exports = class CraftPageController extends PageController @::SCROLL_BUFFER = 8 # px 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' - if not options.storage? then throw new Error 'options.storage 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" + if not options.storage? then throw new Error "options.storage is required" - options.model ?= new CraftPage modPack:options.modPack + options.model ?= new CraftPage modPack:options.modPack, params:options.params options.templateName = 'craft_page' super options @@ -35,41 +34,46 @@ module.exports = class CraftPageController extends PageController @_router = options.router @_storage = options.storage + @model.have.on Observable::ANY, this, "onHaveInventoryChanged" + @model.want.on Observable::ANY, this, "onWantInventoryChanged" + # Event Methods ################################################################################ onHaveInventoryChanged: -> - @_storage.store 'crafting-plan:have', @model.craftsman.have.unparse() + @_storage.store 'crafting-plan:have', @model.have.toUrlString() - onMoveNeedToHave: (itemSlug)-> - quantity = @_needInventoryController.model.quantityOf itemSlug - @model.craftsman.have.add itemSlug, quantity + onMoveNeedToHave: (itemId)-> + quantity = @_needInventoryController.model.getQuantity itemId + item = @_modPack.findItem itemId + @model.have.add item, quantity - onRemoveFromHaveInventory: (itemSlug)-> - @model.craftsman.have.remove itemSlug + onRemoveFromHave: (itemId)-> + @model.have.remove itemId - onRemoveFromWant: (itemSlug)-> - @model.craftsman.want.remove itemSlug + onRemoveFromWant: (itemId)-> + @model.want.remove itemId @onWantInventoryChanged() onSampleClicked: (event)-> $el = $(event.target) while $el.length > 0 - inventoryText = $el.attr 'data-slug' + inventoryText = $el.attr "data-slug" break if inventoryText $el = $el.parent() if inventoryText? - tracker.trackEvent c.tracking.category.craft, 'add-sample', inventoryText - sampleInventory = new SimpleInventory - sampleInventory.parse inventoryText - @model.craftsman.want.addInventory sampleInventory - @_scrollTo @$workingSection - @onWantInventoryChanged() + try + tracker.trackEvent c.tracking.category.craft, "add-sample", inventoryText + sampleInventory = Inventory.fromUrlString inventoryText, @_modPack + @model.want.merge sampleInventory + @_scrollTo @$workingSection + catch e + logger.error e return false onWantInventoryChanged: -> - text = @model.craftsman.want.unparse() + text = @model.want.toUrlString() url = c.url.crafting inventoryText:text @router.navigate url @@ -79,7 +83,7 @@ module.exports = class CraftPageController extends PageController return c.text.craftDescription() getTitle: -> - description = @model.craftsman.want.toDescription() + description = @model.want.toDescription() return null unless description? return "Crafting Plan for #{description}" @@ -91,21 +95,19 @@ module.exports = class CraftPageController extends PageController imageLoader: @_imageLoader isAcceptable: (item)=> item.isCraftable modPack: @_modPack - model: @model.craftsman.want + model: @model.want router: @_router trackingContext: c.tracking.category.craftWant - @_wantInventoryController.on c.event.button.first, (c, s)=> @onRemoveFromWant(s) - @_wantInventoryController.on c.event.change, (c)=> @onWantInventoryChanged() + @_wantInventoryController.on c.event.button.first, (controller, itemId)=> @onRemoveFromWant itemId @_haveInventoryController = @addChild InventoryController, '.have .view__inventory', firstButtonType: 'down' imageLoader: @_imageLoader modPack: @_modPack - model: @model.craftsman.have + model: @model.have router: @_router trackingContext: c.tracking.category.craftHave - @_haveInventoryController.on c.event.button.first, (controller, itemSlug)=> - @onRemoveFromHaveInventory itemSlug + @_haveInventoryController.on c.event.button.first, (controller, itemId)=> @onRemoveFromHave itemId @_needInventoryController = @addChild InventoryController, '.need .view__inventory', editable: false @@ -115,11 +117,9 @@ module.exports = class CraftPageController extends PageController model: null router: @_router trackingContext: c.tracking.category.craftNeed - @_needInventoryController.on c.event.button.first, (c, s)=> @onMoveNeedToHave(s) + @_needInventoryController.on c.event.button.first, (controller, itemId)=> @onMoveNeedToHave itemId - @_workingSectionController = @addChild CraftsmanWorkingController, '.view__craftsman_working', - model: @model.craftsman - @_workingSectionController.on c.event.click, => @_scrollTo @$workingSection + @_workingPanelController = @addChild WorkingPanelController, '.view__working_panel', model:@model @$haveSection = @$('section.have') @$instructionsSection = @$('section.instructions') @@ -128,7 +128,7 @@ module.exports = class CraftPageController extends PageController @$stepsContainer = @$('section.steps .panel') @$stepsSection = @$('section.steps') @$toolsSection = @$('section.tools') - @$workingSection = @$('.view__craftsman_working') + @$workingSection = @$('.view__working_panel') if c.screen.type.compute() is c.screen.type.mobile @$('.view__inventory.large').removeClass 'large' @@ -136,20 +136,15 @@ module.exports = class CraftPageController extends PageController super onWillRender: -> - @model.craftsman.have.clear() - @model.craftsman.have.parse @_storage.load('crafting-plan:have') - @model.craftsman.have.on c.event.change, => @onHaveInventoryChanged() - - @model.craftsman.want.on c.event.change, => @refresh() - - @model.craftsman.on c.event.change + ":stage", => - return unless @model.craftsman.stage is Craftsman::STAGE.COMPLETE - @_scrollTo @$needSection + @model.have.clear() + @model.have.merge Inventory.fromUrlString @_storage.load('crafting-plan:have') + @model.have.on Observable::ANY, this, "onHaveInventoryChanged" + @model.want.on Observable::ANY, this, "tryRefresh" super refresh: -> - @_needInventoryController.model = @model.craftsman.plan?.need + @_needInventoryController.model = @model.currentPlan?.need @_refreshOutdated() @_refreshSectionVisibility() @_refreshSteps() @@ -165,33 +160,30 @@ module.exports = class CraftPageController extends PageController # Private Methods ################################################################################ _addTools: (controller)-> - controller.model.addToolsTo @model.craftsman.want + controller.model.addToolsTo @model.want _completeStep: (controller)-> - controller.markComplete @model.craftsman.have + controller.markComplete @model.have _isAddingToolsPossible: (controller)-> tools = controller.model.recipe.tools return false unless tools.length > 0 - have = @model.craftsman.have - want = @model.craftsman.want + have = @model.have + want = @model.want for stack in tools - return false if have.hasAtLeast stack.itemSlug - return false if want.hasAtLeast stack.itemSlug + return false if @model.have.contains stack.item.id + return false if @model.want.contains stack.item.id return true _isStepCompletable: (controller)-> - recipe = controller.model.recipe - for stack in recipe.output - return false if @model.craftsman.want.hasAtLeast stack.itemSlug - - return true + wantsOutput = @model.want.contains controller.model.recipe.output.item.id + return wantsOutput _refreshOutdated: -> - if @model.craftsman.stage is Craftsman::STAGE.OUTDATED + if @model.isOutdated @$el.addClass 'outdated' else @$el.removeClass 'outdated' @@ -205,22 +197,25 @@ module.exports = class CraftPageController extends PageController visibleSections = [] - if @model.craftsman.want.isEmpty + # TODO: Figure out what to do if the planner can't make a valid plan + # else if @model.craftsman.stage is Craftsman::STAGE.INVALID + # visibleSections.push el for el in [@$wantSection, @$haveSection, @$workingSection] + # TODO: Play around and see if the algo ever takes too long + # else if not @model.craftsman.complete + # visibleSections.push el for el in [@$wantSection, @$haveSection, @$workingSection] + + if @model.want.isEmpty visibleSections.push el for el in [@$instructionsSection, @$wantSection] - else if @model.craftsman.stage is Craftsman::STAGE.INVALID - visibleSections.push el for el in [@$wantSection, @$haveSection, @$workingSection] - else if not @model.craftsman.complete - visibleSections.push el for el in [@$wantSection, @$haveSection, @$workingSection] else visibleSections.push el for el in [@$haveSection, @$wantSection, @$workingSection] - if @model.craftsman.plan? + if @model.currentPlan? visibleSections.push el for el in [@$needSection, @$stepsSection] @hide $el for $el in allSections @show $el for $el in visibleSections _refreshSteps: -> - steps = @model.craftsman.plan?.steps or [] + steps = @model.currentPlan?.steps or [] @_stepControllers ?= [] index = 0 diff --git a/src/client/site/craft_page/craftsman_working/craftsman_working_controller.coffee b/src/client/site/craft_page/craftsman_working/craftsman_working_controller.coffee deleted file mode 100644 index f2e214538..000000000 --- a/src/client/site/craft_page/craftsman_working/craftsman_working_controller.coffee +++ /dev/null @@ -1,106 +0,0 @@ -# -# Crafting Guide - craftsman_working_controller.coffee -# -# Copyright © 2014-2017 by Redwood Labs -# All rights reserved. -# - -BaseController = require '../../base_controller' -{Craftsman} = require('crafting-guide-common').deprecated.crafting - -######################################################################################################################## - -module.exports = class CraftsmanWorkingController extends BaseController - - @::HIDE_TIMER_DURATION = 2000 - - constructor: (options={})-> - if not options.model then throw new Error 'options.model is required' - options.templateName = 'craft_page/craftsman_working' - super options - - @_hideTimer = null - - # Event Methods ################################################################################ - - onButtonClicked: -> - tracker.trackEvent c.tracking.category.craft, 'start' - @trigger c.event.click - @model.reset() - @model.work() - return false - - # BaseController Methods ####################################################################### - - onDidModelChange: -> - @refresh() - - onDidRender: -> - @$button = @$('.button') - @$count = @$('.count p') - @$message = @$('.message p') - @$outdated = @$('.outdated') - @$waiting = @$('.waiting') - - @_controls = [@$button, @$count, @$message, @$outdated, @$waiting] - super - - refresh: -> - return unless @$message? and @$count? - - button = count = message = outdated = waiting = null - - switch @model.stage - when Craftsman::STAGE.READY - message = 'Ready to compute crafting plan!' - count = 'Click "Calculate" to continue.' - button = true - when Craftsman::STAGE.GRAPHING - message = 'Researching recipes...' - count = "Found #{@model.stageCount} recipes so far..." - watiing = true - when Craftsman::STAGE.PLANNING - message = 'Figuring out possible crafting plans...' - count = "Found #{@model.stageCount} possibilities so far..." - watiing = true - when Craftsman::STAGE.ANALYZING - message = 'Looking for the best plan...' - count = "Finished checking #{@model.stageCount} so far..." - watiing = true - when Craftsman::STAGE.COMPLETE - message = 'Crafting plan is complete.' - when Craftsman::STAGE.INVALID - message = 'Couldn\'t make a crafting plan!' - count = 'Please report this problem using the Feedback box.' - when Craftsman::STAGE.OUTDATED - message = 'Your crafting plan is out of date!' - count = 'Click "Calculate" to re-compute.' - button = true - outdated = true - - @hide(control) for control in @_controls - - if button? - @show @$button - - if count? - @show @$count - @$count.html count - - if message? - @show @$message - @$message.html message - - if outdated? - @show @$outdated - - if waiting? - @show @$waiting - - super - - # Backbone.View Overrides ###################################################################### - - events: -> - return _.extend super, - 'click .button': 'onButtonClicked' diff --git a/src/client/site/craft_page/step/step_controller.coffee b/src/client/site/craft_page/step/step_controller.coffee index eef7e330e..f5d364860 100644 --- a/src/client/site/craft_page/step/step_controller.coffee +++ b/src/client/site/craft_page/step/step_controller.coffee @@ -6,16 +6,19 @@ # BaseController = require '../../base_controller' +{Inventory} = require("crafting-guide-common").models +{CraftingPlanStep} = require("crafting-guide-common").crafting InventoryController = require '../../common/inventory/inventory_controller' RecipeController = require '../../common/recipe/recipe_controller' -{SimpleInventory} = require('crafting-guide-common').deprecated.crafting + ######################################################################################################################## module.exports = class StepController extends BaseController constructor: (options={})-> - if not options.model? then throw new Error 'options.model is required' + if options.model?.constructor isnt CraftingPlanStep + throw new Error "options.model must be a CraftingPlanStep" if not options.modPack? then throw new Error 'options.modPack is required' if not options.imageLoader? then throw new Error 'options.imageLoader is required' options.templateName = 'craft_page/step' @@ -41,7 +44,7 @@ module.exports = class StepController extends BaseController onCompleteButtonClicked: (event)-> return if @$completeButton.hasClass 'disabled' - tracker.trackEvent c.tracking.category.craft, 'mark-complete', null, @model.number + tracker.trackEvent c.tracking.category.craft, 'mark-complete', null, @model.count @onComplete this onShowToolPlan: (event)-> @@ -54,7 +57,7 @@ module.exports = class StepController extends BaseController @inventoryController = @addChild InventoryController, '.view__inventory', editable: false imageLoader: @_imageLoader - model: @model.inventory + model: @model.inputInventory modPack: @_modPack router: @_router @@ -78,12 +81,11 @@ module.exports = class StepController extends BaseController return super refresh: -> - itemDisplay = @_modPack.findItemDisplay @model.recipe.output[0].itemSlug - @$header.html "#{@model.number}. #{itemDisplay.itemName}" + @$header.html "#{@model.number}. #{@model.recipe.output.item.displayName}" - @inventoryController.model = @model.inventory + @inventoryController.model = @model.inputInventory @recipeController.model = @model.recipe - @recipeController.multiplier = @model.multiplier + @recipeController.multiplier = @model.count @_refreshCompleteButton() @_refreshToolButton() @@ -100,12 +102,11 @@ module.exports = class StepController extends BaseController # Private Methods ############################################################################## _refreshToolButton: -> - inventory = new SimpleInventory {}, modPack:@_modPack - for toolStack in @model.recipe.tools - inventory.add toolStack.itemSlug, toolStack.quantity - inventory.localize() + inventory = new Inventory + for itemId, item in @model.recipe.tools + inventory.add item - inventoryText = inventory.unparse() + inventoryText = inventory.toUrlString() @$toolButton.attr 'href', "/craft/#{inventoryText}" @$toolButton.attr 'target', inventoryText diff --git a/src/client/site/craft_page/craftsman_working/craftsman_working.jade b/src/client/site/craft_page/working_panel/working_panel.jade similarity index 100% rename from src/client/site/craft_page/craftsman_working/craftsman_working.jade rename to src/client/site/craft_page/working_panel/working_panel.jade diff --git a/src/client/site/craft_page/craftsman_working/craftsman_working.scss b/src/client/site/craft_page/working_panel/working_panel.scss similarity index 100% rename from src/client/site/craft_page/craftsman_working/craftsman_working.scss rename to src/client/site/craft_page/working_panel/working_panel.scss diff --git a/src/client/site/craft_page/working_panel/working_panel_controller.coffee b/src/client/site/craft_page/working_panel/working_panel_controller.coffee new file mode 100644 index 000000000..06da9fa4a --- /dev/null +++ b/src/client/site/craft_page/working_panel/working_panel_controller.coffee @@ -0,0 +1,89 @@ +# +# Crafting Guide - working_panel_controller.coffee +# +# Copyright © 2014-2017 by Redwood Labs +# All rights reserved. +# + +BaseController = require '../../base_controller' +CraftPage = require "../../../models/site/craft_page" + +######################################################################################################################## + +module.exports = class WorkingPanelController extends BaseController + + @::HIDE_TIMER_DURATION = 2000 + + constructor: (options={})-> + if not options.model?.constructor is CraftPage then throw new Error "options.model must be a CraftPage" + options.templateName = "craft_page/working_panel" + super options + + @_hideTimer = null + + # Event Methods ################################################################################ + + onButtonClicked: -> + tracker.trackEvent c.tracking.category.craft, "start" + @trigger c.event.click + @model.createPlan() + return false + + # BaseController Methods ####################################################################### + + onDidModelChange: -> + @refresh() + + onDidRender: -> + @$button = @$('.button') + @$count = @$('.count p') + @$message = @$('.message p') + @$outdated = @$('.outdated') + @$waiting = @$('.waiting') + + @_controls = [@$button, @$count, @$message, @$outdated, @$waiting] + super + + refresh: -> + return unless @$message? and @$count? + + button = count = message = outdated = null + + if @model.isOutdated + message = "Your crafting plan is out of date!" + count = 'Click "Calculate" to re-compute.' + button = true + outdated = true + else if @model.currentPlan? + message = "Crafting plan is complete." + else + message = "Ready to compute crafting plan!" + count = 'Click "Calculate" to continue.' + button = true + + @hide(control) for control in @_controls + + if button? + @show @$button + + if count? + @show @$count + @$count.html count + + if message? + @show @$message + @$message.html message + + if outdated? + @show @$outdated + + if waiting? + @show @$waiting + + super + + # Backbone.View Overrides ###################################################################### + + events: -> + return _.extend super, + 'click .button': 'onButtonClicked' diff --git a/src/client/site/router.coffee b/src/client/site/router.coffee index b7624a57a..39783e41f 100644 --- a/src/client/site/router.coffee +++ b/src/client/site/router.coffee @@ -117,8 +117,7 @@ module.exports = class Router extends Backbone.Router @route__craft() route__craft: (text)-> - controller = new CraftPageController @_makeOptions {} - controller.model.params = inventoryText:text + controller = new CraftPageController @_makeOptions params:inventoryText:text @_siteController.setPage 'craft', controller route__login: -> From f6f736f8be7dc9dfc663972d7564c5ad1b9eef55 Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Tue, 4 Jul 2017 22:52:01 -0700 Subject: [PATCH 07/21] Update item detail page to new models --- src/client/models/site/item_display.coffee | 18 +++-- src/client/models/site/item_page.coffee | 5 +- .../markdown_section_controller.coffee | 5 +- .../site/common/stack/stack_controller.coffee | 2 +- .../site/header/header_controller.coffee | 13 ++-- .../item_page/item_page_controller.coffee | 67 ++++++------------- .../multiblock/multiblock_controller.coffee | 3 +- .../recipe_detail_controller.coffee | 53 ++++++++------- 8 files changed, 75 insertions(+), 91 deletions(-) diff --git a/src/client/models/site/item_display.coffee b/src/client/models/site/item_display.coffee index ac789c463..afa5a61db 100644 --- a/src/client/models/site/item_display.coffee +++ b/src/client/models/site/item_display.coffee @@ -24,10 +24,10 @@ module.exports = class ItemDisplay get: -> inventory = new Inventory inventory.add @item - c.url.crafting inventoryText:inventory.unparse() + c.url.crafting inventoryText:inventory.toUrlString() iconUrl: - get: -> return c.url.itemIcon modId:@_item.mod.id, itemSlug:@slug + get: -> return c.url.itemIcon this set: -> throw new Error "iconUrl cannot be assigned" item: @@ -37,10 +37,18 @@ module.exports = class ItemDisplay if not item? then throw new Error "item is required" @_item = item + itemSlug: + get: -> return _.slugify @name + set: -> throw new Error "slug cannot be assigned" + mod: get: -> return @_item.mod set: -> throw new Error "mod cannot be assigned" + modId: + get: -> return @_item.mod.id + set: -> throw new Error "modId cannot be assigned" + modUrl: get: -> return c.url.mod modId:@item.mod.id set: -> throw new Error "modUrl cannot be assigned" @@ -49,10 +57,6 @@ module.exports = class ItemDisplay get: -> return @item.displayName set: -> throw new Error "name cannot be assigned" - slug: - get: -> return _.slugify @name - set: -> throw new Error "slug cannot be assigned" - url: - get: -> return c.url.item modId:@_item.mod.id, itemSlug:@slug + get: -> return c.url.item this set: -> throw new Error "url cannot be assigned" diff --git a/src/client/models/site/item_page.coffee b/src/client/models/site/item_page.coffee index f7caffe7e..5bbd62b9f 100644 --- a/src/client/models/site/item_page.coffee +++ b/src/client/models/site/item_page.coffee @@ -46,6 +46,9 @@ module.exports = class ItemPage extends Observable return @_findItemsWithMatchingRecipes (recipe)=> recipe.computeQuantityRequired @item + findRecipes: -> + return (recipe for recipeId, recipe of @item.recipes) + findSimilarItems: -> group = @mod.itemGroups[@item.groupName] return unless group? @@ -53,7 +56,7 @@ module.exports = class ItemPage extends Observable return null unless group.length > 0 return group - findToolForItem: -> + findToolForItems: -> return @_findItemsWithMatchingRecipes (recipe)=> return recipe.tools[@item.id]? diff --git a/src/client/site/common/markdown_section/markdown_section_controller.coffee b/src/client/site/common/markdown_section/markdown_section_controller.coffee index fe758d45b..5bfe2ac0c 100644 --- a/src/client/site/common/markdown_section/markdown_section_controller.coffee +++ b/src/client/site/common/markdown_section/markdown_section_controller.coffee @@ -7,6 +7,7 @@ BaseController = require '../../base_controller' convertMarkdown = require 'marked' +ItemDisplay = require "../../../models/site/item_display" MarkdownImageListController = require './markdown_image_list/markdown_image_list_controller' ######################################################################################################################## @@ -219,8 +220,8 @@ module.exports = class MarkdownSectionController extends BaseController result = match item = @_modPack.findItemByName name if item? - display = @_modPack.findItemDisplay item.slug - result = "[#{name}](#{display.itemUrl})" + display = new ItemDisplay item + result = "[#{name}](#{display.url})" return result diff --git a/src/client/site/common/stack/stack_controller.coffee b/src/client/site/common/stack/stack_controller.coffee index 7c8825877..4026c6ede 100644 --- a/src/client/site/common/stack/stack_controller.coffee +++ b/src/client/site/common/stack/stack_controller.coffee @@ -122,7 +122,7 @@ module.exports = class StackController extends BaseController @_imageLoader.load display.iconUrl, @$image @$nameLink.html display.name - @$nameLink.attr 'href', display.itemUrl + @$nameLink.attr 'href', display.url quantityText = if @model.quantity > 10000 then "#{@model.quantity / 1000}k" else "#{@model.quantity}" @$quantityField.val quantityText diff --git a/src/client/site/header/header_controller.coffee b/src/client/site/header/header_controller.coffee index d00f9cf8c..107cdffa2 100644 --- a/src/client/site/header/header_controller.coffee +++ b/src/client/site/header/header_controller.coffee @@ -6,6 +6,7 @@ # BaseController = require '../base_controller' +ItemDisplay = require "../../models/site/item_display" ItemSelectorController = require '../common/item_selector/item_selector_controller' UrlParams = require '../url_params' @@ -52,14 +53,14 @@ module.exports = class HeaderController extends BaseController onSearch: (event, hint='')-> tracker.trackEvent c.tracking.category.search, 'launch' @_selector.launch hint - .then (itemSlug)=> - if not itemSlug? - tracker.trackEvent c.tracking.category.search, 'cancel', itemSlug + .then (item)=> + if not item? + tracker.trackEvent c.tracking.category.search, 'cancel', item.slug return - tracker.trackEvent c.tracking.category.search, 'complete', itemSlug - itemDisplay = @_modPack.findItemDisplay itemSlug - @router.navigate itemDisplay.itemUrl, trigger:true + tracker.trackEvent c.tracking.category.search, 'complete', item.slug + itemDisplay = new ItemDisplay item + @router.navigate itemDisplay.url, trigger:true return false # BaseController Overrides ##################################################################### diff --git a/src/client/site/item_page/item_page_controller.coffee b/src/client/site/item_page/item_page_controller.coffee index 13cb067d9..8cbce16a3 100644 --- a/src/client/site/item_page/item_page_controller.coffee +++ b/src/client/site/item_page/item_page_controller.coffee @@ -45,8 +45,7 @@ module.exports = class ItemPageController extends PageController craftingPlanButtonClicked: -> tracker.trackEvent c.tracking.category.craft, "view-crafting-plan", @model.item.slug - display = @_modPack.findItemDisplay @model.item.slug - @_router.navigate display.craftingUrl, trigger:true + @_router.navigate @model.itemDisplay.craftingUrl, trigger:true return false # PageController Overrides ##################################################################### @@ -54,8 +53,8 @@ module.exports = class ItemPageController extends PageController getBreadcrumbs: -> return [ $("Browse") - $("#{@model.display.modName}") - $("#{display.name}") + $("#{@model.itemDisplay.mod.displayName}") + $("#{@model.itemDisplay.name}") ] getExtraNav: -> @@ -66,17 +65,11 @@ module.exports = class ItemPageController extends PageController return $("Random Item") getMetaDescription: -> - return null unless @_itemSlug? - display = @_modPack.findItemDisplay @_itemSlug - return c.text.itemDescription display + data = itemName:@model.item.displayName, modName:@model.item.mod.displayName + return c.text.itemDescription data getTitle: -> - return null unless @_itemSlug? - - display = @_modPack.findItemDisplay @_itemSlug - return null unless display.itemName? and display.modName? - - return "#{display.itemName} from #{display.modName}" + return "#{@model.item.displayName} from #{@model.item.mod.displayName}" # BaseController Overrides ##################################################################### @@ -120,14 +113,11 @@ module.exports = class ItemPageController extends PageController super refresh: -> - @_resolveItemSlug() - if @model.item? - display = @_modPack.findItemDisplay @model.item.slug - @_imageLoader.load display.iconUrl, @$aboutImage - @$name.text display.itemName + @_imageLoader.load @model.itemDisplay.iconUrl, @$aboutImage + @$name.text @model.itemDisplay.name - @_descriptionController.imageBase = c.url.itemImageDir display + @_descriptionController.imageBase = c.url.itemImageDir @model.itemDisplay if @model.item.officialUrl? @$officialLink.attr 'href', @model.item.officialUrl @@ -182,7 +172,7 @@ module.exports = class ItemPageController extends PageController if not @model.item? return w.reject new Error 'must have an item' - pathArgs = modSlug:@_itemSlug.mod, itemSlug:@_itemSlug.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 @@ -232,8 +222,8 @@ module.exports = class ItemPageController extends PageController @_descriptionController.resetToDefaultState() _refreshMultiblock: -> - if @model.item?.multiblock? - @_multiblockController.model = @model.item.multiblock + if @model.item.isMultiblock + @_multiblockController.model = @model.item.getMultiblockRecipe() @show @$multiblockSection else @hide @$multiblockSection @@ -246,7 +236,7 @@ module.exports = class ItemPageController extends PageController if recipes?.length > 0 @$recipesSectionTitle.html if recipes.length is 1 then 'Recipe' else 'Recipes' - for recipe in @model.findRecipes() + for recipe in recipes controller = @_recipeControllers[index] if not controller? controller = new RecipeDetailController @@ -269,26 +259,22 @@ module.exports = class ItemPageController extends PageController @_recipeControllers.pop().remove() _refreshSimilarItems: -> - group = @model.item?.group - if group? and group isnt Item.Group.Other + group = @model.item.group + if group? and group isnt Item::DEFAULT_GROUP_NAME @_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 + 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.findToolForRecipes() + @_usedAsToolToMakeController.model = @model.findToolForItems() _refreshUsedToMake: -> @_usedToMakeController.title = 'Used to Make' @@ -319,16 +305,3 @@ module.exports = class ItemPageController extends PageController 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() diff --git a/src/client/site/item_page/multiblock_viewer/multiblock/multiblock_controller.coffee b/src/client/site/item_page/multiblock_viewer/multiblock/multiblock_controller.coffee index 914e230fb..5829784bc 100644 --- a/src/client/site/item_page/multiblock_viewer/multiblock/multiblock_controller.coffee +++ b/src/client/site/item_page/multiblock_viewer/multiblock/multiblock_controller.coffee @@ -6,6 +6,7 @@ All rights reserved. ### BaseController = require '../../../base_controller' +ItemDisplay = require "../../../../models/site/item_display" ######################################################################################################################## @@ -143,7 +144,7 @@ module.exports = class MultiblockController extends BaseController move = false if stack? - itemDisplay = @_modPack.findItemDisplay stack.itemSlug + itemDisplay = new ItemDisplay stack.item if not $block? $block = $("#{itemDisplay.itemName}") diff --git a/src/client/site/item_page/recipe_detail/recipe_detail_controller.coffee b/src/client/site/item_page/recipe_detail/recipe_detail_controller.coffee index bcf81d47e..3be268ebd 100644 --- a/src/client/site/item_page/recipe_detail/recipe_detail_controller.coffee +++ b/src/client/site/item_page/recipe_detail/recipe_detail_controller.coffee @@ -5,21 +5,22 @@ # All rights reserved. # -BaseController = require '../../base_controller' -CraftingGridController = require '../../common/crafting_grid/crafting_grid_controller' -{Inventory} = require('crafting-guide-common').deprecated.game -InventoryController = require '../../common/inventory/inventory_controller' -{StringBuilder} = require('crafting-guide-common').util +BaseController = require "../../base_controller" +CraftingGridController = require "../../common/crafting_grid/crafting_grid_controller" +{Inventory} = require("crafting-guide-common").models +InventoryController = require "../../common/inventory/inventory_controller" +ItemDisplay = require "../../../models/site/item_display" +{StringBuilder} = require("crafting-guide-common").util ######################################################################################################################## 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' + 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 @@ -29,26 +30,26 @@ module.exports = class RecipeDetailController extends BaseController # BaseController Overrides ##################################################################### onDidRender: -> - @gridController = @addChild CraftingGridController, '.view__crafting_grid', + @gridController = @addChild CraftingGridController, ".view__crafting_grid", imageLoader: @_imageLoader modPack: @_modPack router: @_router - @inputController = @addChild InventoryController, '.input .view__inventory', + @inputController = @addChild InventoryController, ".input .view__inventory", editable: false imageLoader: @_imageLoader model: new Inventory modPack: @_modPack router: @_router - @outputController = @addChild InventoryController, '.output .view__inventory', + @outputController = @addChild InventoryController, ".output .view__inventory", editable: false imageLoader: @_imageLoader model: new Inventory modPack: @_modPack router: @_router - @$toolContainer = @$('.tool') + @$toolContainer = @$(".tool") super refresh: -> @@ -67,33 +68,33 @@ module.exports = class RecipeDetailController extends BaseController events: -> return _.extend super, - 'click a': 'routeLinkClick' + "click a": "routeLinkClick" # Private Methods ############################################################################## _refreshInputs: -> inputs = @inputController.model inputs.clear() + return unless @model? - if @model? - for stack in @model.input - inputs.add stack.itemSlug, @model.getQuantityRequired stack.itemSlug - + for itemId, item of @model.inputs + inputs.add item, @model.computeQuantityRequired item _refreshOutputs: -> outputs = @outputController.model outputs.clear() + return unless @model? - if @model? - for stack in @model.output - outputs.add stack.itemSlug, @model.getQuantityProduced stack.itemSlug + outputs.add @model.output.item, @model.output.quantity + for itemId, item of @model.extras + outputs.add item, @model.computeQuantityProduced item _refreshTools: -> @$toolContainer.empty() return unless @model? - builder = new StringBuilder - builder.loop @model.tools, delimiter:', ', onEach:(b, stack)=> - display = @_modPack.findItemDisplay stack.itemSlug - b.push "#{display.itemName}" - @$toolContainer.html builder.toString() + toolLinks = [] + for itemId, item of @model.tools + display = new ItemDisplay item + toolLinks.push "#{display.name}" + @$toolContainer.html toolLinks.join ", " From 2fd1de40daf771f6ba979cfe60d2e0335f72951f Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Tue, 4 Jul 2017 23:28:56 -0700 Subject: [PATCH 08/21] Improve render time on long crafting plans --- .../site/craft_page/craft_page_controller.coffee | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/client/site/craft_page/craft_page_controller.coffee b/src/client/site/craft_page/craft_page_controller.coffee index 1abc722c0..59b1c4ea5 100644 --- a/src/client/site/craft_page/craft_page_controller.coffee +++ b/src/client/site/craft_page/craft_page_controller.coffee @@ -18,6 +18,7 @@ StepController = require "./step/step_controller" module.exports = class CraftPageController extends PageController @::SCROLL_BUFFER = 8 # px + @::STEP_RENDER_DELAY = 25 # ms constructor: (options={})-> if not options.imageLoader? then throw new Error "options.imageLoader is required" @@ -231,10 +232,14 @@ module.exports = class CraftPageController extends PageController model: step modPack: @_modPack router: @_router - controller.render() - @$stepsContainer.append controller.$el - @_stepControllers.push controller + do (controller, index)=> + _.delay (=> + controller.render() + + @$stepsContainer.append controller.$el + @_stepControllers.push controller + ), (index * @STEP_RENDER_DELAY) else controller.model = step From b8a2dae9f27585e8a8e7f8aeb6113250d1d08b1f Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Tue, 11 Jul 2017 05:51:52 -0700 Subject: [PATCH 09/21] Ensure inventory changes work on craft page --- .gitignore | 1 + package.json | 1 + .../inventory/inventory_controller.coffee | 7 ++++--- .../craft_page/craft_page_controller.coffee | 19 +++++++++---------- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index ebe50d5e0..6aefb3414 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.log +*.swp .DS_Store .env .sass-cache diff --git a/package.json b/package.json index b62a407e2..52eb08857 100644 --- a/package.json +++ b/package.json @@ -48,3 +48,4 @@ "when": "3.7.8" } } + diff --git a/src/client/site/common/inventory/inventory_controller.coffee b/src/client/site/common/inventory/inventory_controller.coffee index 315e87d43..1110080b1 100644 --- a/src/client/site/common/inventory/inventory_controller.coffee +++ b/src/client/site/common/inventory/inventory_controller.coffee @@ -59,9 +59,9 @@ module.exports = class InventoryController extends BaseController @trigger c.event.change, this onFirstButtonClicked: (stackController)-> - itemId = stackController.model?.item.id - tracker.trackEvent @_trackingContext, 'remove-from', itemId - @trigger c.event.button.first, this, itemId + item = stackController.model?.item + tracker.trackEvent @_trackingContext, 'remove-from', item.id + @trigger c.event.button.first, this, item onItemSelectorButtonClicked: -> return unless @model? @@ -158,3 +158,4 @@ module.exports = class InventoryController extends BaseController while @_stackControllers.length > index @_stackControllers.pop().remove() + diff --git a/src/client/site/craft_page/craft_page_controller.coffee b/src/client/site/craft_page/craft_page_controller.coffee index 59b1c4ea5..db4390b67 100644 --- a/src/client/site/craft_page/craft_page_controller.coffee +++ b/src/client/site/craft_page/craft_page_controller.coffee @@ -43,16 +43,15 @@ module.exports = class CraftPageController extends PageController onHaveInventoryChanged: -> @_storage.store 'crafting-plan:have', @model.have.toUrlString() - onMoveNeedToHave: (itemId)-> - quantity = @_needInventoryController.model.getQuantity itemId - item = @_modPack.findItem itemId + onMoveNeedToHave: (item)-> + quantity = @_needInventoryController.model.getQuantity item @model.have.add item, quantity - onRemoveFromHave: (itemId)-> - @model.have.remove itemId + onRemoveFromHave: (item)-> + @model.have.remove item - onRemoveFromWant: (itemId)-> - @model.want.remove itemId + onRemoveFromWant: (item)-> + @model.want.remove item @onWantInventoryChanged() onSampleClicked: (event)-> @@ -99,7 +98,7 @@ module.exports = class CraftPageController extends PageController model: @model.want router: @_router trackingContext: c.tracking.category.craftWant - @_wantInventoryController.on c.event.button.first, (controller, itemId)=> @onRemoveFromWant itemId + @_wantInventoryController.on c.event.button.first, (controller, item)=> @onRemoveFromWant item @_haveInventoryController = @addChild InventoryController, '.have .view__inventory', firstButtonType: 'down' @@ -108,7 +107,7 @@ module.exports = class CraftPageController extends PageController model: @model.have router: @_router trackingContext: c.tracking.category.craftHave - @_haveInventoryController.on c.event.button.first, (controller, itemId)=> @onRemoveFromHave itemId + @_haveInventoryController.on c.event.button.first, (controller, item)=> @onRemoveFromHave item @_needInventoryController = @addChild InventoryController, '.need .view__inventory', editable: false @@ -118,7 +117,7 @@ module.exports = class CraftPageController extends PageController model: null router: @_router trackingContext: c.tracking.category.craftNeed - @_needInventoryController.on c.event.button.first, (controller, itemId)=> @onMoveNeedToHave itemId + @_needInventoryController.on c.event.button.first, (controller, item)=> @onMoveNeedToHave item @_workingPanelController = @addChild WorkingPanelController, '.view__working_panel', model:@model From 33479051c8c603bd323528e7e38a42ccf360da6d Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Tue, 11 Jul 2017 09:26:09 -0700 Subject: [PATCH 10/21] Ensure step helper buttons work fixes #288 --- package-lock.json | 2917 +++++++++++++++++ package.json | 1 - .../craft_page/craft_page_controller.coffee | 12 +- .../craft_page/step/step_controller.coffee | 7 +- 4 files changed, 2927 insertions(+), 10 deletions(-) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..c061c9209 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2917 @@ +{ + "name": "crafting-guide", + "version": "3.2.6", + "lockfileVersion": 1, + "dependencies": { + "abbrev": { + "version": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", + "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=", + "dev": true + }, + "accepts": { + "version": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", + "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=" + }, + "acorn": { + "version": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", + "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=" + }, + "acorn-globals": { + "version": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz", + "integrity": "sha1-VbtemGkVB7dFedBRNBMhfDgMVM8=" + }, + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true, + "optional": true + }, + "align-text": { + "version": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=" + }, + "amdefine": { + "version": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" + }, + "ansi-regex": { + "version": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "aproba": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.1.2.tgz", + "integrity": "sha512-ZpYajIfO0j2cOFTO955KUMIKNmj6zhX8kVztMAxFsDaMwz+9Z9SV0uou2pC9HJqcfpffOsjnbrDMvkNy+9RXPw==", + "dev": true, + "optional": true + }, + "archiver": { + "version": "https://registry.npmjs.org/archiver/-/archiver-1.3.0.tgz", + "integrity": "sha1-TyGU1tj5nfP1MeaIHxTxXVX6ryI=", + "dev": true, + "dependencies": { + "async": { + "version": "https://registry.npmjs.org/async/-/async-2.4.0.tgz", + "integrity": "sha1-SZAgDxjqW4N8LMT4wDGmmFw4VhE=", + "dev": true + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + }, + "archiver-utils": { + "version": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-1.3.0.tgz", + "integrity": "sha1-5QtMCccL89aA4y/xt5lOn52JUXQ=", + "dev": true, + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + }, + "are-we-there-yet": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", + "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", + "dev": true, + "optional": true + }, + "argparse": { + "version": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true + }, + "array-find-index": { + "version": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-flatten": { + "version": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "asap": { + "version": "https://registry.npmjs.org/asap/-/asap-1.0.0.tgz", + "integrity": "sha1-sqRdpf36ILBJb8N2jMJ8EvqRan0=" + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true, + "optional": true + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "dev": true, + "optional": true + }, + "assertion-error": { + "version": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", + "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=", + "dev": true + }, + "async": { + "version": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true, + "optional": true + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", + "dev": true, + "optional": true + }, + "backbone": { + "version": "https://registry.npmjs.org/backbone/-/backbone-1.3.3.tgz", + "integrity": "sha1-TMgOp8sWMaxHSInOQPL4vGg7KZk=" + }, + "balanced-match": { + "version": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": true + }, + "bl": { + "version": "https://registry.npmjs.org/bl/-/bl-1.2.1.tgz", + "integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=", + "dev": true + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "dev": true + }, + "body-parser": { + "version": "https://registry.npmjs.org/body-parser/-/body-parser-1.17.1.tgz", + "integrity": "sha1-dbO8mN3W5+DY/+dQ36ylxmmT+kc=" + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true + }, + "brace-expansion": { + "version": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz", + "integrity": "sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k=", + "dev": true + }, + "browser-stdout": { + "version": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "browserify-zlib": { + "version": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", + "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=", + "dev": true + }, + "buffer-crc32": { + "version": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true + }, + "buffer-shims": { + "version": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", + "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=", + "dev": true + }, + "builtin-modules": { + "version": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "bytes": { + "version": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", + "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=" + }, + "camelcase": { + "version": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + }, + "camelcase-keys": { + "version": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true, + "optional": true + }, + "center-align": { + "version": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=" + }, + "chai": { + "version": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", + "dev": true + }, + "chalk": { + "version": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true + }, + "character-parser": { + "version": "https://registry.npmjs.org/character-parser/-/character-parser-1.2.1.tgz", + "integrity": "sha1-wN3kqxgnE7kZuXCVmhI+zBow/NY=" + }, + "clean-css": { + "version": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.25.tgz", + "integrity": "sha1-nppS1cHmvFEj4bJ4P6Zf6ViUbt4=", + "dependencies": { + "commander": { + "version": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=" + } + } + }, + "client-sessions": { + "version": "https://registry.npmjs.org/client-sessions/-/client-sessions-0.8.0.tgz", + "integrity": "sha1-p9jFVYrV1W8qGZ81M+tlS134k/0=" + }, + "cliui": { + "version": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dependencies": { + "wordwrap": { + "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" + } + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "coffee-script": { + "version": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.5.tgz", + "integrity": "sha1-gJ9FhUGRErv+RqBzrXVDrxjCc0Y=", + "dev": true + }, + "coffeeify": { + "version": "https://registry.npmjs.org/coffeeify/-/coffeeify-2.1.0.tgz", + "integrity": "sha1-Bt6Aqoe2GUk3c0Nh3vSt4lS3Gh4=", + "dev": true + }, + "colors": { + "version": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "dev": true + }, + "commander": { + "version": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz", + "integrity": "sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0=" + }, + "compress-commons": { + "version": "https://registry.npmjs.org/compress-commons/-/compress-commons-1.2.0.tgz", + "integrity": "sha1-WFhwku8g03y1i68AARLJJ4/3O58=", + "dev": true + }, + "concat-map": { + "version": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "constantinople": { + "version": "https://registry.npmjs.org/constantinople/-/constantinople-3.0.2.tgz", + "integrity": "sha1-S5RdmTeQe82Y7ldRIsOBdRZUQUE=" + }, + "content-disposition": { + "version": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz", + "integrity": "sha1-t9ETrueo3Se9IRM8TcJSnfFyHu0=" + }, + "convert-source-map": { + "version": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz", + "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=", + "dev": true + }, + "cookie": { + "version": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-parser": { + "version": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.3.tgz", + "integrity": "sha1-D+MfoZ0AC5X0qt8fU/3CuKIDuqU=" + }, + "cookie-signature": { + "version": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "cookies": { + "version": "https://registry.npmjs.org/cookies/-/cookies-0.7.0.tgz", + "integrity": "sha1-C8lh2RDDUlSYD8fJ7/XaEgEbvwA=" + }, + "core-util-is": { + "version": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "crafting-guide-common": { + "version": "5.6.0", + "dependencies": { + "abbrev": { + "version": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", + "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=" + }, + "ansi-regex": { + "version": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "argparse": { + "version": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=" + }, + "array-find-index": { + "version": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" + }, + "assertion-error": { + "version": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", + "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=" + }, + "async": { + "version": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + }, + "backbone": { + "version": "https://registry.npmjs.org/backbone/-/backbone-1.3.3.tgz", + "integrity": "sha1-TMgOp8sWMaxHSInOQPL4vGg7KZk=" + }, + "balanced-match": { + "version": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=" + }, + "body-parser": { + "version": "https://registry.npmjs.org/body-parser/-/body-parser-1.14.2.tgz", + "integrity": "sha1-EBXLH+LEQ4WCWVgdtTMy+NDPUPk=", + "dependencies": { + "iconv-lite": { + "version": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", + "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=" + }, + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz", + "integrity": "sha1-qfMRQq9GjLcrJbMBNrokVoNJFr4=" + } + } + }, + "brace-expansion": { + "version": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz", + "integrity": "sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k=" + }, + "browser-stdout": { + "version": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=" + }, + "builtin-modules": { + "version": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" + }, + "bytes": { + "version": "https://registry.npmjs.org/bytes/-/bytes-2.2.0.tgz", + "integrity": "sha1-/TVGSkA/b5EXwt42Cez/nK4ABYg=" + }, + "camelcase": { + "version": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + }, + "camelcase-keys": { + "version": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=" + }, + "chai": { + "version": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=" + }, + "chalk": { + "version": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=" + }, + "coffee-script": { + "version": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.5.tgz", + "integrity": "sha1-gJ9FhUGRErv+RqBzrXVDrxjCc0Y=" + }, + "colors": { + "version": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=" + }, + "commander": { + "version": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=" + }, + "concat-map": { + "version": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "content-type": { + "version": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz", + "integrity": "sha1-t9ETrueo3Se9IRM8TcJSnfFyHu0=" + }, + "currently-unhandled": { + "version": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=" + }, + "dateformat": { + "version": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", + "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=" + }, + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=" + }, + "decamelize": { + "version": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "deep-eql": { + "version": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "dependencies": { + "type-detect": { + "version": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=" + } + } + }, + "depd": { + "version": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz", + "integrity": "sha1-4b2Cxqq2ztlluXuIsX7T5SjKGMM=" + }, + "diff": { + "version": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=" + }, + "ee-first": { + "version": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "error-ex": { + "version": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=" + }, + "escape-string-regexp": { + "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "esprima": { + "version": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=" + }, + "eventemitter2": { + "version": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=" + }, + "exit": { + "version": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=" + }, + "faye-websocket": { + "version": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=" + }, + "file-sync-cmp": { + "version": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz", + "integrity": "sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=" + }, + "find-up": { + "version": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=" + }, + "findup-sync": { + "version": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", + "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", + "dependencies": { + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=" + } + } + }, + "formatio": { + "version": "https://registry.npmjs.org/formatio/-/formatio-1.2.0.tgz", + "integrity": "sha1-87IWfZBoxGmKjVH092CjmlTYGOs=" + }, + "fs.realpath": { + "version": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "gaze": { + "version": "https://registry.npmjs.org/gaze/-/gaze-1.1.2.tgz", + "integrity": "sha1-hHIkZ3rbiHDWeSV+0ziP22HkAQU=" + }, + "get-stdin": { + "version": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" + }, + "getobject": { + "version": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", + "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=" + }, + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=" + }, + "globule": { + "version": "https://registry.npmjs.org/globule/-/globule-1.1.0.tgz", + "integrity": "sha1-xJNS5NwYPYWJPuglOF65lLtt9F8=", + "dependencies": { + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=" + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.16.6.tgz", + "integrity": "sha1-0iyaxmAojzhD4Wun0rXQbMon13c=" + } + } + }, + "graceful-fs": { + "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "graceful-readlink": { + "version": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" + }, + "growl": { + "version": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=" + }, + "grunt": { + "version": "https://registry.npmjs.org/grunt/-/grunt-1.0.1.tgz", + "integrity": "sha1-6HeHZOlEsY8yuw8QuQeEdcnftWs=", + "dependencies": { + "coffee-script": { + "version": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.10.0.tgz", + "integrity": "sha1-EpOLz5vhlI+gBvkuDEyegXBRCMA=" + }, + "grunt-cli": { + "version": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz", + "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=" + } + } + }, + "grunt-contrib-clean": { + "version": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-1.1.0.tgz", + "integrity": "sha1-Vkq/LQN4qYOhW54/MO51tzjEBjg=", + "dependencies": { + "rimraf": { + "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=" + } + } + }, + "grunt-contrib-coffee": { + "version": "https://registry.npmjs.org/grunt-contrib-coffee/-/grunt-contrib-coffee-1.0.0.tgz", + "integrity": "sha1-2u6wSVTxTihovMm6bq+RBf3C2kw=", + "dependencies": { + "ansi-regex": { + "version": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", + "integrity": "sha1-QchHGUZGN15qGl0Qw8oFTvn8mA0=" + }, + "chalk": { + "version": "https://registry.npmjs.org/chalk/-/chalk-1.0.0.tgz", + "integrity": "sha1-s89O0P9Tl8mcdbj2edsvUoMfltw=" + }, + "coffee-script": { + "version": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.10.0.tgz", + "integrity": "sha1-EpOLz5vhlI+gBvkuDEyegXBRCMA=" + }, + "has-ansi": { + "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-1.0.3.tgz", + "integrity": "sha1-wLWxYV2eOCsP9nFp2We0JeSMpTg=" + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz", + "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=" + }, + "strip-ansi": { + "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz", + "integrity": "sha1-32LBqpTtLxFOHQ8h/R1QSCt5pg4=" + }, + "supports-color": { + "version": "https://registry.npmjs.org/supports-color/-/supports-color-1.3.1.tgz", + "integrity": "sha1-FXWN8J2P87SswwdTn6vicJXhBC0=" + } + } + }, + "grunt-contrib-copy": { + "version": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-1.0.0.tgz", + "integrity": "sha1-cGDGWB6QS4qw0A8HbgqPbj58NXM=" + }, + "grunt-contrib-watch": { + "version": "https://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-1.0.0.tgz", + "integrity": "sha1-hKGnodar0m7VaEE0lscxM+mQAY8=" + }, + "grunt-known-options": { + "version": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.0.tgz", + "integrity": "sha1-pCdO6zL6dl2lp6OxcSYXzjsUQUk=" + }, + "grunt-legacy-log": { + "version": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-1.0.0.tgz", + "integrity": "sha1-+4bxgJhHvAfcR4Q/ns1srLYt8tU=", + "dependencies": { + "underscore.string": { + "version": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.2.3.tgz", + "integrity": "sha1-gGmSYzZl1eX8tNsfs6hi62jp5to=" + } + } + }, + "grunt-legacy-log-utils": { + "version": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-1.0.0.tgz", + "integrity": "sha1-p7ji0Ps1taUPSvmG/BEnSevJbz0=", + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz", + "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=" + } + } + }, + "grunt-legacy-util": { + "version": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.0.0.tgz", + "integrity": "sha1-OGqnjcbtUJhsKxiVcmWxtIq7m4Y=", + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz", + "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=" + }, + "underscore.string": { + "version": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.2.3.tgz", + "integrity": "sha1-gGmSYzZl1eX8tNsfs6hi62jp5to=" + } + } + }, + "grunt-mocha-test": { + "version": "https://registry.npmjs.org/grunt-mocha-test/-/grunt-mocha-test-0.13.2.tgz", + "integrity": "sha1-Dzq8xqtUNkex7/xatE69NwLwq4w=" + }, + "has-ansi": { + "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=" + }, + "has-flag": { + "version": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=" + }, + "hooker": { + "version": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", + "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=" + }, + "hosted-git-info": { + "version": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.4.2.tgz", + "integrity": "sha1-AHa59GonBQbduq6lZJaJdGBhKmc=" + }, + "http-errors": { + "version": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz", + "integrity": "sha1-GX4izevUGYWF6GlO9nhhl7ke2UI=" + }, + "iconv-lite": { + "version": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.16.tgz", + "integrity": "sha1-Zd477rOeKWDWfwSfFjT/y83pAUs=" + }, + "indent-string": { + "version": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=" + }, + "inflight": { + "version": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=" + }, + "inherits": { + "version": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "is-arrayish": { + "version": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-builtin-module": { + "version": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=" + }, + "is-finite": { + "version": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=" + }, + "is-utf8": { + "version": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + }, + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "isexe": { + "version": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "js-yaml": { + "version": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.5.5.tgz", + "integrity": "sha1-A3fDgBfKvHMisNH7zSWkkWQfL74=" + }, + "json3": { + "version": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=" + }, + "livereload-js": { + "version": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.2.2.tgz", + "integrity": "sha1-bIclfmSKtHW8JOoldFftzB+NC8I=" + }, + "load-json-file": { + "version": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=" + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" + }, + "lodash._baseassign": { + "version": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=" + }, + "lodash._basecopy": { + "version": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=" + }, + "lodash._basecreate": { + "version": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=" + }, + "lodash._getnative": { + "version": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" + }, + "lodash._isiterateecall": { + "version": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=" + }, + "lodash.create": { + "version": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=" + }, + "lodash.isarguments": { + "version": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" + }, + "lodash.isarray": { + "version": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=" + }, + "lodash.keys": { + "version": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=" + }, + "lolex": { + "version": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz", + "integrity": "sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=" + }, + "loud-rejection": { + "version": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=" + }, + "map-obj": { + "version": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" + }, + "media-typer": { + "version": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "meow": { + "version": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=" + }, + "mime-db": { + "version": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", + "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=" + }, + "mime-types": { + "version": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", + "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=" + }, + "minimatch": { + "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=" + }, + "minimist": { + "version": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "mkdirp": { + "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dependencies": { + "minimist": { + "version": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "mocha": { + "version": "https://registry.npmjs.org/mocha/-/mocha-3.3.0.tgz", + "integrity": "sha1-0pt0KNP1LILi5l3x7LcGThqrv7U=", + "dependencies": { + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.6.0.tgz", + "integrity": "sha1-vFlryr52F/Edn6FTYe3tVgi4SZs=" + }, + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=" + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" + }, + "supports-color": { + "version": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=" + } + } + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + }, + "native-promise-only": { + "version": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", + "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=" + }, + "nopt": { + "version": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=" + }, + "normalize-package-data": { + "version": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.8.tgz", + "integrity": "sha1-2Bntoqne29H/pWPqQHHZNngilbs=" + }, + "number-is-nan": { + "version": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "object-assign": { + "version": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "on-finished": { + "version": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=" + }, + "once": { + "version": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=" + }, + "parse-json": { + "version": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=" + }, + "parseurl": { + "version": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz", + "integrity": "sha1-yKuMkiO6NIiKpkopeyiFO+wY2lY=" + }, + "path-exists": { + "version": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=" + }, + "path-is-absolute": { + "version": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-to-regexp": { + "version": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=" + }, + "path-type": { + "version": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=" + }, + "pify": { + "version": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "pinkie": { + "version": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=" + }, + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-5.1.0.tgz", + "integrity": "sha1-TZMuXH6kEcynajEtOaYGIA/VDNk=" + }, + "raw-body": { + "version": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz", + "integrity": "sha1-rf6s4uT7MJgFgBTQjActzFl1h3Q=", + "dependencies": { + "bytes": { + "version": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", + "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=" + }, + "iconv-lite": { + "version": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", + "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=" + } + } + }, + "read-pkg": { + "version": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=" + }, + "read-pkg-up": { + "version": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=" + }, + "redent": { + "version": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=" + }, + "repeating": { + "version": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=" + }, + "resolve": { + "version": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" + }, + "rimraf": { + "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=" + }, + "samsam": { + "version": "https://registry.npmjs.org/samsam/-/samsam-1.2.1.tgz", + "integrity": "sha1-7dOQk6MYQ3DLhZJDsr3yVefY6mc=" + }, + "semver": { + "version": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" + }, + "signal-exit": { + "version": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "sinon": { + "version": "https://registry.npmjs.org/sinon/-/sinon-2.1.0.tgz", + "integrity": "sha1-4Fep0r8bMvXW3WJijKnuOWGwyvs=", + "dependencies": { + "type-detect": { + "version": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.3.tgz", + "integrity": "sha1-Dj8mcLRAmbC0bChNE2p+9Jx0wuo=" + } + } + }, + "sinon-chai": { + "version": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-2.9.0.tgz", + "integrity": "sha1-NNggBCvJZhoUUnEw1AHrRixJu4Q=" + }, + "spdx-correct": { + "version": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=" + }, + "spdx-expression-parse": { + "version": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=" + }, + "spdx-license-ids": { + "version": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=" + }, + "sprintf-js": { + "version": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "statuses": { + "version": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + }, + "strip-ansi": { + "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=" + }, + "strip-bom": { + "version": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=" + }, + "strip-indent": { + "version": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=" + }, + "supports-color": { + "version": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "text-encoding": { + "version": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", + "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=" + }, + "tiny-lr": { + "version": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-0.2.1.tgz", + "integrity": "sha1-s/26gC5dVqM8L28QeUsy5Hescp0=" + }, + "trim-newlines": { + "version": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" + }, + "type-detect": { + "version": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", + "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=" + }, + "type-is": { + "version": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", + "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=" + }, + "underscore": { + "version": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" + }, + "underscore.inflections": { + "version": "https://registry.npmjs.org/underscore.inflections/-/underscore.inflections-0.2.1.tgz", + "integrity": "sha1-EBvTWeAq8pOqWhBidI6WPiCHZ/E=" + }, + "underscore.string": { + "version": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.4.tgz", + "integrity": "sha1-LCo/n4PmR2L9xF5s6sZRQoZCE9s=" + }, + "unpipe": { + "version": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "uri-path": { + "version": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", + "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=" + }, + "util-deprecate": { + "version": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz", + "integrity": "sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE=" + }, + "validate-npm-package-license": { + "version": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=" + }, + "websocket-driver": { + "version": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz", + "integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=" + }, + "websocket-extensions": { + "version": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz", + "integrity": "sha1-domUmcGEtu91Q3fC27DNbLVdKec=" + }, + "when": { + "version": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", + "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=" + }, + "which": { + "version": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=" + }, + "wrappy": { + "version": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } + }, + "crc": { + "version": "https://registry.npmjs.org/crc/-/crc-3.4.4.tgz", + "integrity": "sha1-naHpgOO9RPxck79as9ozeNheRms=" + }, + "crc32-stream": { + "version": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-2.0.0.tgz", + "integrity": "sha1-483TtN8xaN10494/u8t7KX/pCPQ=", + "dev": true + }, + "cross-spawn": { + "version": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-0.2.9.tgz", + "integrity": "sha1-vWf5bAfvtjA7f+lMHpefiEeOCjk=", + "dev": true + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true, + "optional": true + }, + "css": { + "version": "https://registry.npmjs.org/css/-/css-1.0.8.tgz", + "integrity": "sha1-k4aBHKgrzMnuf7WnMrHioxfIo+c=" + }, + "css-parse": { + "version": "https://registry.npmjs.org/css-parse/-/css-parse-1.0.4.tgz", + "integrity": "sha1-OLBQP7+dqfVOnB29pg4UXHcRe90=" + }, + "css-stringify": { + "version": "https://registry.npmjs.org/css-stringify/-/css-stringify-1.0.5.tgz", + "integrity": "sha1-sNBClG2ylTu50pKQCmy19tASIDE=" + }, + "currently-unhandled": { + "version": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true + }, + "dargs": { + "version": "https://registry.npmjs.org/dargs/-/dargs-4.1.0.tgz", + "integrity": "sha1-A6nbtLXC8Tm/FK5T8LiipqhvThc=", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "optional": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "optional": true + } + } + }, + "dateformat": { + "version": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", + "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", + "dev": true + }, + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.6.1.tgz", + "integrity": "sha1-eYVQkLosTjEVzH2HaUkdWPBJE1E=" + }, + "decamelize": { + "version": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "deep-eql": { + "version": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "dev": true, + "dependencies": { + "type-detect": { + "version": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", + "dev": true + } + } + }, + "deep-extend": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", + "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=", + "dev": true, + "optional": true + }, + "define-properties": { + "version": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", + "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true, + "optional": true + }, + "depd": { + "version": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz", + "integrity": "sha1-4b2Cxqq2ztlluXuIsX7T5SjKGMM=" + }, + "destroy": { + "version": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "diff": { + "version": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "dev": true + }, + "dotenv": { + "version": "https://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz", + "integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0=" + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true + }, + "ee-first": { + "version": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", + "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=" + }, + "end-of-stream": { + "version": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz", + "integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=", + "dev": true + }, + "error-ex": { + "version": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "dev": true + }, + "escape-html": { + "version": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "etag": { + "version": "https://registry.npmjs.org/etag/-/etag-1.8.0.tgz", + "integrity": "sha1-b2Ma7zNtbEY2K1F2QETOIWvjwFE=" + }, + "eventemitter2": { + "version": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", + "dev": true + }, + "exit": { + "version": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "express": { + "version": "https://registry.npmjs.org/express/-/express-4.15.2.tgz", + "integrity": "sha1-rxB/wUhQRFfy3Kmm8lcdcSm5ezU=" + }, + "express-session": { + "version": "https://registry.npmjs.org/express-session/-/express-session-1.15.2.tgz", + "integrity": "sha1-2YUWRDpMy4aI4XJa5YTALapAk9Q=", + "dependencies": { + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.6.3.tgz", + "integrity": "sha1-D364wwll7AjHKsz6ATDIt5mEFB0=" + } + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true, + "optional": true + }, + "extsprintf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", + "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=", + "dev": true + }, + "faye-websocket": { + "version": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true + }, + "figures": { + "version": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true + }, + "file-sync-cmp": { + "version": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz", + "integrity": "sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=", + "dev": true + }, + "finalhandler": { + "version": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.2.tgz", + "integrity": "sha1-0ONvnbxVfy3hRCPfYmGInp1gyTo=", + "dependencies": { + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.6.4.tgz", + "integrity": "sha1-dYaps8OXQcAoKuM0RcTorHRzT+A=" + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.3.tgz", + "integrity": "sha1-cIFVpeROM/X9D8U+gdDUCpG+H/8=" + } + } + }, + "find-up": { + "version": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true + }, + "findup-sync": { + "version": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", + "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", + "dev": true, + "dependencies": { + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true + } + } + }, + "foreach": { + "version": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true, + "optional": true + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true, + "optional": true + }, + "formatio": { + "version": "https://registry.npmjs.org/formatio/-/formatio-1.2.0.tgz", + "integrity": "sha1-87IWfZBoxGmKjVH092CjmlTYGOs=", + "dev": true + }, + "forwarded": { + "version": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz", + "integrity": "sha1-Ge+YdMSuHCl7zweP3mOgm2aoQ2M=" + }, + "fresh": { + "version": "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz", + "integrity": "sha1-9HTKXmqSRtb9jglTz6m5yAWvp44=" + }, + "fs.realpath": { + "version": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fstream": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", + "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "dev": true + }, + "fstream-ignore": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz", + "integrity": "sha1-nDHa40dnAY/h0kmyTa2mfQktoQU=", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.0.tgz", + "integrity": "sha1-FhdnFMgBeY5Ojyz391KUZ7tKV3E=", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "optional": true + }, + "gaze": { + "version": "https://registry.npmjs.org/gaze/-/gaze-1.1.2.tgz", + "integrity": "sha1-hHIkZ3rbiHDWeSV+0ziP22HkAQU=", + "dev": true + }, + "get-stdin": { + "version": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "getobject": { + "version": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", + "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "optional": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "optional": true + } + } + }, + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", + "dev": true + }, + "globule": { + "version": "https://registry.npmjs.org/globule/-/globule-1.1.0.tgz", + "integrity": "sha1-xJNS5NwYPYWJPuglOF65lLtt9F8=", + "dev": true, + "dependencies": { + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "dev": true + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.16.6.tgz", + "integrity": "sha1-0iyaxmAojzhD4Wun0rXQbMon13c=", + "dev": true + } + } + }, + "graceful-fs": { + "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "graceful-readlink": { + "version": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" + }, + "growl": { + "version": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "grunt": { + "version": "https://registry.npmjs.org/grunt/-/grunt-1.0.1.tgz", + "integrity": "sha1-6HeHZOlEsY8yuw8QuQeEdcnftWs=", + "dev": true, + "dependencies": { + "coffee-script": { + "version": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.10.0.tgz", + "integrity": "sha1-EpOLz5vhlI+gBvkuDEyegXBRCMA=", + "dev": true + }, + "grunt-cli": { + "version": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz", + "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=", + "dev": true + } + } + }, + "grunt-contrib-clean": { + "version": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-1.1.0.tgz", + "integrity": "sha1-Vkq/LQN4qYOhW54/MO51tzjEBjg=", + "dev": true, + "dependencies": { + "rimraf": { + "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "dev": true + } + } + }, + "grunt-contrib-coffee": { + "version": "https://registry.npmjs.org/grunt-contrib-coffee/-/grunt-contrib-coffee-1.0.0.tgz", + "integrity": "sha1-2u6wSVTxTihovMm6bq+RBf3C2kw=", + "dev": true, + "dependencies": { + "ansi-regex": { + "version": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", + "integrity": "sha1-QchHGUZGN15qGl0Qw8oFTvn8mA0=", + "dev": true + }, + "chalk": { + "version": "https://registry.npmjs.org/chalk/-/chalk-1.0.0.tgz", + "integrity": "sha1-s89O0P9Tl8mcdbj2edsvUoMfltw=", + "dev": true + }, + "coffee-script": { + "version": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.10.0.tgz", + "integrity": "sha1-EpOLz5vhlI+gBvkuDEyegXBRCMA=", + "dev": true + }, + "has-ansi": { + "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-1.0.3.tgz", + "integrity": "sha1-wLWxYV2eOCsP9nFp2We0JeSMpTg=", + "dev": true + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz", + "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=", + "dev": true + }, + "strip-ansi": { + "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz", + "integrity": "sha1-32LBqpTtLxFOHQ8h/R1QSCt5pg4=", + "dev": true + }, + "supports-color": { + "version": "https://registry.npmjs.org/supports-color/-/supports-color-1.3.1.tgz", + "integrity": "sha1-FXWN8J2P87SswwdTn6vicJXhBC0=", + "dev": true + } + } + }, + "grunt-contrib-compress": { + "version": "https://registry.npmjs.org/grunt-contrib-compress/-/grunt-contrib-compress-1.4.1.tgz", + "integrity": "sha1-NiEum7tB6bQf9vvi/HcoHGmrAqA=", + "dev": true, + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + }, + "grunt-contrib-copy": { + "version": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-1.0.0.tgz", + "integrity": "sha1-cGDGWB6QS4qw0A8HbgqPbj58NXM=", + "dev": true + }, + "grunt-contrib-jade": { + "version": "https://registry.npmjs.org/grunt-contrib-jade/-/grunt-contrib-jade-1.0.0.tgz", + "integrity": "sha1-tVe8uc0uczrU4gkOEpvrIBsLhFw=", + "dev": true + }, + "grunt-contrib-sass": { + "version": "https://registry.npmjs.org/grunt-contrib-sass/-/grunt-contrib-sass-1.0.0.tgz", + "integrity": "sha1-gGg4JRy8DhqU1k1RXN00z2dNcBs=", + "dev": true, + "dependencies": { + "async": { + "version": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", + "dev": true + } + } + }, + "grunt-contrib-uglify": { + "version": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-2.3.0.tgz", + "integrity": "sha1-s9AmDr3WzvoS/y+Onh4ln33kIW8=", + "dev": true + }, + "grunt-contrib-watch": { + "version": "https://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-1.0.0.tgz", + "integrity": "sha1-hKGnodar0m7VaEE0lscxM+mQAY8=", + "dev": true + }, + "grunt-known-options": { + "version": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.0.tgz", + "integrity": "sha1-pCdO6zL6dl2lp6OxcSYXzjsUQUk=", + "dev": true + }, + "grunt-legacy-log": { + "version": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-1.0.0.tgz", + "integrity": "sha1-+4bxgJhHvAfcR4Q/ns1srLYt8tU=", + "dev": true, + "dependencies": { + "underscore.string": { + "version": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.2.3.tgz", + "integrity": "sha1-gGmSYzZl1eX8tNsfs6hi62jp5to=", + "dev": true + } + } + }, + "grunt-legacy-log-utils": { + "version": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-1.0.0.tgz", + "integrity": "sha1-p7ji0Ps1taUPSvmG/BEnSevJbz0=", + "dev": true, + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz", + "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=", + "dev": true + } + } + }, + "grunt-legacy-util": { + "version": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.0.0.tgz", + "integrity": "sha1-OGqnjcbtUJhsKxiVcmWxtIq7m4Y=", + "dev": true, + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz", + "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=", + "dev": true + }, + "underscore.string": { + "version": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.2.3.tgz", + "integrity": "sha1-gGmSYzZl1eX8tNsfs6hi62jp5to=", + "dev": true + } + } + }, + "grunt-mocha-test": { + "version": "https://registry.npmjs.org/grunt-mocha-test/-/grunt-mocha-test-0.13.2.tgz", + "integrity": "sha1-Dzq8xqtUNkex7/xatE69NwLwq4w=", + "dev": true + }, + "grunt-sass-globbing": { + "version": "https://registry.npmjs.org/grunt-sass-globbing/-/grunt-sass-globbing-1.5.1.tgz", + "integrity": "sha1-nmCVXNjLP0lt3QfPcc+UQFsjgtE=", + "dev": true + }, + "gzip-size": { + "version": "https://registry.npmjs.org/gzip-size/-/gzip-size-1.0.0.tgz", + "integrity": "sha1-Zs+LEBBHInuVus5uodoMF37Vwi8=", + "dev": true + }, + "har-schema": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", + "dev": true, + "optional": true + }, + "har-validator": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "dev": true, + "optional": true + }, + "has-ansi": { + "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true + }, + "has-flag": { + "version": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true, + "optional": true + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true, + "optional": true + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "hooker": { + "version": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", + "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", + "dev": true + }, + "hosted-git-info": { + "version": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.4.2.tgz", + "integrity": "sha1-AHa59GonBQbduq6lZJaJdGBhKmc=", + "dev": true + }, + "http-errors": { + "version": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.1.tgz", + "integrity": "sha1-X4uO2YrKVFZWv1cplzh/kEpyIlc=" + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", + "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=" + }, + "iltorb": { + "version": "https://registry.npmjs.org/iltorb/-/iltorb-1.2.1.tgz", + "integrity": "sha1-hqfJJF8GxRqL94L0YZTY+yYMLnE=", + "dev": true, + "optional": true + }, + "indent-string": { + "version": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true + }, + "inflight": { + "version": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true + }, + "inherits": { + "version": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", + "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", + "dev": true, + "optional": true + }, + "ipaddr.js": { + "version": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.3.0.tgz", + "integrity": "sha1-HgOlL9rYOou7KyXL9JmLTP/NPew=" + }, + "is-arrayish": { + "version": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-buffer": { + "version": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", + "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=" + }, + "is-builtin-module": { + "version": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true + }, + "is-finite": { + "version": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true + }, + "is-promise": { + "version": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true, + "optional": true + }, + "is-utf8": { + "version": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true, + "optional": true + }, + "jade": { + "version": "https://registry.npmjs.org/jade/-/jade-1.11.0.tgz", + "integrity": "sha1-nIDlOMEtP7lcjZu5VZ+gzAQEBf0=" + }, + "jquery": { + "version": "https://registry.npmjs.org/jquery/-/jquery-3.2.1.tgz", + "integrity": "sha1-XE2d5lKvbNCncBVKYxu6ErAVx4c=" + }, + "js-yaml": { + "version": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.5.5.tgz", + "integrity": "sha1-A3fDgBfKvHMisNH7zSWkkWQfL74=", + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true, + "optional": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "optional": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true, + "optional": true + }, + "json3": { + "version": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true, + "optional": true + }, + "jsprim": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz", + "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=", + "dev": true, + "optional": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "optional": true + } + } + }, + "jstransformer": { + "version": "https://registry.npmjs.org/jstransformer/-/jstransformer-0.0.2.tgz", + "integrity": "sha1-eq4pqQPRls+glz2IXT5HlH7Ndqs=" + }, + "keygrip": { + "version": "https://registry.npmjs.org/keygrip/-/keygrip-1.0.1.tgz", + "integrity": "sha1-sC+kgW7vIajEs1yp5Skh/8iaMOk=" + }, + "kind-of": { + "version": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.0.tgz", + "integrity": "sha1-tYq+TVwEStM3JqjBUltIz4kb/wc=" + }, + "lazy-cache": { + "version": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" + }, + "lazystream": { + "version": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "dev": true + }, + "livereload-js": { + "version": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.2.2.tgz", + "integrity": "sha1-bIclfmSKtHW8JOoldFftzB+NC8I=", + "dev": true + }, + "load-json-file": { + "version": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", + "dev": true + }, + "lodash._baseassign": { + "version": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "dev": true + }, + "lodash._basecopy": { + "version": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basecreate": { + "version": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", + "dev": true + }, + "lodash._getnative": { + "version": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash.create": { + "version": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "dev": true + }, + "lodash.isarguments": { + "version": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.keys": { + "version": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true + }, + "lolex": { + "version": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz", + "integrity": "sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=", + "dev": true + }, + "longest": { + "version": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" + }, + "loud-rejection": { + "version": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true + }, + "lru-cache": { + "version": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "dev": true + }, + "map-obj": { + "version": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "marked": { + "version": "https://registry.npmjs.org/marked/-/marked-0.3.6.tgz", + "integrity": "sha1-ssbGGPzOzk74bE/Gy4p8v1rtqNc=" + }, + "maxmin": { + "version": "https://registry.npmjs.org/maxmin/-/maxmin-1.1.0.tgz", + "integrity": "sha1-cTZehKmd2Piz99X94vANHn9zvmE=", + "dev": true, + "dependencies": { + "pretty-bytes": { + "version": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", + "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=", + "dev": true + } + } + }, + "media-typer": { + "version": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "meow": { + "version": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true + }, + "merge-descriptors": { + "version": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", + "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=" + }, + "mime-db": { + "version": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", + "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=" + }, + "mime-types": { + "version": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", + "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=" + }, + "minimatch": { + "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=", + "dev": true + }, + "minimist": { + "version": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "mkdirp": { + "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dependencies": { + "minimist": { + "version": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "mocha": { + "version": "https://registry.npmjs.org/mocha/-/mocha-3.3.0.tgz", + "integrity": "sha1-0pt0KNP1LILi5l3x7LcGThqrv7U=", + "dev": true, + "dependencies": { + "commander": { + "version": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true + }, + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.6.0.tgz", + "integrity": "sha1-vFlryr52F/Edn6FTYe3tVgi4SZs=", + "dev": true + }, + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "dev": true + }, + "supports-color": { + "version": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "dev": true + } + } + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" + }, + "nan": { + "version": "https://registry.npmjs.org/nan/-/nan-2.6.2.tgz", + "integrity": "sha1-5P805slf37WuzAjeZZb0NgWn20U=", + "dev": true, + "optional": true + }, + "native-promise-only": { + "version": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", + "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=", + "dev": true + }, + "negotiator": { + "version": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "node-pre-gyp": { + "version": "0.6.36", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz", + "integrity": "sha1-22BBEst04NR3VU6bUFsXq936t4Y=", + "dev": true, + "optional": true, + "dependencies": { + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "dev": true, + "optional": true + }, + "rimraf": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "dev": true, + "optional": true + } + } + }, + "nopt": { + "version": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true + }, + "normalize-package-data": { + "version": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.8.tgz", + "integrity": "sha1-2Bntoqne29H/pWPqQHHZNngilbs=", + "dev": true + }, + "normalize-path": { + "version": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "optional": true + }, + "number-is-nan": { + "version": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true, + "optional": true + }, + "object-assign": { + "version": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-keys": { + "version": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", + "dev": true + }, + "object.assign": { + "version": "https://registry.npmjs.org/object.assign/-/object.assign-4.0.4.tgz", + "integrity": "sha1-scnMBE7xuf5jYG/BQau7MuFHMMw=", + "dev": true + }, + "on-finished": { + "version": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=" + }, + "on-headers": { + "version": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", + "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=" + }, + "once": { + "version": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true + }, + "optimist": { + "version": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "integrity": "sha1-yQlBrVnkJzMokjB00s8ufLxuwNk=" + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz", + "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=", + "dev": true, + "optional": true + }, + "pako": { + "version": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=", + "dev": true + }, + "parse-json": { + "version": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true + }, + "parseurl": { + "version": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz", + "integrity": "sha1-yKuMkiO6NIiKpkopeyiFO+wY2lY=" + }, + "path-exists": { + "version": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true + }, + "path-is-absolute": { + "version": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-to-regexp": { + "version": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "path-type": { + "version": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true + }, + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", + "dev": true, + "optional": true + }, + "pify": { + "version": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true + }, + "pretty-bytes": { + "version": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-3.0.1.tgz", + "integrity": "sha1-J9AAjXeAY6C0gRuzXHnxvV1fvM8=", + "dev": true + }, + "process-nextick-args": { + "version": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "promise": { + "version": "https://registry.npmjs.org/promise/-/promise-6.1.0.tgz", + "integrity": "sha1-LOcp9rlLRcJoka0GAsXJDgTG7vY=" + }, + "proxy-addr": { + "version": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.4.tgz", + "integrity": "sha1-J+VF9pYKRKYn2bREZ+NcG2tM4vM=" + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true, + "optional": true + }, + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" + }, + "random-bytes": { + "version": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" + }, + "range-parser": { + "version": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "https://registry.npmjs.org/raw-body/-/raw-body-2.2.0.tgz", + "integrity": "sha1-mUl2z2pQlqQRYoQEkvC9xdbn+5Y=" + }, + "rc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.1.tgz", + "integrity": "sha1-LgPo5C7kULjLPc5lvhv4l04d/ZU=", + "dev": true, + "optional": true + }, + "read-pkg": { + "version": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true + }, + "read-pkg-up": { + "version": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true + }, + "readable-stream": { + "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz", + "integrity": "sha1-z3jsb0ptHrQ9JkiMrJfwQudLf8g=", + "dev": true + }, + "redent": { + "version": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true + }, + "remove-trailing-separator": { + "version": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz", + "integrity": "sha1-YV67lq9VlVLUv0BXyENtSGq2PMQ=", + "dev": true + }, + "repeat-string": { + "version": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "repeating": { + "version": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true + }, + "request": { + "version": "2.81.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "dev": true, + "optional": true + }, + "resolve": { + "version": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + }, + "right-align": { + "version": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=" + }, + "rimraf": { + "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "dev": true + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "samsam": { + "version": "https://registry.npmjs.org/samsam/-/samsam-1.2.1.tgz", + "integrity": "sha1-7dOQk6MYQ3DLhZJDsr3yVefY6mc=", + "dev": true + }, + "sass": { + "version": "https://registry.npmjs.org/sass/-/sass-0.5.0.tgz", + "integrity": "sha1-ne4Rg6D0ADYfLF00U78uVHBeA/k=", + "dev": true + }, + "semver": { + "version": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + }, + "send": { + "version": "https://registry.npmjs.org/send/-/send-0.15.1.tgz", + "integrity": "sha1-igI1TCbm9cynAAZfXwzeupDse18=" + }, + "serve-static": { + "version": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.1.tgz", + "integrity": "sha1-dEOpZePO1kes61Y5+ga/TRu+ADk=" + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true, + "optional": true + }, + "setprototypeof": { + "version": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + }, + "signal-exit": { + "version": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "sinon": { + "version": "https://registry.npmjs.org/sinon/-/sinon-2.2.0.tgz", + "integrity": "sha1-OxtC/13vy/UaUqYqym1hFxuf0mI=", + "dev": true, + "dependencies": { + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "path-to-regexp": { + "version": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "dev": true + }, + "type-detect": { + "version": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.3.tgz", + "integrity": "sha1-Dj8mcLRAmbC0bChNE2p+9Jx0wuo=", + "dev": true + } + } + }, + "sinon-chai": { + "version": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-2.10.0.tgz", + "integrity": "sha1-arMAi7jK6ZKedE12ZXS0zzXzS1s=", + "dev": true + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true, + "optional": true + }, + "source-map": { + "version": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=" + }, + "spdx-correct": { + "version": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "dev": true + }, + "spdx-expression-parse": { + "version": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", + "dev": true + }, + "spdx-license-ids": { + "version": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", + "dev": true + }, + "sprintf-js": { + "version": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "dev": true, + "optional": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "optional": true + } + } + }, + "statuses": { + "version": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + }, + "stream-buffers": { + "version": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", + "integrity": "sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ=", + "dev": true + }, + "string_decoder": { + "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.0.tgz", + "integrity": "sha1-8G9BFXtmTYYGn4S9vcmw2KsoFmc=", + "dev": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "dev": true, + "optional": true + }, + "strip-ansi": { + "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true + }, + "strip-bom": { + "version": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true + }, + "strip-indent": { + "version": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "optional": true + }, + "supports-color": { + "version": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "tar": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "dev": true + }, + "tar-pack": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.4.0.tgz", + "integrity": "sha1-I74tf2cagzk3bL2wuP4/3r8xeYQ=", + "dev": true, + "optional": true, + "dependencies": { + "rimraf": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "dev": true, + "optional": true + } + } + }, + "tar-stream": { + "version": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.2.tgz", + "integrity": "sha1-+8bG6DwaGdTLSMfZYXH8JI7/x78=", + "dev": true + }, + "text-encoding": { + "version": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", + "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", + "dev": true + }, + "through2": { + "version": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "dev": true + }, + "tiny-lr": { + "version": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-0.2.1.tgz", + "integrity": "sha1-s/26gC5dVqM8L28QeUsy5Hescp0=", + "dev": true, + "dependencies": { + "body-parser": { + "version": "https://registry.npmjs.org/body-parser/-/body-parser-1.14.2.tgz", + "integrity": "sha1-EBXLH+LEQ4WCWVgdtTMy+NDPUPk=", + "dev": true, + "dependencies": { + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz", + "integrity": "sha1-qfMRQq9GjLcrJbMBNrokVoNJFr4=", + "dev": true + } + } + }, + "bytes": { + "version": "https://registry.npmjs.org/bytes/-/bytes-2.2.0.tgz", + "integrity": "sha1-/TVGSkA/b5EXwt42Cez/nK4ABYg=", + "dev": true + }, + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true + }, + "http-errors": { + "version": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz", + "integrity": "sha1-GX4izevUGYWF6GlO9nhhl7ke2UI=", + "dev": true + }, + "iconv-lite": { + "version": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", + "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=", + "dev": true + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + }, + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-5.1.0.tgz", + "integrity": "sha1-TZMuXH6kEcynajEtOaYGIA/VDNk=", + "dev": true + }, + "raw-body": { + "version": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz", + "integrity": "sha1-rf6s4uT7MJgFgBTQjActzFl1h3Q=", + "dev": true, + "dependencies": { + "bytes": { + "version": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", + "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=", + "dev": true + } + } + } + } + }, + "tough-cookie": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", + "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", + "dev": true, + "optional": true + }, + "transformers": { + "version": "https://registry.npmjs.org/transformers/-/transformers-2.1.0.tgz", + "integrity": "sha1-XSPLNVYd2F3Gf7hIIwm0fVPM6ac=", + "dependencies": { + "is-promise": { + "version": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz", + "integrity": "sha1-MVc3YcBX4zwukaq56W2gjO++duU=" + }, + "promise": { + "version": "https://registry.npmjs.org/promise/-/promise-2.0.0.tgz", + "integrity": "sha1-RmSKqdYFr10ucMMCS/WUNtoCuA4=" + }, + "source-map": { + "version": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=" + }, + "uglify-js": { + "version": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.2.5.tgz", + "integrity": "sha1-puAqcNg5eSuXgEiLe4sYTAlcmcc=" + } + } + }, + "trim-newlines": { + "version": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "optional": true + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, + "type-detect": { + "version": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", + "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=", + "dev": true + }, + "type-is": { + "version": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", + "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=" + }, + "typedarray": { + "version": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "uglify-js": { + "version": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.22.tgz", + "integrity": "sha1-1Uk0d4qNoUkD+imjJvskwKtRoaA=", + "dependencies": { + "source-map": { + "version": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=" + } + } + }, + "uglify-to-browserify": { + "version": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", + "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=", + "dev": true, + "optional": true + }, + "uid-safe": { + "version": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.4.tgz", + "integrity": "sha1-Otbzg2jG1MjHXsF2I/t5qh0HHYE=" + }, + "underscore": { + "version": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" + }, + "underscore.inflections": { + "version": "https://registry.npmjs.org/underscore.inflections/-/underscore.inflections-0.2.1.tgz", + "integrity": "sha1-EBvTWeAq8pOqWhBidI6WPiCHZ/E=" + }, + "underscore.string": { + "version": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.4.tgz", + "integrity": "sha1-LCo/n4PmR2L9xF5s6sZRQoZCE9s=" + }, + "unpipe": { + "version": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "uri-path": { + "version": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", + "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=", + "dev": true + }, + "util-deprecate": { + "version": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", + "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" + }, + "uuid": { + "version": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz", + "integrity": "sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE=", + "dev": true, + "optional": true + }, + "validate-npm-package-license": { + "version": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "dev": true + }, + "vary": { + "version": "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz", + "integrity": "sha1-Z1Neu2lMHVIldFeYRmUyP1h+jTc=" + }, + "verror": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", + "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", + "dev": true, + "optional": true + }, + "void-elements": { + "version": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" + }, + "walkdir": { + "version": "https://registry.npmjs.org/walkdir/-/walkdir-0.0.11.tgz", + "integrity": "sha1-oW0CXrkxvQO1LzCMrtD0D86+lTI=", + "dev": true + }, + "websocket-driver": { + "version": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz", + "integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=", + "dev": true + }, + "websocket-extensions": { + "version": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz", + "integrity": "sha1-domUmcGEtu91Q3fC27DNbLVdKec=", + "dev": true + }, + "when": { + "version": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", + "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=" + }, + "which": { + "version": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "dev": true + }, + "wide-align": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", + "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "dev": true, + "optional": true + }, + "window-size": { + "version": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" + }, + "with": { + "version": "https://registry.npmjs.org/with/-/with-4.0.3.tgz", + "integrity": "sha1-7v0VTp550sjTQXtkeo8U2f7M4U4=", + "dependencies": { + "acorn": { + "version": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz", + "integrity": "sha1-yM4n3grMdtiW0rH6099YjZ6C8BQ=" + } + } + }, + "wordwrap": { + "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + }, + "wrappy": { + "version": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xtend": { + "version": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "yargs": { + "version": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dependencies": { + "camelcase": { + "version": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" + } + } + }, + "zip-stream": { + "version": "https://registry.npmjs.org/zip-stream/-/zip-stream-1.1.1.tgz", + "integrity": "sha1-Uha0i7tNJlH2TVxubwnrSnOZ1Vc=", + "dev": true, + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + } + } +} diff --git a/package.json b/package.json index 52eb08857..b62a407e2 100644 --- a/package.json +++ b/package.json @@ -48,4 +48,3 @@ "when": "3.7.8" } } - diff --git a/src/client/site/craft_page/craft_page_controller.coffee b/src/client/site/craft_page/craft_page_controller.coffee index db4390b67..12d1e953b 100644 --- a/src/client/site/craft_page/craft_page_controller.coffee +++ b/src/client/site/craft_page/craft_page_controller.coffee @@ -166,21 +166,21 @@ module.exports = class CraftPageController extends PageController controller.markComplete @model.have _isAddingToolsPossible: (controller)-> - tools = controller.model.recipe.tools + tools = (item for itemId, item of controller.model.recipe.tools) return false unless tools.length > 0 have = @model.have want = @model.want - for stack in tools - return false if @model.have.contains stack.item.id - return false if @model.want.contains stack.item.id + for item in tools + return false if @model.have.contains item + return false if @model.want.contains item return true _isStepCompletable: (controller)-> - wantsOutput = @model.want.contains controller.model.recipe.output.item.id - return wantsOutput + userWantsItem = @model.want.contains controller.model.recipe.output.item + return not userWantsItem _refreshOutdated: -> if @model.isOutdated diff --git a/src/client/site/craft_page/step/step_controller.coffee b/src/client/site/craft_page/step/step_controller.coffee index f5d364860..020eff516 100644 --- a/src/client/site/craft_page/step/step_controller.coffee +++ b/src/client/site/craft_page/step/step_controller.coffee @@ -43,11 +43,12 @@ module.exports = class StepController extends BaseController # Event Methods ################################################################################ onCompleteButtonClicked: (event)-> - return if @$completeButton.hasClass 'disabled' + return false if @$completeButton.hasClass 'disabled' tracker.trackEvent c.tracking.category.craft, 'mark-complete', null, @model.count @onComplete this onShowToolPlan: (event)-> + return false if @$toolButton.hasClass 'disabled' tracker.trackEvent c.tracking.category.navigate, 'show-tool-plan', @$toolButton.attr 'target' return true @@ -97,13 +98,13 @@ module.exports = class StepController extends BaseController events: -> return _.extend super, 'click .button.complete': 'onCompleteButtonClicked' - 'click a.button.tool': 'onShowToolPlan' + 'click .button.tool': 'onShowToolPlan' # Private Methods ############################################################################## _refreshToolButton: -> inventory = new Inventory - for itemId, item in @model.recipe.tools + for itemId, item of @model.recipe.tools inventory.add item inventoryText = inventory.toUrlString() From ccb2cad516ac9244506bca87ddabe5424f05c346 Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Tue, 11 Jul 2017 09:58:56 -0700 Subject: [PATCH 11/21] Fix search box to return better results --- src/client/models/site/item_selector.coffee | 13 +++++++------ src/client/site/header/header_controller.coffee | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/client/models/site/item_selector.coffee b/src/client/models/site/item_selector.coffee index 00c07a1a2..7e77ee3c0 100644 --- a/src/client/models/site/item_selector.coffee +++ b/src/client/models/site/item_selector.coffee @@ -65,8 +65,6 @@ module.exports = class ItemSelector extends Observable nextScore = 1 return 0 if hintIndex < @_hint.length - - totalScore *= @_hint.length / name.length return totalScore _refreshResults: -> @@ -79,10 +77,8 @@ module.exports = class ItemSelector extends Observable return unless mod.isEnabled for itemId, item of mod.items - return if scoredItems.length >= @_maxResults - score = @_computeScore item - if score >= @_hint.length + if score > 0 scoredItems.push score:score, item:item scoredItems.sort (a, b)-> @@ -99,5 +95,10 @@ module.exports = class ItemSelector extends Observable return 0 - @_results = (e.item for e in scoredItems) + @_results = [] + for element in scoredItems + @_results.push element.item + break if @_results.length >= @_maxResults + @trigger c.event.change + ':results', this + diff --git a/src/client/site/header/header_controller.coffee b/src/client/site/header/header_controller.coffee index 107cdffa2..2c9ca71a8 100644 --- a/src/client/site/header/header_controller.coffee +++ b/src/client/site/header/header_controller.coffee @@ -55,7 +55,7 @@ module.exports = class HeaderController extends BaseController @_selector.launch hint .then (item)=> if not item? - tracker.trackEvent c.tracking.category.search, 'cancel', item.slug + tracker.trackEvent c.tracking.category.search, 'cancel' return tracker.trackEvent c.tracking.category.search, 'complete', item.slug From dac1a8dceb8a15641391fa0a15c31e5e0e7d0b06 Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Tue, 11 Jul 2017 14:24:13 -0700 Subject: [PATCH 12/21] Ensure changing quantities outdates plans --- src/client/models/site/craft_page.coffee | 1 + src/client/site/craft_page/craft_page_controller.coffee | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/models/site/craft_page.coffee b/src/client/models/site/craft_page.coffee index 087b98f0d..30c2b0c1d 100644 --- a/src/client/models/site/craft_page.coffee +++ b/src/client/models/site/craft_page.coffee @@ -90,4 +90,5 @@ module.exports = class CraftPage extends Observable _onWantChanged: -> @triggerPropertyChange "isDirty", @_isDirty, true, -> + @_isDirty = true if @want.isEmpty then @triggerPropertyChange "currentPlan", @_currentPlan, null diff --git a/src/client/site/craft_page/craft_page_controller.coffee b/src/client/site/craft_page/craft_page_controller.coffee index 12d1e953b..d292a51d5 100644 --- a/src/client/site/craft_page/craft_page_controller.coffee +++ b/src/client/site/craft_page/craft_page_controller.coffee @@ -52,7 +52,6 @@ module.exports = class CraftPageController extends PageController onRemoveFromWant: (item)-> @model.want.remove item - @onWantInventoryChanged() onSampleClicked: (event)-> $el = $(event.target) From ab96166601afb9456e7a67a04e2d87128fa76484 Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Thu, 13 Jul 2017 16:52:51 -0400 Subject: [PATCH 13/21] Add missing detail data to item pages --- src/client/client.coffee | 60 ++++++++++--------- src/client/models/site/item_display.coffee | 2 +- src/client/models/site/item_page.coffee | 14 +++++ .../site/common/video/video_controller.coffee | 13 ++-- .../item_page/item_page_controller.coffee | 11 ++-- src/client/site/router.coffee | 2 + src/server/crafting_guide_server.coffee | 1 + src/server/middleware.coffee | 2 +- 8 files changed, 63 insertions(+), 42 deletions(-) diff --git a/src/client/client.coffee b/src/client/client.coffee index 67822d11f..ebf5d2286 100644 --- a/src/client/client.coffee +++ b/src/client/client.coffee @@ -8,81 +8,83 @@ ############################################################################################################ # Allow Node.js-style `global` in addition to `window` -if typeof(global) is 'undefined' +if typeof(global) is "undefined" window.global = window -global._ = require '../common/underscore' -global.$ = require 'jquery' -global.c = require '../common/constants' +global._ = require "../common/underscore" +global.$ = require "jquery" +global.c = require "../common/constants" global.π = Math.PI global.ε = 0.0001 -global.w = require 'when' +global.w = require "when" -{Logger} = require('crafting-guide-common').util +{Logger} = require("crafting-guide-common").util global.logger = new Logger -Tracker = require './tracker' +Tracker = require "./tracker" global.tracker = new Tracker -marked = require 'marked' +marked = require "marked" marked.setOptions sanitize:true -global.Backbone = Backbone = require 'backbone' +global.Backbone = Backbone = require "backbone" Backbone.$ = $ ######################################################################################################################## global.hostName = window.location.hostname switch global.hostName - when 'prerender.crafting-guide.com' - global.env = 'prerender' + when "prerender.crafting-guide.com" + global.env = "prerender" logger.level = Logger.FATAL - apiBaseUrl = 'http://prerender.crafting-guide.com:4347' - when 'local.crafting-guide.com', 'localhost' - global.env = 'local' + apiBaseUrl = "http://prerender.crafting-guide.com:4347" + when "local.crafting-guide.com", "localhost" + global.env = "local" logger.level = Logger.DEBUG apiBaseUrl = "http://#{global.hostName}:4347" - when 'staging.crafting-guide.com' - global.env = 'staging' + when "staging.crafting-guide.com" + global.env = "staging" logger.level = Logger.VERBOSE - apiBaseUrl = 'http://api-staging.crafting-guide.com' - when 'crafting-guide.com' - global.env = 'production' + apiBaseUrl = "http://api-staging.crafting-guide.com" + when "crafting-guide.com" + global.env = "production" logger.level = Logger.INFO tracker.enabled = true - apiBaseUrl = 'http://api.crafting-guide.com' + apiBaseUrl = "http://api.crafting-guide.com" else throw new Error "cannot determine the environment of: #{window.location.hostname}" ######################################################################################################################## -Storage = require './storage' +Storage = require "./storage" storage = new Storage storage:global.localStorage ######################################################################################################################## tracker.trackPageView() -{CraftingGuideClient} = require('crafting-guide-common').api +{CraftingGuideClient} = require("crafting-guide-common").api client = _(new CraftingGuideClient(baseUrl:apiBaseUrl)).extend Backbone.Events client.onStatusChanged = (client, oldStatus, newStatus)-> logger.info "Crafting Guide server status changed from #{oldStatus} to #{newStatus}" - client.trigger 'change:status', client, oldStatus, newStatus - client.trigger 'change', client + client.trigger "change:status", client, oldStatus, newStatus + client.trigger "change", client client.startMonitoringStatus() ######################################################################################################################## -{http, ModPackStore} = require("crafting-guide-common").api -modPackBaseUrl = "#{location.protocol}//#{location.hostname}:#{location.port}" -modPackStore = new ModPackStore http, modPackBaseUrl +{http, ModPackStore, ItemDetailStore} = require("crafting-guide-common").api +storeOptions = http:http, baseUrl:"#{location.protocol}//#{location.hostname}:#{location.port}" +global.stores = + modPack: new ModPackStore storeOptions + itemDetail: new ItemDetailStore storeOptions ######################################################################################################################## -modPackStore.load c.modPacks.default +global.stores.modPack.load c.modPacks.default .then (modPack)-> - SiteController = require './site/site_controller' + SiteController = require "./site/site_controller" global.site = site = new SiteController client:client, storage:storage, modPack:modPack site.render() site.loadCurrentUser() diff --git a/src/client/models/site/item_display.coffee b/src/client/models/site/item_display.coffee index afa5a61db..a35582e0f 100644 --- a/src/client/models/site/item_display.coffee +++ b/src/client/models/site/item_display.coffee @@ -1,5 +1,5 @@ # -# Crafting Guide - item_page.coffee +# Crafting Guide - item_display.coffee # # Copyright © 2014-2017 by Redwood Labs # All rights reserved. diff --git a/src/client/models/site/item_page.coffee b/src/client/models/site/item_page.coffee index 5bbd62b9f..88fcba6ba 100644 --- a/src/client/models/site/item_page.coffee +++ b/src/client/models/site/item_page.coffee @@ -27,7 +27,9 @@ module.exports = class ItemPage extends Observable set: (item)-> if @_item? then throw new Error "item cannot be reassigned" if not item? then throw new Error "item is required" + if @_item? then @_item.off Observable::ANY, this @_item = item + @_item.on Observable::ANY, this, "_onItemChanged" itemDisplay: get: -> return @_itemDisplay ?= new ItemDisplay @item @@ -60,6 +62,14 @@ module.exports = class ItemPage extends Observable return @_findItemsWithMatchingRecipes (recipe)=> return recipe.tools[@item.id]? + loadDetails: -> + stores.itemDetail.loadDetailFor @item + .catch (error)=> + if error.message.indexOf("404") is -1 + logger.error "Could not load details for item #{@item.id}: #{error.message}" + else + logger.info "Item #{@item.id} has no details file." + # Private Methods ############################################################################## _findItemsWithMatchingRecipes: (isMatching)-> @@ -79,3 +89,7 @@ module.exports = class ItemPage extends Observable return a.displayName.localeCompare b.displayName return result + + _onItemChanged: -> + @trigger Observable::CHANGE + diff --git a/src/client/site/common/video/video_controller.coffee b/src/client/site/common/video/video_controller.coffee index f4f72bdab..4d675fa12 100644 --- a/src/client/site/common/video/video_controller.coffee +++ b/src/client/site/common/video/video_controller.coffee @@ -5,30 +5,31 @@ # All rights reserved. # -BaseController = require '../../base_controller' +BaseController = require "../../base_controller" ######################################################################################################################## module.exports = class VideoController extends BaseController constructor: (options={})-> - if not options.model? then throw new Error 'options.model is required' - options.templateName = 'common/video' + if not options.model? then throw new Error "options.model is required" + options.templateName = "common/video" super options # BaseController Overrides ##################################################################### onDidRender: -> - @$iframe = @$('iframe') - @$caption = @$('.caption p') + @$iframe = @$("iframe") + @$caption = @$(".caption p") super refresh: -> @$caption.html @model.name - @$iframe.attr 'src', @_createYouTubeUrl() + @$iframe.attr "src", @_createYouTubeUrl() super # Private ###################################################################################### _createYouTubeUrl: -> return "http://www.youtube.com/embed/#{@model.youTubeId}?modestbranding=1&autohide=1&showinfo=0" + diff --git a/src/client/site/item_page/item_page_controller.coffee b/src/client/site/item_page/item_page_controller.coffee index 8cbce16a3..ce2fc8b63 100644 --- a/src/client/site/item_page/item_page_controller.coffee +++ b/src/client/site/item_page/item_page_controller.coffee @@ -119,8 +119,8 @@ module.exports = class ItemPageController extends PageController @_descriptionController.imageBase = c.url.itemImageDir @model.itemDisplay - if @model.item.officialUrl? - @$officialLink.attr 'href', @model.item.officialUrl + if @model.item.detail?.links.length > 0 + @$officialLink.attr 'href', @model.item.detail.links[0] @show @$aboutLinks else @hide @$aboutLinks @@ -217,8 +217,8 @@ module.exports = class ItemPageController extends PageController throw e _refreshDescription: -> - if @model.item?.description?.length > 0 - @_descriptionController.model = @model.item.description + if @model.item.detail?.description.length > 0 + @_descriptionController.model = @model.item.detail.description @_descriptionController.resetToDefaultState() _refreshMultiblock: -> @@ -284,7 +284,7 @@ module.exports = class ItemPageController extends PageController @_videoControllers ?= [] index = 0 - videos = @model?.item?.videos or [] + videos = @model.item.detail?.videos if videos? and videos.length > 0 @$videosSectionTitle.html if videos.length is 1 then 'Video' else 'Videos' @@ -305,3 +305,4 @@ module.exports = class ItemPageController extends PageController while @_videoControllers.length > index @_videoControllers.pop().remove() + diff --git a/src/client/site/router.coffee b/src/client/site/router.coffee index 39783e41f..74e3412f3 100644 --- a/src/client/site/router.coffee +++ b/src/client/site/router.coffee @@ -103,6 +103,8 @@ module.exports = class Router extends Backbone.Router if not item? then throw new Error "could not find item #{modId}__#{itemSlug}" itemPage = new ItemPage item + itemPage.loadDetails() + params = new UrlParams login:{type:'boolean', default:false} controller = new ItemPageController @_makeOptions {model:itemPage, login:params.login} @_siteController.setPage 'browseModItem', controller diff --git a/src/server/crafting_guide_server.coffee b/src/server/crafting_guide_server.coffee index 3b8cd6423..296e87ba6 100644 --- a/src/server/crafting_guide_server.coffee +++ b/src/server/crafting_guide_server.coffee @@ -41,3 +41,4 @@ module.exports = class CraftingGuideServer console.log "CraftingGuide is shutting down" @httpServer.close() => resolve this + diff --git a/src/server/middleware.coffee b/src/server/middleware.coffee index 200ec9ad1..1887df898 100644 --- a/src/server/middleware.coffee +++ b/src/server/middleware.coffee @@ -26,7 +26,7 @@ exports.installBefore = (app)-> ] exports.installAfter = (app)-> - app.use '/data', express.static '../../crafting-guide-data/data/', etag:false, maxAge: 0 + app.use '/data', express.static '/src/crafting-guide/data/data/', etag:false, maxAge: 0 app.use express.static './static', etag: false, maxAge: 0 # Middleware Functions ##################################################################################### From 89ba3ac48e2b4bdcdf161318389893e4d2af00a6 Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Sun, 16 Jul 2017 04:58:16 -0400 Subject: [PATCH 14/21] Fix support for multiblock recipes --- src/client/models/site/item_page.coffee | 5 +- .../models/site/multiblock_display.coffee | 53 +++++++++++++++ .../multiblock/multiblock_controller.coffee | 44 ++++++------- .../multiblock_viewer_controller.coffee | 65 ++++++++++--------- 4 files changed, 114 insertions(+), 53 deletions(-) create mode 100644 src/client/models/site/multiblock_display.coffee diff --git a/src/client/models/site/item_page.coffee b/src/client/models/site/item_page.coffee index 88fcba6ba..b0c62ccd8 100644 --- a/src/client/models/site/item_page.coffee +++ b/src/client/models/site/item_page.coffee @@ -48,8 +48,11 @@ module.exports = class ItemPage extends Observable return @_findItemsWithMatchingRecipes (recipe)=> recipe.computeQuantityRequired @item + findMultiblockRecipes: -> + return (recipe for recipeId, recipe of @item.recipes when recipes.depth > 1) + findRecipes: -> - return (recipe for recipeId, recipe of @item.recipes) + return (recipe for recipeId, recipe of @item.recipes when recipe.depth is 1) findSimilarItems: -> group = @mod.itemGroups[@item.groupName] diff --git a/src/client/models/site/multiblock_display.coffee b/src/client/models/site/multiblock_display.coffee new file mode 100644 index 000000000..64df5b37d --- /dev/null +++ b/src/client/models/site/multiblock_display.coffee @@ -0,0 +1,53 @@ +# +# Crafting Guide - multiblock_display.coffee +# +# Copyright © 2014-2017 by Redwood Labs +# All rights reserved. +# + +{Inventory} = require("crafting-guide-common").models +{Observable} = require("crafting-guide-common").util + +######################################################################################################################## + +module.exports = class MultiblockDisplay extends Observable + + constructor: (recipe)-> + @_layerInventories = [] + @recipe = recipe + + # Properties ################################################################################### + + Object.defineProperties @prototype, + + recipe: + get: -> return @_recipe + set: (recipe)-> + if not recipe? then throw new Error "recipe is required" + if @_recipe? then throw new Error "recipe cannot be reassigned" + @_recipe = recipe + + # Public Methods ############################################################################### + + getInventory: (z)-> + if not z? + return @_fullInventory ?= @_createFullInventory() + else + return @_layerInventories[z] ?= @_addLayerInventory z + + # Private Methods ############################################################################## + + _addLayerInventory: (z, inventory=null)-> + inventory ?= new Inventory + for x in [0..@recipe.width] + for y in [0..@recipe.height] + stack = @recipe.getInputAt x, y, z + continue unless stack? + inventory.add stack.item, stack.quantity + return inventory + + _createFullInventory: (inventory=null)-> + inventory ?= new Inventory() + for z in [0..@recipe.depth] + @_addLayerInventory z, inventory + return inventory diff --git a/src/client/site/item_page/multiblock_viewer/multiblock/multiblock_controller.coffee b/src/client/site/item_page/multiblock_viewer/multiblock/multiblock_controller.coffee index 5829784bc..51e11991e 100644 --- a/src/client/site/item_page/multiblock_viewer/multiblock/multiblock_controller.coffee +++ b/src/client/site/item_page/multiblock_viewer/multiblock/multiblock_controller.coffee @@ -1,11 +1,11 @@ -### -Crafting Guide - multiblock_controller.coffee +# +# Crafting Guide - multiblock_controller.coffee +# +# Copyright (c) 2014-2017 by Redwood Labs +# All rights reserved. +# -Copyright (c) 2014-2015 by Redwood Labs -All rights reserved. -### - -BaseController = require '../../../base_controller' +BaseController = require "../../../base_controller" ItemDisplay = require "../../../../models/site/item_display" ######################################################################################################################## @@ -26,9 +26,9 @@ module.exports = class MultiblockController extends BaseController @::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' + 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 @@ -64,11 +64,11 @@ module.exports = class MultiblockController extends BaseController # BaseController Overrides ##################################################################### onDidRender: -> - @$outline = @$('.outline') + @$outline = @$(".outline") super refresh: -> - @$el.css 'height':@_computeMinHeight(), 'width':@_computeMinWidth() + @$el.css "height":@_computeMinHeight(), "width":@_computeMinWidth() @_refreshBlockCache() @_refreshAllBlocks() @@ -77,7 +77,7 @@ module.exports = class MultiblockController extends BaseController # Private Methods ############################################################################## _computePosition: (x, y, z, options={})-> - if not @model? then return left:0, top:-@IMAGE_SIZE, 'z-index':0, opacity:0.0 + if not @model? then return left:0, top:-@IMAGE_SIZE, "z-index":0, opacity:0.0 options.hideUpperLayers ?= false pxWidth = @$el.width() @@ -94,7 +94,7 @@ module.exports = class MultiblockController extends BaseController zindex = ((@model.width - x) + (@model.depth - z) + ((@model.width * @model.depth) * y)) * 2 - return left:left, top:top, 'z-index':zindex, opacity:opacity + return left:left, top:top, "z-index":zindex, opacity:opacity _computeMinHeight: -> return 0 unless @model? @@ -131,14 +131,14 @@ module.exports = class MultiblockController extends BaseController for z in [0...@model.depth] @_blockCache[x][y][z] ?= null - for el in @$('.block') + for el in @$(".block") $el = $(el) - @_blockCache[$el.data('x')][$el.data('y')][$el.data('z')] = $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 + stack = @model.getInputAt x, y, z $block = @_blockCache[x][y][z] position = @_computePosition x, y, z, hideUpperLayers:true move = false @@ -147,7 +147,7 @@ module.exports = class MultiblockController extends BaseController itemDisplay = new ItemDisplay stack.item if not $block? - $block = $("#{itemDisplay.itemName}") + $block = $("\"#{itemDisplay.itemName}\"") $block.css position, top:-@IMAGE_SIZE, opacity:0.0 @_registerHoverHandlers $block, y, itemDisplay @_imageLoader.load itemDisplay.iconUrl, $block @@ -155,10 +155,10 @@ module.exports = class MultiblockController extends BaseController @$el.append $block move = true else - $block.attr 'src', itemDisplay.iconUrl + $block.attr "src", itemDisplay.iconUrl move = true else if $block? - $block.attr 'src', '' + $block.attr "src", "" move = true if move then _.delay (-> $block.css position), @_randomDropDelay() @@ -175,10 +175,10 @@ module.exports = class MultiblockController extends BaseController _registerHoverHandlers: ($el, y, itemDisplay)-> startHovering = => return unless y is @_currentLayer - zIndex = parseInt($el.css('z-index')) + 1 + 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 + @$outline.css opacity:1.0, top:$el.css("top"), left:$el.css("left"), "z-index":zIndex @_onHovering itemDisplay if @_hoverTimer? then clearTimeout @_hoverTimer diff --git a/src/client/site/item_page/multiblock_viewer/multiblock_viewer_controller.coffee b/src/client/site/item_page/multiblock_viewer/multiblock_viewer_controller.coffee index 068118934..8d993bab1 100644 --- a/src/client/site/item_page/multiblock_viewer/multiblock_viewer_controller.coffee +++ b/src/client/site/item_page/multiblock_viewer/multiblock_viewer_controller.coffee @@ -5,19 +5,20 @@ # All rights reserved. # -BaseController = require '../../base_controller' -InventoryController = require '../../common/inventory/inventory_controller' -MultiblockController = require './multiblock/multiblock_controller' +BaseController = require "../../base_controller" +InventoryController = require "../../common/inventory/inventory_controller" +MultiblockController = require "./multiblock/multiblock_controller" +MultiblockDisplay = require "../../../models/site/multiblock_display" ######################################################################################################################## 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' + 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 @@ -28,66 +29,70 @@ module.exports = class MultiblockViewerController extends BaseController # Event Methods ################################################################################ onBackClicked: -> - return if @$backButton.hasClass 'disabled' - tracker.trackEvent c.tracking.category.multiblock, 'back' + return if @$backButton.hasClass "disabled" + tracker.trackEvent c.tracking.category.multiblock, "back" @multiblockController.goBackLayer() @refresh() onNextClicked: -> - return if @$nextButton.hasClass 'disabled' - tracker.trackEvent c.tracking.category.multiblock, 'next' + return if @$nextButton.hasClass "disabled" + tracker.trackEvent c.tracking.category.multiblock, "next" @multiblockController.goNextLayer() @refresh() onBlockHovered: (itemDisplay)-> if itemDisplay? - @$captionText.html itemDisplay.itemName + @$captionText.html itemDisplay.name @_imageLoader.load itemDisplay.iconUrl, @$captionIcon else - @$captionText.html ' ' - @$captionIcon.attr 'src', '/images/empty.png' + @$captionText.html " " + @$captionIcon.attr "src", "/images/empty.png" # BaseController Overrides ##################################################################### onDidRender: -> - @completeInventoryController = @addChild InventoryController, '.view__inventory.complete', + @completeInventoryController = @addChild InventoryController, ".view__inventory.complete", editable: false imageLoader: @_imageLoader modPack: @_modPack router: @_router - @layerInventoryController = @addChild InventoryController, '.view__inventory.layer', + @layerInventoryController = @addChild InventoryController, ".view__inventory.layer", editable: false imageLoader: @_imageLoader modPack: @_modPack router: @_router - @multiblockController = @addChild MultiblockController, '.view__multiblock', + @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') + @$backButton = @$(".button.back") + @$nextButton = @$(".button.next") + @$captionText = @$(".caption p") + @$captionIcon = @$(".caption img") super + onWillChangeModel: (oldModel, newModel)-> + @_display = new MultiblockDisplay newModel + super oldModel, newModel + refresh: -> - if @model? - @completeInventoryController.model = @model.inventory - @layerInventoryController.model = @model.getLayerInventory @multiblockController.currentLayer + if @model? and @_display? + @completeInventoryController.model = @_display.getInventory() + @layerInventoryController.model = @_display.getInventory @multiblockController.currentLayer @multiblockController.model = @model if @multiblockController.hasBackLayer() - @$backButton.removeClass 'disabled' + @$backButton.removeClass "disabled" else - @$backButton.addClass 'disabled' + @$backButton.addClass "disabled" if @multiblockController.hasNextLayer() - @$nextButton.removeClass 'disabled' + @$nextButton.removeClass "disabled" else - @$nextButton.addClass 'disabled' + @$nextButton.addClass "disabled" super @@ -95,5 +100,5 @@ module.exports = class MultiblockViewerController extends BaseController events: -> _.extend super, - 'click .button.back': 'onBackClicked' - 'click .button.next': 'onNextClicked' + "click .button.back": "onBackClicked" + "click .button.next": "onNextClicked" From 3ca0dcceed4d350247ad8375a327990a692a00c4 Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Sun, 16 Jul 2017 07:44:55 -0400 Subject: [PATCH 15/21] Recipe compoent can show many types of recipes --- .../recipe/crafting_table/crafting_table.jade | 14 +++ .../recipe/crafting_table/crafting_table.scss | 49 +++++++++ .../crafting_table_controller.coffee | 99 +++++++++++++++++++ src/client/site/common/recipe/recipe.jade | 8 +- .../common/recipe/recipe_controller.coffee | 96 +++++++++--------- 5 files changed, 208 insertions(+), 58 deletions(-) create mode 100644 src/client/site/common/recipe/crafting_table/crafting_table.jade create mode 100644 src/client/site/common/recipe/crafting_table/crafting_table.scss create mode 100644 src/client/site/common/recipe/crafting_table/crafting_table_controller.coffee diff --git a/src/client/site/common/recipe/crafting_table/crafting_table.jade b/src/client/site/common/recipe/crafting_table/crafting_table.jade new file mode 100644 index 000000000..41b8f1eb2 --- /dev/null +++ b/src/client/site/common/recipe/crafting_table/crafting_table.jade @@ -0,0 +1,14 @@ +//- +//- Crafting Guide - crafting_table.jade +//- +//- Copyright (c) 2015-2017 by Redwood Labs +//- All rights reserved. +//- + +.view__crafting_table + .input + .view__crafting_grid + .tool + .output + .view__slot + .multiplier diff --git a/src/client/site/common/recipe/crafting_table/crafting_table.scss b/src/client/site/common/recipe/crafting_table/crafting_table.scss new file mode 100644 index 000000000..88e857633 --- /dev/null +++ b/src/client/site/common/recipe/crafting_table/crafting_table.scss @@ -0,0 +1,49 @@ +// +// Crafting Guide - crafting_table.scss +// +// Copyright © 2014-2017 by Redwood Labs +// All rights reserved. +// + +.view__crafting_table { + display: flex; + + .input { + flex: 0 0 auto; + + align-items : center; + display : flex; + flex-direction : column; + + .view__crafting_grid { + flex: 0 0 auto; + } + + .tool { + margin-top : $size-margin-small; + + font-family : $font-family-text; + font-size : $font-size-medium; + } + } + + .output { + flex: 1 1 100%; + margin-left: $size-margin-medium; + + display : flex; + flex-direction : column; + justify-content : center; + align-items : center; + + .view__slot { + border: $size-border-medium solid $color-gray-medium; + } + + .multiplier { + font-family : $font-family-header; + font-size : $font-size-large; + margin-top : $size-margin-medium; + } + } +} diff --git a/src/client/site/common/recipe/crafting_table/crafting_table_controller.coffee b/src/client/site/common/recipe/crafting_table/crafting_table_controller.coffee new file mode 100644 index 000000000..364ad9eab --- /dev/null +++ b/src/client/site/common/recipe/crafting_table/crafting_table_controller.coffee @@ -0,0 +1,99 @@ +# +# Crafting Guide - crafting_table_controller.coffee +# +# Copyright © 2014-2017 by Redwood Labs +# All rights reserved. +# + +BaseController = require "../../../base_controller" +CraftingGridController = require "../../crafting_grid/crafting_grid_controller" +ItemDisplay = require "../../../../models/site/item_display" +SlotController = require "../../slot/slot_controller" +{StringBuilder} = require("crafting-guide-common").util + +######################################################################################################################## + +module.exports = class CraftingTableController 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 = "common/recipe/crafting_table" + super options + + @_imageLoader = options.imageLoader + @_modPack = options.modPack + @_multiplier = options.multiplier + @_router = options.router + + # BaseController Overrides ##################################################################### + + onDidRender: -> + @_gridController = @addChild CraftingGridController, ".view__crafting_grid", + modPack: @_modPack + imageLoader: @_imageLoader + router: @_router + + @_outputSlotController = @addChild SlotController, ".output .view__slot", + imageLoader: @_imageLoader + modPack: @_modPack + router: @_router + + @$multiplier = @$(".multiplier") + @$outputImg = @$(".output img") + @$outputLink = @$(".output a") + @$outputQuantity = @$(".quantity") + @$toolContainer = @$(".tool") + super + + refresh: -> + @_gridController.model = @model + @_outputSlotController.model = @model?.output + + @_refreshMultiplier() + @_refreshTools() + super + + # Property Methods ############################################################################# + + Object.defineProperties @prototype, + multiplier: + get: -> + @_multiplier ?= 1 + return @_multiplier + + set: (newMultiplier)-> + oldMultiplier = @_multiplier + return if newMultiplier is oldMultiplier + + @_multiplier = newMultiplier + @_refreshMultiplier() + + @trigger "change:multiplier", this, oldMultiplier, newMultiplier + @trigger "change", this + + # Backbone.View Methods ######################################################################## + + events: -> + return _.extend super, + "click a": "routeLinkClick" + + # Private Methods ############################################################################## + + _refreshMultiplier: -> + if @multiplier > 1 + @$multiplier.html "x#{@multiplier}" + else + @$multiplier.html "" + + _refreshTools: -> + @$toolContainer.empty() + return unless @model? + + toolLinks = [] + for itemId, item of @model.tools + display = new ItemDisplay item + toolLinks.push "#{display.name}" + + @$toolContainer.html toolLinks.join ", " diff --git a/src/client/site/common/recipe/recipe.jade b/src/client/site/common/recipe/recipe.jade index 0acf46b76..95ae08bb5 100644 --- a/src/client/site/common/recipe/recipe.jade +++ b/src/client/site/common/recipe/recipe.jade @@ -1,14 +1,8 @@ //- //- Crafting Guide - recipe.jade //- -//- Copyright (c) 2015 by Redwood Labs +//- Copyright (c) 2014-2017 by Redwood Labs //- All rights reserved. //- .view__recipe - .input - .view__crafting_grid - .tool - .output - .view__slot - .multiplier \ No newline at end of file diff --git a/src/client/site/common/recipe/recipe_controller.coffee b/src/client/site/common/recipe/recipe_controller.coffee index 0d851b546..0567bc802 100644 --- a/src/client/site/common/recipe/recipe_controller.coffee +++ b/src/client/site/common/recipe/recipe_controller.coffee @@ -5,11 +5,8 @@ # All rights reserved. # -BaseController = require "../../base_controller" -CraftingGridController = require "../crafting_grid/crafting_grid_controller" -ItemDisplay = require "../../../models/site/item_display" -SlotController = require "../slot/slot_controller" -{StringBuilder} = require("crafting-guide-common").util +BaseController = require "../../base_controller" +CraftingTableController = require "./crafting_table/crafting_table_controller" ######################################################################################################################## @@ -27,35 +24,16 @@ module.exports = class RecipeController extends BaseController @_multiplier = options.multiplier @_router = options.router - # BaseController Overrides ##################################################################### + # Class Members ################################################################################ + + @::RECIPE_TYPE = + CRAFTING_TABLE: + css: "crafting_table" + Controller: CraftingTableController - onDidRender: -> - @_gridController = @addChild CraftingGridController, ".view__crafting_grid", - modPack: @_modPack - imageLoader: @_imageLoader - router: @_router + @::ALL_RECIPE_TYPES = (value for key, value of @::RECIPE_TYPE) - @_outputSlotController = @addChild SlotController, ".output .view__slot", - imageLoader: @_imageLoader - modPack: @_modPack - router: @_router - - @$multiplier = @$(".multiplier") - @$outputImg = @$(".output img") - @$outputLink = @$(".output a") - @$outputQuantity = @$(".quantity") - @$toolContainer = @$(".tool") - super - - refresh: -> - @_gridController.model = @model - @_outputSlotController.model = @model?.output - - @_refreshMultiplier() - @_refreshTools() - super - - # Property Methods ############################################################################# + # Properties ################################################################################### Object.defineProperties @prototype, multiplier: @@ -68,32 +46,48 @@ module.exports = class RecipeController extends BaseController return if newMultiplier is oldMultiplier @_multiplier = newMultiplier - @_refreshMultiplier() - @trigger Event.change + ":multiplier", this, oldMultiplier, newMultiplier - @trigger Event.change, this + @trigger "change:multiplier", this, oldMultiplier, newMultiplier + @trigger "change", this - # Backbone.View Methods ######################################################################## + recipeType: + get: -> return @_recipeType + set: -> throw new Error "recipeType cannot be assigned" - events: -> - return _.extend super, - "click a": "routeLinkClick" + # BaseController Overrides ##################################################################### + + onWillChangeModel: (oldModel, newModel)-> + @_recomputeRecipeType(newModel) + return super oldModel, newModel + + refresh: -> + @_refreshRecipeType() # Private Methods ############################################################################## - _refreshMultiplier: -> - if @multiplier > 1 - @$multiplier.html "x#{@multiplier}" + _recomputeRecipeType: (recipe)-> + oldRecipeType = @_recipeType + + if not recipe? + newRecipeType = null else - @$multiplier.html "" + newRecipeType = @RECIPE_TYPE.CRAFTING_TABLE - _refreshTools: -> - @$toolContainer.empty() - return unless @model? + return unless newRecipeType isnt oldRecipeType - toolLinks = [] - for itemId, item of @model.tools - display = new ItemDisplay item - toolLinks.push "#{display.name}" + @_recipeType = newRecipeType + @trigger "change:recipeType", this, oldRecipeType, newRecipeType - @$toolContainer.html toolLinks.join ", " + _refreshRecipeType: -> + return if @_renderedRecipeType is @recipeType + @_renderedRecipeType = @recipeType + + if @_typeController? + @_typeController.remove() + @_typeController = null + + return unless @recipeType? + + @$el.append "
" + options = imageLoader:@_imageLoader, model:@model, modPack:@_modPack, router:@_router + @_typeController = @addChild @recipeType.Controller, ".view__#{@recipeType.css}", options From 0e6d75ec9b6732ad74ec0bc836fbd38943f90627 Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Sun, 16 Jul 2017 13:07:49 -0400 Subject: [PATCH 16/21] Recipe component can show multiblock recipes --- src/client/models/site/item_page.coffee | 5 +- src/client/models/site/recipe_display.coffee | 109 ++++++++++++++++++ .../crafting_table_controller.coffee | 45 +++----- .../multiblock/multiblock.jade | 0 .../multiblock/multiblock.scss | 0 .../multiblock/multiblock_controller.coffee | 6 +- .../multiblock_viewer/multiblock_viewer.jade | 0 .../multiblock_viewer/multiblock_viewer.scss | 0 .../multiblock_viewer_controller.coffee | 40 +++---- .../common/recipe/recipe_controller.coffee | 69 +++-------- src/client/site/craft_page/step/step.jade | 4 +- src/client/site/craft_page/step/step.scss | 19 +-- .../craft_page/step/step_controller.coffee | 73 +++++------- src/client/site/item_page/item_page.jade | 7 +- .../item_page/item_page_controller.coffee | 19 +-- 15 files changed, 199 insertions(+), 197 deletions(-) create mode 100644 src/client/models/site/recipe_display.coffee rename src/client/site/{item_page => common/recipe}/multiblock_viewer/multiblock/multiblock.jade (100%) rename src/client/site/{item_page => common/recipe}/multiblock_viewer/multiblock/multiblock.scss (100%) rename src/client/site/{item_page => common/recipe}/multiblock_viewer/multiblock/multiblock_controller.coffee (96%) rename src/client/site/{item_page => common/recipe}/multiblock_viewer/multiblock_viewer.jade (100%) rename src/client/site/{item_page => common/recipe}/multiblock_viewer/multiblock_viewer.scss (100%) rename src/client/site/{item_page => common/recipe}/multiblock_viewer/multiblock_viewer_controller.coffee (71%) diff --git a/src/client/models/site/item_page.coffee b/src/client/models/site/item_page.coffee index b0c62ccd8..88fcba6ba 100644 --- a/src/client/models/site/item_page.coffee +++ b/src/client/models/site/item_page.coffee @@ -48,11 +48,8 @@ module.exports = class ItemPage extends Observable return @_findItemsWithMatchingRecipes (recipe)=> recipe.computeQuantityRequired @item - findMultiblockRecipes: -> - return (recipe for recipeId, recipe of @item.recipes when recipes.depth > 1) - findRecipes: -> - return (recipe for recipeId, recipe of @item.recipes when recipe.depth is 1) + return (recipe for recipeId, recipe of @item.recipes) findSimilarItems: -> group = @mod.itemGroups[@item.groupName] diff --git a/src/client/models/site/recipe_display.coffee b/src/client/models/site/recipe_display.coffee new file mode 100644 index 000000000..06be38519 --- /dev/null +++ b/src/client/models/site/recipe_display.coffee @@ -0,0 +1,109 @@ +# +# Crafting Guide - recipe_display.coffee +# +# Copyright © 2014-2017 by Redwood Labs +# All rights reserved. +# + +_ = require "../../../common/underscore" +c = require "../../../common/constants" +{Inventory} = require("crafting-guide-common").models +{Observable} = require("crafting-guide-common").util + +######################################################################################################################## + +module.exports = class RecipeDisplay extends Observable + + constructor: (options={})-> + if not options.recipe? then throw new Error "options.recipe is required" + options.multiplier ?= 1 + super + + @_layerInventories = [] + + @recipe = options.recipe + @multiplier = options.multiplier + + # Class Methods ################################################################################ + + @::RECIPE_TYPE = + CRAFTING_TABLE: "crafting_table" + MULTIBLOCK: "multiblock" + + @::ALL_RECIPE_TYPES = (value for key, value of @::RECIPE_TYPE) + + # Properties ################################################################################### + + Object.defineProperties @prototype, + + depth: + get: -> return @recipe.depth + set: -> throw new Error "depth cannot be assigned" + + height: + get: -> return @recipe.height + set: -> throw new Error "height cannot be assigned" + + multiplier: + get: -> return @_multiplier + set: (multiplier)-> + if not _.isNumber(multiplier) then multiplier = 1 + @triggerPropertyChange "multiplier", @_multiplier, multiplier + + recipe: + get: -> return @_recipe + set: (recipe)-> + return if recipe is @_recipe + if not recipe? then throw new Error "recipe is required" + if @_recipe? then throw new Error "recipe cannot be reassigned" + @_recipe = recipe + @_computeType() + + tools: + get: -> return @recipe.tools + set: -> throw new Error "tools cannot be assigned" + + type: + get: -> return @_type + set: -> throw new Error "type cannot be assigned" + + width: + get: -> return @recipe.width + set: -> throw new Error "width cannot be assigned" + + # Public Methods ############################################################################### + + getInputAt: (x, y, z)-> + return @recipe.getInputAt x, y, z + + getInventory: (z)-> + if not z? + return @_fullInventory ?= @_createFullInventory() + else + return @_layerInventories[z] ?= @_addLayerInventory z + + # Private Methods ############################################################################## + + _addLayerInventory: (z, inventory=null)-> + inventory ?= new Inventory + for x in [0..@recipe.width] + for y in [0..@recipe.height] + stack = @recipe.getInputAt x, y, z + continue unless stack? + inventory.add stack.item, stack.quantity + return inventory + + _computeType: -> + if not @recipe? + type = null + else if @recipe.depth > 1 + type = @RECIPE_TYPE.MULTIBLOCK + else + type = @RECIPE_TYPE.CRAFTING_TABLE + @triggerPropertyChange "type", @_type, type + + _createFullInventory: (inventory=null)-> + inventory ?= new Inventory() + for z in [0..@recipe.depth] + @_addLayerInventory z, inventory + return inventory diff --git a/src/client/site/common/recipe/crafting_table/crafting_table_controller.coffee b/src/client/site/common/recipe/crafting_table/crafting_table_controller.coffee index 364ad9eab..740846d8d 100644 --- a/src/client/site/common/recipe/crafting_table/crafting_table_controller.coffee +++ b/src/client/site/common/recipe/crafting_table/crafting_table_controller.coffee @@ -8,6 +8,7 @@ BaseController = require "../../../base_controller" CraftingGridController = require "../../crafting_grid/crafting_grid_controller" ItemDisplay = require "../../../../models/site/item_display" +RecipeDisplay = require "../../../../models/site/recipe_display" SlotController = require "../../slot/slot_controller" {StringBuilder} = require("crafting-guide-common").util @@ -24,21 +25,14 @@ module.exports = class CraftingTableController extends BaseController @_imageLoader = options.imageLoader @_modPack = options.modPack - @_multiplier = options.multiplier @_router = options.router # BaseController Overrides ##################################################################### onDidRender: -> - @_gridController = @addChild CraftingGridController, ".view__crafting_grid", - modPack: @_modPack - imageLoader: @_imageLoader - router: @_router - - @_outputSlotController = @addChild SlotController, ".output .view__slot", - imageLoader: @_imageLoader - modPack: @_modPack - router: @_router + options = modPack:@_modPack, imageLoader:@_imageLoader, router:@_router + @_gridController = @addChild CraftingGridController, ".view__crafting_grid", options + @_outputSlotController = @addChild SlotController, ".output .view__slot", options @$multiplier = @$(".multiplier") @$outputImg = @$(".output img") @@ -47,32 +41,19 @@ module.exports = class CraftingTableController extends BaseController @$toolContainer = @$(".tool") super + onWillChangeModel: (oldModel, newModel)-> + if not newModel? then throw new Error "model is required" + if newModel.constructor isnt RecipeDisplay then throw new Error "model must be a RecipeDisplay" + return super oldModel, newModel + refresh: -> - @_gridController.model = @model - @_outputSlotController.model = @model?.output + @_gridController.model = @model.recipe + @_outputSlotController.model = @model?.recipe.output @_refreshMultiplier() @_refreshTools() super - # Property Methods ############################################################################# - - Object.defineProperties @prototype, - multiplier: - get: -> - @_multiplier ?= 1 - return @_multiplier - - set: (newMultiplier)-> - oldMultiplier = @_multiplier - return if newMultiplier is oldMultiplier - - @_multiplier = newMultiplier - @_refreshMultiplier() - - @trigger "change:multiplier", this, oldMultiplier, newMultiplier - @trigger "change", this - # Backbone.View Methods ######################################################################## events: -> @@ -82,8 +63,8 @@ module.exports = class CraftingTableController extends BaseController # Private Methods ############################################################################## _refreshMultiplier: -> - if @multiplier > 1 - @$multiplier.html "x#{@multiplier}" + if @model.multiplier > 1 + @$multiplier.html "x#{@model.multiplier}" else @$multiplier.html "" diff --git a/src/client/site/item_page/multiblock_viewer/multiblock/multiblock.jade b/src/client/site/common/recipe/multiblock_viewer/multiblock/multiblock.jade similarity index 100% rename from src/client/site/item_page/multiblock_viewer/multiblock/multiblock.jade rename to src/client/site/common/recipe/multiblock_viewer/multiblock/multiblock.jade diff --git a/src/client/site/item_page/multiblock_viewer/multiblock/multiblock.scss b/src/client/site/common/recipe/multiblock_viewer/multiblock/multiblock.scss similarity index 100% rename from src/client/site/item_page/multiblock_viewer/multiblock/multiblock.scss rename to src/client/site/common/recipe/multiblock_viewer/multiblock/multiblock.scss diff --git a/src/client/site/item_page/multiblock_viewer/multiblock/multiblock_controller.coffee b/src/client/site/common/recipe/multiblock_viewer/multiblock/multiblock_controller.coffee similarity index 96% rename from src/client/site/item_page/multiblock_viewer/multiblock/multiblock_controller.coffee rename to src/client/site/common/recipe/multiblock_viewer/multiblock/multiblock_controller.coffee index 51e11991e..678cec969 100644 --- a/src/client/site/item_page/multiblock_viewer/multiblock/multiblock_controller.coffee +++ b/src/client/site/common/recipe/multiblock_viewer/multiblock/multiblock_controller.coffee @@ -5,8 +5,8 @@ # All rights reserved. # -BaseController = require "../../../base_controller" -ItemDisplay = require "../../../../models/site/item_display" +BaseController = require "../../../../base_controller" +ItemDisplay = require "../../../../../models/site/item_display" ######################################################################################################################## @@ -28,7 +28,7 @@ module.exports = class MultiblockController 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" - options.templateName = "item_page/multiblock_viewer/multiblock" + options.templateName = "common/recipe/multiblock_viewer/multiblock" super options @_currentLayer = 0 diff --git a/src/client/site/item_page/multiblock_viewer/multiblock_viewer.jade b/src/client/site/common/recipe/multiblock_viewer/multiblock_viewer.jade similarity index 100% rename from src/client/site/item_page/multiblock_viewer/multiblock_viewer.jade rename to src/client/site/common/recipe/multiblock_viewer/multiblock_viewer.jade diff --git a/src/client/site/item_page/multiblock_viewer/multiblock_viewer.scss b/src/client/site/common/recipe/multiblock_viewer/multiblock_viewer.scss similarity index 100% rename from src/client/site/item_page/multiblock_viewer/multiblock_viewer.scss rename to src/client/site/common/recipe/multiblock_viewer/multiblock_viewer.scss diff --git a/src/client/site/item_page/multiblock_viewer/multiblock_viewer_controller.coffee b/src/client/site/common/recipe/multiblock_viewer/multiblock_viewer_controller.coffee similarity index 71% rename from src/client/site/item_page/multiblock_viewer/multiblock_viewer_controller.coffee rename to src/client/site/common/recipe/multiblock_viewer/multiblock_viewer_controller.coffee index 8d993bab1..2a6e40c5f 100644 --- a/src/client/site/item_page/multiblock_viewer/multiblock_viewer_controller.coffee +++ b/src/client/site/common/recipe/multiblock_viewer/multiblock_viewer_controller.coffee @@ -5,10 +5,10 @@ # All rights reserved. # -BaseController = require "../../base_controller" -InventoryController = require "../../common/inventory/inventory_controller" +BaseController = require "../../../base_controller" +InventoryController = require "../../inventory/inventory_controller" MultiblockController = require "./multiblock/multiblock_controller" -MultiblockDisplay = require "../../../models/site/multiblock_display" +RecipeDisplay = require "../../../../models/site/recipe_display" ######################################################################################################################## @@ -18,7 +18,7 @@ module.exports = class MultiblockViewerController extends BaseController 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" + options.templateName = "common/recipe/multiblock_viewer" super options @_imageLoader = options.imageLoader @@ -51,22 +51,14 @@ module.exports = class MultiblockViewerController extends BaseController # BaseController Overrides ##################################################################### onDidRender: -> - @completeInventoryController = @addChild InventoryController, ".view__inventory.complete", - editable: false - imageLoader: @_imageLoader - modPack: @_modPack - router: @_router + baseOptions = imageLoader:@_imageLoader, modPack:@_modPack, router:@_router - @layerInventoryController = @addChild InventoryController, ".view__inventory.layer", - editable: false - imageLoader: @_imageLoader - modPack: @_modPack - router: @_router + options = _.extend {editable:false}, baseOptions + @completeInventoryController = @addChild InventoryController, ".view__inventory.complete", options + @layerInventoryController = @addChild InventoryController, ".view__inventory.layer", options - @multiblockController = @addChild MultiblockController, ".view__multiblock", - imageLoader: @_imageLoader - modPack: @_modPack - onHovering: (itemDisplay)=> @onBlockHovered(itemDisplay) + options = _.extend {onHovering:(itemDisplay)=> @onBlockHovered(itemDisplay)}, baseOptions + @multiblockController = @addChild MultiblockController, ".view__multiblock", options @$backButton = @$(".button.back") @$nextButton = @$(".button.next") @@ -75,14 +67,14 @@ module.exports = class MultiblockViewerController extends BaseController super onWillChangeModel: (oldModel, newModel)-> - @_display = new MultiblockDisplay newModel - super oldModel, newModel + if not newModel? then throw new Error "model is required" + if newModel.constructor isnt RecipeDisplay then throw new Error "model must be a RecipeDisplay" + return super oldModel, newModel refresh: -> - if @model? and @_display? - @completeInventoryController.model = @_display.getInventory() - @layerInventoryController.model = @_display.getInventory @multiblockController.currentLayer - @multiblockController.model = @model + @completeInventoryController.model = @model.getInventory() + @layerInventoryController.model = @model.getInventory @multiblockController.currentLayer + @multiblockController.model = @model if @multiblockController.hasBackLayer() @$backButton.removeClass "disabled" diff --git a/src/client/site/common/recipe/recipe_controller.coffee b/src/client/site/common/recipe/recipe_controller.coffee index 0567bc802..68eaf9c7e 100644 --- a/src/client/site/common/recipe/recipe_controller.coffee +++ b/src/client/site/common/recipe/recipe_controller.coffee @@ -5,8 +5,10 @@ # All rights reserved. # -BaseController = require "../../base_controller" -CraftingTableController = require "./crafting_table/crafting_table_controller" +BaseController = require "../../base_controller" +CraftingTableController = require "./crafting_table/crafting_table_controller" +MultiblockViewerController = require "./multiblock_viewer/multiblock_viewer_controller" +RecipeDisplay = require "../../../models/site/recipe_display" ######################################################################################################################## @@ -21,73 +23,38 @@ module.exports = class RecipeController extends BaseController @_imageLoader = options.imageLoader @_modPack = options.modPack - @_multiplier = options.multiplier @_router = options.router - # Class Members ################################################################################ - - @::RECIPE_TYPE = - CRAFTING_TABLE: - css: "crafting_table" - Controller: CraftingTableController - - @::ALL_RECIPE_TYPES = (value for key, value of @::RECIPE_TYPE) - - # Properties ################################################################################### - - Object.defineProperties @prototype, - multiplier: - get: -> - @_multiplier ?= 1 - return @_multiplier - - set: (newMultiplier)-> - oldMultiplier = @_multiplier - return if newMultiplier is oldMultiplier - - @_multiplier = newMultiplier - - @trigger "change:multiplier", this, oldMultiplier, newMultiplier - @trigger "change", this - - recipeType: - get: -> return @_recipeType - set: -> throw new Error "recipeType cannot be assigned" - # BaseController Overrides ##################################################################### onWillChangeModel: (oldModel, newModel)-> - @_recomputeRecipeType(newModel) + if not newModel? then throw new Error "model is required" + if newModel.constructor isnt RecipeDisplay then throw new Error "model must be a RecipeDisplay" return super oldModel, newModel refresh: -> + return unless @model? @_refreshRecipeType() + super # Private Methods ############################################################################## - _recomputeRecipeType: (recipe)-> - oldRecipeType = @_recipeType - - if not recipe? - newRecipeType = null - else - newRecipeType = @RECIPE_TYPE.CRAFTING_TABLE - - return unless newRecipeType isnt oldRecipeType - - @_recipeType = newRecipeType - @trigger "change:recipeType", this, oldRecipeType, newRecipeType + _lookupControllerFor: (recipeType)-> + if recipeType is RecipeDisplay::RECIPE_TYPE.CRAFTING_TABLE then return CraftingTableController + if recipeType is RecipeDisplay::RECIPE_TYPE.MULTIBLOCK then return MultiblockViewerController _refreshRecipeType: -> - return if @_renderedRecipeType is @recipeType - @_renderedRecipeType = @recipeType + return if @_renderedRecipeType is @model.type + @_renderedRecipeType = @model.type if @_typeController? @_typeController.remove() @_typeController = null - return unless @recipeType? + return unless @_renderedRecipeType? - @$el.append "
" + TypeController = @_lookupControllerFor @model.type + + @$el.append "
" options = imageLoader:@_imageLoader, model:@model, modPack:@_modPack, router:@_router - @_typeController = @addChild @recipeType.Controller, ".view__#{@recipeType.css}", options + @_typeController = @addChild TypeController, ".view__#{@model.type}", options diff --git a/src/client/site/craft_page/step/step.jade b/src/client/site/craft_page/step/step.jade index 913cb6ef9..2fb9eed80 100644 --- a/src/client/site/craft_page/step/step.jade +++ b/src/client/site/craft_page/step/step.jade @@ -7,9 +7,7 @@ .view__step h3 - .main_content - .view__inventory - .view__recipe + .view__recipe .buttons a.button.tool: .bezel: p show plan for tools .button.complete: .bezel: p complete step diff --git a/src/client/site/craft_page/step/step.scss b/src/client/site/craft_page/step/step.scss index c79068001..8a0b4cf89 100644 --- a/src/client/site/craft_page/step/step.scss +++ b/src/client/site/craft_page/step/step.scss @@ -25,24 +25,7 @@ margin-bottom: 1em; } - .main_content { - display: flex; - - .view__inventory { - flex: 50%; - margin-left: $size-margin-large; - - .buttons { - display: none; - } - } - - .view__recipe { - flex: 50%; - } - } - - .buttons { + & > .buttons { margin-top: $size-margin-large; opacity: 0; diff --git a/src/client/site/craft_page/step/step_controller.coffee b/src/client/site/craft_page/step/step_controller.coffee index 020eff516..ebcc582cb 100644 --- a/src/client/site/craft_page/step/step_controller.coffee +++ b/src/client/site/craft_page/step/step_controller.coffee @@ -5,11 +5,12 @@ # All rights reserved. # -BaseController = require '../../base_controller' +BaseController = require "../../base_controller" {Inventory} = require("crafting-guide-common").models {CraftingPlanStep} = require("crafting-guide-common").crafting -InventoryController = require '../../common/inventory/inventory_controller' -RecipeController = require '../../common/recipe/recipe_controller' +InventoryController = require "../../common/inventory/inventory_controller" +RecipeController = require "../../common/recipe/recipe_controller" +RecipeDisplay = require "../../../models/site/recipe_display" ######################################################################################################################## @@ -19,9 +20,9 @@ module.exports = class StepController extends BaseController constructor: (options={})-> if options.model?.constructor isnt CraftingPlanStep throw new Error "options.model must be a CraftingPlanStep" - if not options.modPack? then throw new Error 'options.modPack is required' - if not options.imageLoader? then throw new Error 'options.imageLoader is required' - options.templateName = 'craft_page/step' + if not options.modPack? then throw new Error "options.modPack is required" + if not options.imageLoader? then throw new Error "options.imageLoader is required" + options.templateName = "craft_page/step" super options @_imageLoader = options.imageLoader @@ -36,57 +37,45 @@ module.exports = class StepController extends BaseController # Public Methods ############################################################################### markComplete: (targetInventory)-> - @$el.addClass 'complete' - @$completeButton.addClass 'disabled' + @$el.addClass "complete" + @$completeButton.addClass "disabled" @model.completeInto targetInventory # Event Methods ################################################################################ onCompleteButtonClicked: (event)-> - return false if @$completeButton.hasClass 'disabled' - tracker.trackEvent c.tracking.category.craft, 'mark-complete', null, @model.count + return false if @$completeButton.hasClass "disabled" + tracker.trackEvent c.tracking.category.craft, "mark-complete", null, @model.count @onComplete this onShowToolPlan: (event)-> - return false if @$toolButton.hasClass 'disabled' - tracker.trackEvent c.tracking.category.navigate, 'show-tool-plan', @$toolButton.attr 'target' + return false if @$toolButton.hasClass "disabled" + tracker.trackEvent c.tracking.category.navigate, "show-tool-plan", @$toolButton.attr "target" return true # BaseController Overrides ##################################################################### onDidRender: -> - @inventoryController = @addChild InventoryController, '.view__inventory', - editable: false - imageLoader: @_imageLoader - model: @model.inputInventory - modPack: @_modPack - router: @_router + options = imageLoader:@_imageLoader, modPack:@_modPack, router:@_router + @recipeController = @addChild RecipeController, ".view__recipe", options - @recipeController = @addChild RecipeController, '.view__recipe', - imageLoader: @_imageLoader - model: @model.recipe - modPack: @_modPack - router: @_router - - @$completeButton = @$('.button.complete') - @$header = @$('h3') - @$toolButton = @$('.button.tool') - @$toolButtonLabel = @$('.button.tool p') + @$completeButton = @$(".button.complete") + @$header = @$("h3") + @$toolButton = @$(".button.tool") + @$toolButtonLabel = @$(".button.tool p") super onWillChangeModel: (oldModel, newModel)-> - if not newModel? then throw new Error 'model cannot be null' + if not newModel? then throw new Error "model cannot be null" if @rendered - @$el.removeClass 'complete' - @$completeButton.removeClass 'disabled' + @$el.removeClass "complete" + @$completeButton.removeClass "disabled" return super refresh: -> @$header.html "#{@model.number}. #{@model.recipe.output.item.displayName}" - @inventoryController.model = @model.inputInventory - @recipeController.model = @model.recipe - @recipeController.multiplier = @model.count + @recipeController.model = new RecipeDisplay recipe:@model.recipe, multiplier:@model.count @_refreshCompleteButton() @_refreshToolButton() @@ -97,8 +86,8 @@ module.exports = class StepController extends BaseController events: -> return _.extend super, - 'click .button.complete': 'onCompleteButtonClicked' - 'click .button.tool': 'onShowToolPlan' + "click .button.complete": "onCompleteButtonClicked" + "click .button.tool": "onShowToolPlan" # Private Methods ############################################################################## @@ -108,16 +97,16 @@ module.exports = class StepController extends BaseController inventory.add item inventoryText = inventory.toUrlString() - @$toolButton.attr 'href', "/craft/#{inventoryText}" - @$toolButton.attr 'target', inventoryText + @$toolButton.attr "href", "/craft/#{inventoryText}" + @$toolButton.attr "target", inventoryText if @canAddTools this - @$toolButton.removeClass 'disabled' + @$toolButton.removeClass "disabled" else - @$toolButton.addClass 'disabled' + @$toolButton.addClass "disabled" _refreshCompleteButton: -> if @canComplete this - @$completeButton.removeClass 'disabled' + @$completeButton.removeClass "disabled" else - @$completeButton.addClass 'disabled' + @$completeButton.addClass "disabled" diff --git a/src/client/site/item_page/item_page.jade b/src/client/site/item_page/item_page.jade index 906d9ec96..0a417a23c 100644 --- a/src/client/site/item_page/item_page.jade +++ b/src/client/site/item_page/item_page.jade @@ -24,11 +24,6 @@ section.description.view__markdown_section - section.multiblock - h2 Multiblock Construction - .panel - .view__multiblock_viewer - section.recipes h2 Recipes .panel @@ -43,4 +38,4 @@ section.view__item_group.usedAsToolToMake - section.view__item_group.similar \ No newline at end of file + section.view__item_group.similar diff --git a/src/client/site/item_page/item_page_controller.coffee b/src/client/site/item_page/item_page_controller.coffee index ce2fc8b63..2b3367e32 100644 --- a/src/client/site/item_page/item_page_controller.coffee +++ b/src/client/site/item_page/item_page_controller.coffee @@ -11,9 +11,9 @@ 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" -MultiblockViewerController = require "./multiblock_viewer/multiblock_viewer_controller" PageController = require "../page_controller" -RecipeDetailController = require "./recipe_detail/recipe_detail_controller" +RecipeController = require "../common/recipe/recipe_controller" +RecipeDisplay = require "../../models/site/recipe_display" VideoController = require "../common/video/video_controller" w = require "when" @@ -79,7 +79,6 @@ module.exports = class ItemPageController extends PageController onDidRender: -> 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 @@ -140,7 +139,6 @@ module.exports = class ItemPageController extends PageController @_refreshSourceMod() @_refreshDescription() - @_refreshMultiblock() @_refreshRecipes() @_refreshSimilarItems() @_refreshUsedAsToolToMake() @@ -221,13 +219,6 @@ module.exports = class ItemPageController extends PageController @_descriptionController.model = @model.item.detail.description @_descriptionController.resetToDefaultState() - _refreshMultiblock: -> - if @model.item.isMultiblock - @_multiblockController.model = @model.item.getMultiblockRecipe() - @show @$multiblockSection - else - @hide @$multiblockSection - _refreshRecipes: -> @_recipeControllers ?= [] index = 0 @@ -239,16 +230,16 @@ module.exports = class ItemPageController extends PageController for recipe in recipes controller = @_recipeControllers[index] if not controller? - controller = new RecipeDetailController + controller = new RecipeController imageLoader: @_imageLoader modPack: @_modPack - model: recipe + model: new RecipeDisplay recipe:recipe router: @_router @_recipeControllers.push controller @$recipeContainer.append controller.$el controller.render() else - controller.model = recipe + controller.model = new RecipeDisplay recipe:recipe index++ @show @$recipesSection From 8b0cd71bb54c86a463e51aa0f4c1254c9b5ac1ad Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Wed, 19 Jul 2017 19:35:16 -0700 Subject: [PATCH 17/21] Allow recipe comp. to show I/O inventories --- src/client/models/site/recipe_display.coffee | 35 ++++++++++++++++--- src/client/site/base_controller.coffee | 9 +++-- .../recipe/crafting_table/crafting_table.jade | 8 +++-- .../recipe/crafting_table/crafting_table.scss | 23 +++++++++--- .../crafting_table_controller.coffee | 33 ++++++++++++----- .../craft_page/step/step_controller.coffee | 7 ++-- src/client/site/item_page/item_page.scss | 4 +++ .../item_page/item_page_controller.coffee | 8 +++-- 8 files changed, 99 insertions(+), 28 deletions(-) diff --git a/src/client/models/site/recipe_display.coffee b/src/client/models/site/recipe_display.coffee index 06be38519..b7a0a56f0 100644 --- a/src/client/models/site/recipe_display.coffee +++ b/src/client/models/site/recipe_display.coffee @@ -16,16 +16,18 @@ module.exports = class RecipeDisplay extends Observable constructor: (options={})-> if not options.recipe? then throw new Error "options.recipe is required" - options.multiplier ?= 1 super @_layerInventories = [] - @recipe = options.recipe - @multiplier = options.multiplier + @multiplier = options.multiplier or 1 + @recipe = options.recipe + @showInputInventory = if options.showInputInventory then options.showInputInventory or false + @showOutputInventory = if options.showOutputInventory then options.showOutputInventory or false + @showOutputSlot = if options.showOutputSlot then options.showOutputSlot or false # Class Methods ################################################################################ - + @::RECIPE_TYPE = CRAFTING_TABLE: "crafting_table" MULTIBLOCK: "multiblock" @@ -59,6 +61,21 @@ module.exports = class RecipeDisplay extends Observable @_recipe = recipe @_computeType() + showInputInventory: + get: -> return @_showInputInventory + set: (showInputInventory)-> + @triggerPropertyChange "showInputInventory", @_showInputInventory, !!showInputInventory + + showOutputInventory: + get: -> return @_showOutputInventory + set: (showOutputInventory)-> + @triggerPropertyChange "showOutputInventory", @_showOutputInventory, !!showOutputInventory + + showOutputSlot: + get: -> return @_showOutputSlot + set: (showOutputSlot)-> + @triggerPropertyChange "showOutputSlot", @_showOutputSlot, !!showOutputSlot + tools: get: -> return @recipe.tools set: -> throw new Error "tools cannot be assigned" @@ -82,6 +99,14 @@ module.exports = class RecipeDisplay extends Observable else return @_layerInventories[z] ?= @_addLayerInventory z + getOutputInventory: -> + if not @_outputInventory? + @_outputInventory = new Inventory + for stack in @recipe.allProducts + @_outputInventory.add stack.item, stack.quantity + + return @_outputInventory + # Private Methods ############################################################################## _addLayerInventory: (z, inventory=null)-> @@ -90,7 +115,7 @@ module.exports = class RecipeDisplay extends Observable for y in [0..@recipe.height] stack = @recipe.getInputAt x, y, z continue unless stack? - inventory.add stack.item, stack.quantity + inventory.add stack.item, stack.quantity * @multiplier return inventory _computeType: -> diff --git a/src/client/site/base_controller.coffee b/src/client/site/base_controller.coffee index 31b43ac61..d1f7733f8 100644 --- a/src/client/site/base_controller.coffee +++ b/src/client/site/base_controller.coffee @@ -146,10 +146,13 @@ module.exports = class BaseController extends Backbone.View @$el.append $renderedEl.children() @$el.addClass $renderedEl.attr 'class' - @$el.data $renderedEl.data() - @delegateEvents() - @$el.controller = this + elementData = $renderedEl.data() + elementData.controller = this + elementData.model = data + @$el.data elementData + + @delegateEvents() @_rendered = true @onDidRender() diff --git a/src/client/site/common/recipe/crafting_table/crafting_table.jade b/src/client/site/common/recipe/crafting_table/crafting_table.jade index 41b8f1eb2..da52afb11 100644 --- a/src/client/site/common/recipe/crafting_table/crafting_table.jade +++ b/src/client/site/common/recipe/crafting_table/crafting_table.jade @@ -6,9 +6,13 @@ //- .view__crafting_table - .input + .input_inventory + .view__inventory + .input_grid .view__crafting_grid .tool - .output + .output_slot .view__slot .multiplier + .output_inventory + .view__inventory diff --git a/src/client/site/common/recipe/crafting_table/crafting_table.scss b/src/client/site/common/recipe/crafting_table/crafting_table.scss index 88e857633..f0edb4e91 100644 --- a/src/client/site/common/recipe/crafting_table/crafting_table.scss +++ b/src/client/site/common/recipe/crafting_table/crafting_table.scss @@ -8,8 +8,15 @@ .view__crafting_table { display: flex; - .input { - flex: 0 0 auto; + .input_inventory { + flex: 1 1 100%; + + display: flex; + margin-right: $size-margin-large; + } + + .input_grid { + flex: 1 1 100%; align-items : center; display : flex; @@ -27,9 +34,9 @@ } } - .output { - flex: 1 1 100%; - margin-left: $size-margin-medium; + .output_slot { + flex: 0 0 auto; + margin-left: $size-margin-large; display : flex; flex-direction : column; @@ -46,4 +53,10 @@ margin-top : $size-margin-medium; } } + + .output_inventory { + flex: 1 1 100%; + display: flex; + margin-left: $size-margin-large; + } } diff --git a/src/client/site/common/recipe/crafting_table/crafting_table_controller.coffee b/src/client/site/common/recipe/crafting_table/crafting_table_controller.coffee index 740846d8d..dc1d59b3a 100644 --- a/src/client/site/common/recipe/crafting_table/crafting_table_controller.coffee +++ b/src/client/site/common/recipe/crafting_table/crafting_table_controller.coffee @@ -7,6 +7,7 @@ BaseController = require "../../../base_controller" CraftingGridController = require "../../crafting_grid/crafting_grid_controller" +InventoryController = require "../../inventory/inventory_controller" ItemDisplay = require "../../../../models/site/item_display" RecipeDisplay = require "../../../../models/site/recipe_display" SlotController = require "../../slot/slot_controller" @@ -30,15 +31,21 @@ module.exports = class CraftingTableController extends BaseController # BaseController Overrides ##################################################################### onDidRender: -> - options = modPack:@_modPack, imageLoader:@_imageLoader, router:@_router - @_gridController = @addChild CraftingGridController, ".view__crafting_grid", options - @_outputSlotController = @addChild SlotController, ".output .view__slot", options + options = editable:false, modPack:@_modPack, imageLoader:@_imageLoader, router:@_router - @$multiplier = @$(".multiplier") - @$outputImg = @$(".output img") - @$outputLink = @$(".output a") - @$outputQuantity = @$(".quantity") - @$toolContainer = @$(".tool") + @_inputController = @addChild InventoryController, ".input_inventory .view__inventory", options + @_gridController = @addChild CraftingGridController, ".input_grid .view__crafting_grid", options + @_outputSlotController = @addChild SlotController, ".output_slot .view__slot", options + @_outputController = @addChild InventoryController, ".output_inventory .view__inventory", options + + @$inputInventorySection = @$(".input_inventory") + @$multiplier = @$(".multiplier") + @$outputImg = @$(".output.slot img") + @$outputInventorySection = @$(".output_inventory") + @$outputLink = @$(".output.slot a") + @$outputQuantity = @$(".quantity") + @$outputSlotSection = @$(".output_slot") + @$toolContainer = @$(".tool") super onWillChangeModel: (oldModel, newModel)-> @@ -47,10 +54,13 @@ module.exports = class CraftingTableController extends BaseController return super oldModel, newModel refresh: -> - @_gridController.model = @model.recipe + @_inputController.model = @model?.getInventory() + @_gridController.model = @model?.recipe @_outputSlotController.model = @model?.recipe.output + @_outputController.model = @model?.getOutputInventory() @_refreshMultiplier() + @_refreshSections() @_refreshTools() super @@ -68,6 +78,11 @@ module.exports = class CraftingTableController extends BaseController else @$multiplier.html "" + _refreshSections: -> + @$inputInventorySection.css display:(if @model.showInputInventory then "" else "none") + @$outputInventorySection.css display:(if @model.showOutputInventory then "" else "none") + @$outputSlotSection.css display:(if @model.showOutputSlot then "" else "none") + _refreshTools: -> @$toolContainer.empty() return unless @model? diff --git a/src/client/site/craft_page/step/step_controller.coffee b/src/client/site/craft_page/step/step_controller.coffee index ebcc582cb..4c1c3f27f 100644 --- a/src/client/site/craft_page/step/step_controller.coffee +++ b/src/client/site/craft_page/step/step_controller.coffee @@ -12,7 +12,6 @@ InventoryController = require "../../common/inventory/inventory_controller" RecipeController = require "../../common/recipe/recipe_controller" RecipeDisplay = require "../../../models/site/recipe_display" - ######################################################################################################################## module.exports = class StepController extends BaseController @@ -75,7 +74,11 @@ module.exports = class StepController extends BaseController refresh: -> @$header.html "#{@model.number}. #{@model.recipe.output.item.displayName}" - @recipeController.model = new RecipeDisplay recipe:@model.recipe, multiplier:@model.count + @recipeController.model = new RecipeDisplay + multiplier: @model.count + recipe: @model.recipe + showInputInventory: true + showOutputSlot: true @_refreshCompleteButton() @_refreshToolButton() diff --git a/src/client/site/item_page/item_page.scss b/src/client/site/item_page/item_page.scss index 4af4faa20..81d5401ab 100644 --- a/src/client/site/item_page/item_page.scss +++ b/src/client/site/item_page/item_page.scss @@ -57,6 +57,10 @@ flex: 0 0 auto; } } + + .view__recipe + .view__recipe { + margin-top: $size-margin-large; + } } @include screen-size(mobile) { diff --git a/src/client/site/item_page/item_page_controller.coffee b/src/client/site/item_page/item_page_controller.coffee index 2b3367e32..cafa9293b 100644 --- a/src/client/site/item_page/item_page_controller.coffee +++ b/src/client/site/item_page/item_page_controller.coffee @@ -229,17 +229,21 @@ module.exports = class ItemPageController extends PageController 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: new RecipeDisplay recipe:recipe + model: model router: @_router @_recipeControllers.push controller @$recipeContainer.append controller.$el controller.render() else - controller.model = new RecipeDisplay recipe:recipe + controller.model = model index++ @show @$recipesSection From cbf66bf5bb2eb4bde6cbd0c855ca042ac953ba2a Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Wed, 19 Jul 2017 19:40:16 -0700 Subject: [PATCH 18/21] Fix bug where similar items weren't shown --- src/client/site/item_page/item_page_controller.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/client/site/item_page/item_page_controller.coffee b/src/client/site/item_page/item_page_controller.coffee index cafa9293b..d095b5c3b 100644 --- a/src/client/site/item_page/item_page_controller.coffee +++ b/src/client/site/item_page/item_page_controller.coffee @@ -254,9 +254,9 @@ module.exports = class ItemPageController extends PageController @_recipeControllers.pop().remove() _refreshSimilarItems: -> - group = @model.item.group - if group? and group isnt Item::DEFAULT_GROUP_NAME - @_similarItemsController.title = "Other #{group}" + 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 From 0b94cc4a1f457334d6f26cb35055467c911f0ef8 Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Sun, 23 Jul 2017 15:16:05 -0700 Subject: [PATCH 19/21] Update wiki editing to use new data format fixes: #292 --- .../models/site/markdown_image_list.coffee | 82 ++++++++----- .../site/markdown_image_list.test.coffee | 2 +- .../markdown_image_list_controller.coffee | 67 +++++----- .../markdown_section_controller.coffee | 112 ++++++++--------- src/client/site/item_page/item_page.jade | 2 +- .../item_page/item_page_controller.coffee | 114 +++++++++--------- src/common/constants.coffee | 2 +- 7 files changed, 199 insertions(+), 182 deletions(-) diff --git a/src/client/models/site/markdown_image_list.coffee b/src/client/models/site/markdown_image_list.coffee index 42821fad3..a11755541 100644 --- a/src/client/models/site/markdown_image_list.coffee +++ b/src/client/models/site/markdown_image_list.coffee @@ -5,26 +5,22 @@ # All rights reserved. # -{BaseModel} = require('crafting-guide-common').deprecated +{Observable} = require("crafting-guide-common").util MarkdownImage = require './markdown_image' ######################################################################################################################## -module.exports = class MarkdownImageList extends BaseModel +module.exports = class MarkdownImageList extends Observable - constructor: (attributes={}, options={})-> - attributes.imageBase ?= '' - attributes.markdownText ?= null - super attributes, options + constructor: (options={})-> + super - @client = options.client - @_images = {} + @_images = [] + @muted => + @client = options.client + @imageBase = options.imageBase + @markdownText = options.markdownText - @on c.event.change + ':imageBase', => - for fileName, image of @_images - image.path = @imageBase - - @on c.event.change + ':markdownText', => @_analyzeMarkdownText() @_analyzeMarkdownText() # Public Methods ############################################################################### @@ -46,22 +42,43 @@ module.exports = class MarkdownImageList extends BaseModel # Property Methods ############################################################################# - getAll: -> - fileNames = (fileName for fileName, image of @_images).sort() - result = [] - for fileName in fileNames - result.push @_images[fileName] - - return result - - isValid: -> - for fileName, image of @_images - return false unless image.valid - return true - Object.defineProperties @prototype, - all: {get:@prototype.getAll} - valid: {get:@prototype.isValid} + + all: + get: -> + fileNames = (fileName for fileName, image of @_images).sort() + result = [] + for fileName in fileNames + result.push @_images[fileName] + + return result + + client: + get: -> return @_client + set: (client)-> + if not client? then throw new Error "client is required" + @_client = client + + imageBase: -> + get: -> return @_imageBase + set: (imageBase)-> + @triggerPropertyChange "imageBase", @_imageBase, imageBase, -> + @_imageBase = imageBase + for fileName, image of @_images + image.path = @imageBase + + markdownText: + get: -> return @_markdownText + set: (markdownText)-> + @triggerPropertyChange "markdownText", @_markdownText, markdownText, -> + @_markdownText = markdownText + @_analyzeMarkdownText() + + valid: + get: -> + for fileName, image of @_images + return false unless image.valid + return true # Private Methods ############################################################################## @@ -79,8 +96,8 @@ module.exports = class MarkdownImageList extends BaseModel image = @_images[fileName] if not image? image = new MarkdownImage {fileName:fileName, path:@imageBase}, {client:@client} - @listenTo image, c.event.change, => @trigger c.event.change, this - @trigger c.event.add, this, image + image.on Observable::CHANGE, this, "_onImageChanged" + @trigger Observable::ADD, image changed = true newImages[fileName] = image @@ -92,4 +109,7 @@ module.exports = class MarkdownImageList extends BaseModel if changed @_images = newImages - @trigger c.event.change, this + @trigger Observable::CHANGE + + _onImageChanged: -> + @trigger Observable::CHANGE diff --git a/src/client/models/site/markdown_image_list.test.coffee b/src/client/models/site/markdown_image_list.test.coffee index 58e458766..2bc701570 100644 --- a/src/client/models/site/markdown_image_list.test.coffee +++ b/src/client/models/site/markdown_image_list.test.coffee @@ -16,7 +16,7 @@ list = null describe 'markdown_image_list.coffee', -> beforeEach -> - list = new MarkdownImageList {}, client:{fetchFile:sinon.stub().returns(w.promise(->))} + list = new MarkdownImageList client:{fetchFile:sinon.stub().returns(w.promise(->))} describe '_analyzeMarkdownText', -> diff --git a/src/client/site/common/markdown_section/markdown_image_list/markdown_image_list_controller.coffee b/src/client/site/common/markdown_section/markdown_image_list/markdown_image_list_controller.coffee index 81db1a92d..d2468583d 100644 --- a/src/client/site/common/markdown_section/markdown_image_list/markdown_image_list_controller.coffee +++ b/src/client/site/common/markdown_section/markdown_image_list/markdown_image_list_controller.coffee @@ -5,20 +5,24 @@ # All rights reserved. # -BaseController = require '../../../base_controller' -MarkdownImageController = require './markdown_image/markdown_image_controller' -MarkdownImageList = require '../../../../models/site/markdown_image_list' +_ = require "../../../../../underscore" +c = require "../../../../../common/constants" +BaseController = require "../../../base_controller" +MarkdownImageController = require "./markdown_image/markdown_image_controller" +MarkdownImageList = require "../../../../models/site/markdown_image_list" +{Observable} = require("crafting-guide-common").util ######################################################################################################################## module.exports = class MarkdownImageListController extends BaseController + _.extend this, Observable constructor: (options={})-> - options.model ?= new MarkdownImageList {}, {client:options.client} - options.templateName = 'common/markdown_section/markdown_image_list' + options.model ?= new MarkdownImageList client:options.client + options.templateName = "common/markdown_section/markdown_image_list" super options - @imageBase = '' + @imageBase = "" @_valid = null # Public Methods ############################################################################### @@ -33,31 +37,24 @@ module.exports = class MarkdownImageListController extends BaseController @model.reset() # Property Methods ############################################################################# - - getImageBase: -> - return @_imageBase - - setImageBase: (newImageBase)-> - oldImageBase = @_imageBase - return unless oldImageBase isnt newImageBase - - @_imageBase = newImageBase - @trigger c.event.change + ':imageBase', this, oldImageBase, newImageBase - @trigger c.event.change, this - - getMarkdownText: -> - return @model.markdownText - - setMarkdownText: (markdownText)-> - @model.markdownText = markdownText - - getValid: -> - return @_valid - + Object.defineProperties @prototype, - imageBase: {get:@prototype.getImageBase, set:@prototype.setImageBase} - markdownText: {get:@prototype.getMarkdownText, set:@prototype.setMarkdownText} - valid: {get:@prototype.getValid} + + imageBase: + get: -> return @_imageBase + set: (imageBase)-> + @_imageBase = imageBase + @trigger c.event.change + + markdownText: + get: -> return @model.markdownText + set: (markdownText)-> + @model.markdownText = markdownText + @trigger c.event.change + + valid: + get: -> return @_valid + set: -> throw new Error "valid cannot be assigned" # BaseController Overrides ##################################################################### @@ -66,7 +63,7 @@ module.exports = class MarkdownImageListController extends BaseController @_setValid @model.valid onDidRender: -> - @$imageContainer = @$('.image_container') + @$imageContainer = @$(".image_container") super refresh: -> @@ -90,10 +87,6 @@ module.exports = class MarkdownImageListController extends BaseController # Private Methods ############################################################################## - _setValid: (newValid)-> - oldValid = @_valid - return if newValid is oldValid - - @_valid = newValid - @trigger c.event.change + ':valid', this, oldValid, newValid + _setValid: (valid)-> + @_valid = valid @trigger c.event.change diff --git a/src/client/site/common/markdown_section/markdown_section_controller.coffee b/src/client/site/common/markdown_section/markdown_section_controller.coffee index 5bfe2ac0c..0f9020ff1 100644 --- a/src/client/site/common/markdown_section/markdown_section_controller.coffee +++ b/src/client/site/common/markdown_section/markdown_section_controller.coffee @@ -5,28 +5,28 @@ # All rights reserved. # -BaseController = require '../../base_controller' -convertMarkdown = require 'marked' +BaseController = require "../../base_controller" +convertMarkdown = require "marked" ItemDisplay = require "../../../models/site/item_display" -MarkdownImageListController = require './markdown_image_list/markdown_image_list_controller' +MarkdownImageListController = require "./markdown_image_list/markdown_image_list_controller" ######################################################################################################################## module.exports = class MarkdownSectionController extends BaseController @::State = - appologizing: 'applogizing' - confirming: 'confirming' - creating: 'creating' - editing: 'editing' - previewing: 'previewing' - viewing: 'viewing' - waiting: 'waiting' + appologizing: "applogizing" + confirming: "confirming" + creating: "creating" + editing: "editing" + previewing: "previewing" + viewing: "viewing" + waiting: "waiting" constructor: (options={})-> - if not options.modPack? then throw new Error 'options.modPack is required' + if not options.modPack? then throw new Error "options.modPack is required" options.model ?= null - options.templateName = 'common/markdown_section' + options.templateName = "common/markdown_section" @_state = @State.waiting super options @@ -34,9 +34,9 @@ module.exports = class MarkdownSectionController extends BaseController @_confirmationMessage = options.confirmationMessage @_confirmDuration = options.confirmationDuration or 5000 @_enterFeedback = options.enterFeedback or -> # do nothing - @_imageBase = options.imageBase or '' + @_imageBase = options.imageBase or "" @_modPack = options.modPack - @_title = options.title or 'Description' + @_title = options.title or "Description" # @_beginEditing must be a function returning a promise which resolves when all actions necessary prior to an # editing session have been completed (e.g., loading the latest content from a remote server). The promise must @@ -61,7 +61,7 @@ module.exports = class MarkdownSectionController extends BaseController # Event Methods ################################################################################ onCancelClicked: (event)-> - tracker.trackEvent c.tracking.category.markdown, 'cancel' + tracker.trackEvent c.tracking.category.markdown, "cancel" @model = @_originalModel @resetToDefaultState() @@ -72,7 +72,7 @@ module.exports = class MarkdownSectionController extends BaseController onEditClicked: (event)-> return false unless @editable - tracker.trackEvent c.tracking.category.markdown, 'edit' + tracker.trackEvent c.tracking.category.markdown, "edit" @_originalModel = @model @state = @State.waiting @_beginEditing() @@ -86,22 +86,22 @@ module.exports = class MarkdownSectionController extends BaseController return false onQuestionClicked: (event)-> - @_enterFeedback '' + @_enterFeedback "" return false onPreviewClicked: (event)-> - tracker.trackEvent c.tracking.category.markdown, 'preview' + tracker.trackEvent c.tracking.category.markdown, "preview" @_updatePreview() @state = @State.previewing return false onReturnClicked: (event)-> - tracker.trackEvent c.tracking.category.markdown, 'return' + tracker.trackEvent c.tracking.category.markdown, "return" @state = @State.editing return false onSaveClicked: (event)-> - tracker.trackEvent c.tracking.category.markdown, 'save' + tracker.trackEvent c.tracking.category.markdown, "save" @state = @State.waiting @_endEditing() .then => @@ -133,7 +133,7 @@ module.exports = class MarkdownSectionController extends BaseController return unless newImageBase isnt oldImageBase @_imageBase = newImageBase - @trigger c.event.change + ':imageBase', this, oldImageBase, newImageBase + @trigger c.event.change + ":imageBase", this, oldImageBase, newImageBase @trigger c.event.change, this getImageFiles: -> @@ -148,7 +148,7 @@ module.exports = class MarkdownSectionController extends BaseController @_state = newState logger.verbose => "MarkdownSectionController.#{@cid} changed state from #{oldState} to #{newState}" - @trigger c.event.change + ':state', this, oldState, newState + @trigger c.event.change + ":state", this, oldState, newState @tryRefresh() Object.defineProperties @prototype, @@ -160,21 +160,21 @@ module.exports = class MarkdownSectionController extends BaseController # BaseController Overrides ##################################################################### onDidRender: -> - @_imageListController = @addChild MarkdownImageListController, '.view__markdown_image_list', + @_imageListController = @addChild MarkdownImageListController, ".view__markdown_image_list", client: @_client imageBase: @_imageBase - @on c.event.change + ':imageBase', => @_imageListController.model.imageBase = @_imageBase - @listenTo @_imageListController, c.event.change + ':valid', => @tryRefresh() + @on c.event.change + ":imageBase", => @_imageListController.model.imageBase = @_imageBase + @listenTo @_imageListController, c.event.change + ":valid", => @tryRefresh() - @$errorPanel = @$('.error') - @$errorText = @$('.error p') - @$markdownPanel = @$('.markdown') - @$previewButton = @$('.button.preview') - @$questionPanel = @$('.question') - @$saveButton = @$('.button.save') - @$sizer = @$('.sizer') - @$textarea = @$('textarea') - @$title = @$('h2') + @$errorPanel = @$(".error") + @$errorText = @$(".error p") + @$markdownPanel = @$(".markdown") + @$previewButton = @$(".button.preview") + @$questionPanel = @$(".question") + @$saveButton = @$(".button.save") + @$sizer = @$(".sizer") + @$textarea = @$("textarea") + @$title = @$("h2") @resetToDefaultState() @@ -200,14 +200,14 @@ module.exports = class MarkdownSectionController extends BaseController events: -> return _.extend super, - 'click .markdown a': 'routeLinkClick' - 'click .button.cancel': 'onCancelClicked' - 'click .button.edit': 'onEditClicked' - 'click .button.preview': 'onPreviewClicked' - 'click .button.return': 'onReturnClicked' - 'click .button.save': 'onSaveClicked' - 'click .question a': 'onQuestionClicked' - 'input textarea': 'onTextChanged' + "click .markdown a": "routeLinkClick" + "click .button.cancel": "onCancelClicked" + "click .button.edit": "onEditClicked" + "click .button.preview": "onPreviewClicked" + "click .button.return": "onReturnClicked" + "click .button.save": "onSaveClicked" + "click .question a": "onQuestionClicked" + "input textarea": "onTextChanged" # Private Methods ############################################################################## @@ -228,14 +228,14 @@ module.exports = class MarkdownSectionController extends BaseController _updateButtonStates: -> for $button in [ @$previewButton, @$saveButton ] if @_imageListController.valid - $button.prop 'disabled', false + $button.prop "disabled", false else - $button.prop 'disabled', true + $button.prop "disabled", true _updateSizer: -> text = @model if @model? - text = text.replace /\n/g, '
' + text = text.replace /\n/g, "
" @$sizer.html text @@ -255,22 +255,22 @@ module.exports = class MarkdownSectionController extends BaseController logger.verbose => "Updating markdown section visibility for state: #{@state}" elements = - appologizingPanel: @$('.appologizing') - cancelButton: @$('.button.cancel') - confirmingPanel: @$('.confirming') - creatingPanel: @$('.creating') - editButton: @$('.button.edit') - editorPanel: @$('.editor') - footerPanel: @$('.footer') - imageList: @$('.view__markdown_image_list') + appologizingPanel: @$(".appologizing") + cancelButton: @$(".button.cancel") + confirmingPanel: @$(".confirming") + creatingPanel: @$(".creating") + editButton: @$(".button.edit") + editorPanel: @$(".editor") + footerPanel: @$(".footer") + imageList: @$(".view__markdown_image_list") markdownPanel: @$markdownPanel previewButton: @$previewButton - returnButton: @$('.button.return') + returnButton: @$(".button.return") saveButton: @$saveButton - waitingPanel: @$('.waiting') + waitingPanel: @$(".waiting") visible = {} - errorText = '' + errorText = "" if @state is @State.appologizing visible = appologizingPanel:true diff --git a/src/client/site/item_page/item_page.jade b/src/client/site/item_page/item_page.jade index 0a417a23c..c98a873ff 100644 --- a/src/client/site/item_page/item_page.jade +++ b/src/client/site/item_page/item_page.jade @@ -7,7 +7,7 @@ .content.view__item_page .left - include ../common/youtube/youtube.jade + // include ../common/youtube/youtube.jade .right .about diff --git a/src/client/site/item_page/item_page_controller.coffee b/src/client/site/item_page/item_page_controller.coffee index d095b5c3b..c1a2215ea 100644 --- a/src/client/site/item_page/item_page_controller.coffee +++ b/src/client/site/item_page/item_page_controller.coffee @@ -5,17 +5,19 @@ # All rights reserved. # -EditableFile = require "../../models/site/editable_file" -{Item} = require("crafting-guide-common").models -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" +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" ######################################################################################################################## @@ -52,8 +54,8 @@ module.exports = class ItemPageController extends PageController getBreadcrumbs: -> return [ - $("Browse") - $("#{@model.itemDisplay.mod.displayName}") + $("Browse") + $("#{@model.itemDisplay.mod.displayName}") $("#{@model.itemDisplay.name}") ] @@ -62,7 +64,7 @@ module.exports = class ItemPageController extends PageController return null unless item? display = new ItemDisplay item - return $("Random Item") + return $("Random Item") getMetaDescription: -> data = itemName:@model.item.displayName, modName:@model.item.mod.displayName @@ -79,11 +81,11 @@ module.exports = class ItemPageController extends PageController 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 + @_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', + @_descriptionController = @addChild MarkdownSectionController, ".view__markdown_section", client: @_client editable: true modPack: @_modPack @@ -92,23 +94,23 @@ module.exports = class ItemPageController extends PageController endEditing: => @_endEditingDescription() enterFeedback: @_enterFeedback - @$aboutImage = @$('.about img') - @$craftingPlanButton = @$('.button.craftingPlan') - @$name = @$('.about .title') - @$officialLink = @$('.about a.officialLink') - @$sourceModLink = @$('.about a.sourceMod') - @$aboutLinks = @$('.about .right') + @$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') + @$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: -> @@ -119,7 +121,7 @@ module.exports = class ItemPageController extends PageController @_descriptionController.imageBase = c.url.itemImageDir @model.itemDisplay if @model.item.detail?.links.length > 0 - @$officialLink.attr 'href', @model.item.detail.links[0] + @$officialLink.attr "href", @model.item.detail.links[0] @show @$aboutLinks else @hide @$aboutLinks @@ -155,20 +157,20 @@ module.exports = class ItemPageController extends PageController events: -> return _.extend super, - 'click a.craftingPlan': 'routeLinkClick' - 'click a.sourceMod': 'routeLinkClick' - 'click .markdown a': 'routeLinkClick' - 'click .button.craftingPlan': 'craftingPlanButtonClicked' + "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' + return w.reject new Error "must be logged in to edit" if not @model.item? - return w.reject new Error 'must have an item' + return w.reject new Error "must have an item" pathArgs = modSlug:@model.item.mod.id, itemSlug:@model.itemDisplay.itemSlug attributes = @@ -179,27 +181,29 @@ module.exports = class ItemPageController extends PageController @_descriptionFile.fetch() .then => if @_descriptionFile.encodedData?.length > 0 - @model.item.parse @_descriptionFile.getDecodedData 'utf8' + parser = new ItemDetailJsonParser item:@model.item + parser.parse @_descriptionFile.getDecodedData "utf8" else - @model.item.description = '' + @model.item.detail = new ItemDetail item:@model.item - @_descriptionController.model = @model.item.description + @_descriptionController.model = @model.item.detail.description _endEditingDescription: -> - oldDescription = @model.item.description + oldDescription = @model.item.detail.description promises = [] saveList = [] for imageFile in @_descriptionController.imageFiles saveList.push file: imageFile - message: "User-submitted image for #{@model.item.name} from #{global.hostName}" + message: "User-submitted image for #{@model.item.displayName} from #{global.hostName}" - @model.item.description = @_descriptionController.model - @_descriptionFile.setDecodedData @model.item.unparse() + @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.name} from #{global.hostName}" + message: "User-submitted text for #{@model.item.displayName} from #{global.hostName}" saveNextFile = (fileList)-> return w(true) if fileList.length is 0 @@ -211,7 +215,7 @@ module.exports = class ItemPageController extends PageController saveNextFile saveList .catch (e)=> - @model.item.description = oldDescription + @model.item.detail.description = oldDescription throw e _refreshDescription: -> @@ -225,7 +229,7 @@ module.exports = class ItemPageController extends PageController recipes = @model.findRecipes() if recipes?.length > 0 - @$recipesSectionTitle.html if recipes.length is 1 then 'Recipe' else 'Recipes' + @$recipesSectionTitle.html if recipes.length is 1 then "Recipe" else "Recipes" for recipe in recipes controller = @_recipeControllers[index] @@ -263,16 +267,16 @@ module.exports = class ItemPageController extends PageController _refreshSourceMod: -> mod = @model.item.mod - @$sourceModLink.attr 'href', c.url.mod @model.itemDisplay + @$sourceModLink.attr "href", c.url.mod @model.itemDisplay @$sourceModLink.text mod.name @show @$sourceModLink _refreshUsedAsToolToMake: -> - @_usedAsToolToMakeController.title = 'Used as Tool to Make' + @_usedAsToolToMakeController.title = "Used as Tool to Make" @_usedAsToolToMakeController.model = @model.findToolForItems() _refreshUsedToMake: -> - @_usedToMakeController.title = 'Used to Make' + @_usedToMakeController.title = "Used to Make" @_usedToMakeController.model = @model.findComponentInItems() _refreshVideos: -> @@ -281,7 +285,7 @@ module.exports = class ItemPageController extends PageController videos = @model.item.detail?.videos if videos? and videos.length > 0 - @$videosSectionTitle.html if videos.length is 1 then 'Video' else 'Videos' + @$videosSectionTitle.html if videos.length is 1 then "Video" else "Videos" for video in videos controller = @_videoControllers[index] diff --git a/src/common/constants.coffee b/src/common/constants.coffee index 8c1214f7a..4799b4d04 100644 --- a/src/common/constants.coffee +++ b/src/common/constants.coffee @@ -81,7 +81,7 @@ duration.slow = 1200 exports.gitHub = gitHub = {} gitHub.file = {} gitHub.file.itemDescription = {} -gitHub.file.itemDescription.fileName = _.template "item.cg" +gitHub.file.itemDescription.fileName = _.template "item.json" gitHub.file.itemDescription.path = _.template "/data/<%= modSlug %>/items/<%= itemSlug %>" exports.key = key = {} From 59217a5fea19ba6b283d75823599437a619a306a Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Sun, 23 Jul 2017 15:51:13 -0700 Subject: [PATCH 20/21] Quantity change should cause step count change fixes #294 --- src/client/site/common/recipe/recipe_controller.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/client/site/common/recipe/recipe_controller.coffee b/src/client/site/common/recipe/recipe_controller.coffee index 68eaf9c7e..f625427eb 100644 --- a/src/client/site/common/recipe/recipe_controller.coffee +++ b/src/client/site/common/recipe/recipe_controller.coffee @@ -30,6 +30,7 @@ module.exports = class RecipeController extends BaseController onWillChangeModel: (oldModel, newModel)-> if not newModel? then throw new Error "model is required" if newModel.constructor isnt RecipeDisplay then throw new Error "model must be a RecipeDisplay" + if @_typeController? then @_typeController.model = newModel return super oldModel, newModel refresh: -> From c45572997fef2d1cea579683105d589493c1d1e6 Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Sun, 23 Jul 2017 20:06:02 -0700 Subject: [PATCH 21/21] Make adjustments for mobile --- .../recipe/crafting_table/crafting_table.jade | 13 +-- .../recipe/crafting_table/crafting_table.scss | 95 +++++++++++++------ src/client/site/common/recipe/recipe.scss | 2 +- 3 files changed, 76 insertions(+), 34 deletions(-) diff --git a/src/client/site/common/recipe/crafting_table/crafting_table.jade b/src/client/site/common/recipe/crafting_table/crafting_table.jade index da52afb11..16d805b81 100644 --- a/src/client/site/common/recipe/crafting_table/crafting_table.jade +++ b/src/client/site/common/recipe/crafting_table/crafting_table.jade @@ -8,11 +8,12 @@ .view__crafting_table .input_inventory .view__inventory - .input_grid - .view__crafting_grid - .tool - .output_slot - .view__slot - .multiplier + .grid_block + .input_grid + .view__crafting_grid + .tool + .output_slot + .view__slot + .multiplier .output_inventory .view__inventory diff --git a/src/client/site/common/recipe/crafting_table/crafting_table.scss b/src/client/site/common/recipe/crafting_table/crafting_table.scss index f0edb4e91..3f8d5d173 100644 --- a/src/client/site/common/recipe/crafting_table/crafting_table.scss +++ b/src/client/site/common/recipe/crafting_table/crafting_table.scss @@ -15,42 +15,50 @@ margin-right: $size-margin-large; } - .input_grid { + .grid_block { flex: 1 1 100%; - align-items : center; - display : flex; - flex-direction : column; + display: flex; + align-items: center; + justify-content: center; - .view__crafting_grid { + .input_grid { flex: 0 0 auto; + + align-items : center; + display : flex; + flex-direction : column; + + .view__crafting_grid { + flex: 0 0 auto; + } + + .tool { + margin-top : $size-margin-small; + + font-family : $font-family-text; + font-size : $font-size-medium; + } } - .tool { - margin-top : $size-margin-small; + .output_slot { + flex: 0 0 auto; + margin-left: $size-margin-large; - font-family : $font-family-text; - font-size : $font-size-medium; - } - } + display : flex; + flex-direction : column; + justify-content : center; + align-items : center; - .output_slot { - flex: 0 0 auto; - margin-left: $size-margin-large; + .view__slot { + border: $size-border-medium solid $color-gray-medium; + } - display : flex; - flex-direction : column; - justify-content : center; - align-items : center; - - .view__slot { - border: $size-border-medium solid $color-gray-medium; - } - - .multiplier { - font-family : $font-family-header; - font-size : $font-size-large; - margin-top : $size-margin-medium; + .multiplier { + font-family : $font-family-header; + font-size : $font-size-large; + margin-top : $size-margin-medium; + } } } @@ -60,3 +68,36 @@ margin-left: $size-margin-large; } } + +@include screen-size(mobile) { + .view__crafting_table { + border-bottom: 1px solid $color-gray-light; + padding-bottom: $size-margin-medium; + + flex-direction: column; + align-items: center; + + .input_inventory { + flex: 0 0 auto; + margin-bottom: $size-margin-small; + } + + .grid_block { + flex: 0 0 auto; + + .tool { + margin-bottom: $size-margin-medium; + } + } + + .output_inventory { + flex: 0 0 auto; + margin-left: 0; + } + + .view__inventory { + margin-left: $size-margin-medium; + margin-right: $size-margin-medium; + } + } +} diff --git a/src/client/site/common/recipe/recipe.scss b/src/client/site/common/recipe/recipe.scss index 5d9bf6d57..1c9244d26 100644 --- a/src/client/site/common/recipe/recipe.scss +++ b/src/client/site/common/recipe/recipe.scss @@ -46,4 +46,4 @@ margin-top : $size-margin-medium; } } -} \ No newline at end of file +}