Author SHA1 Message Date
Andrew Miner 240a14da58 wip 2016-05-10 21:12:38 -07:00
Andrew Miner c441d75529 Fix layout issues on News Page 2016-05-07 14:50:06 -07:00
Andrew Miner 1bc89c1c89 Fix layout issues for News page 2016-05-07 14:47:07 -07:00
Andrew Miner 43202e9917 Add link to Twitter account
fixes #226
2016-05-07 14:41:47 -07:00
Andrew Miner 05bc1a271d Add support for Google Sitelinks
fixes #187
2016-05-07 13:36:49 -07:00
Andrew Miner da1419d6b6 Add a "Random Item" link to the breadcrumb bar
fixes #216
2016-05-07 12:25:21 -07:00
Andrew Miner 841fac38d3 Correct errors on mobile search feature
fixes #235, #233
2016-05-07 09:49:51 -07:00
Andrew Miner 2b8e23b32f Fix layout of video sections on mobile 2016-05-07 09:39:11 -07:00
Andrew Miner 5eae2bb488 Start editing after login needed for editing
When a user isn't logged in, click the "Edit" button on an item
description will initiate the login process.  After it is complete,
the user is placed back on the page where they started.  However,
the edit box remains closed.  So, after all the activity which
resulted in trying to edit, they user still has to click the edit
button one more time to actually start editing.

This change makes it so that the user returning from the login
process is placed directly into edit mode without having to click the
button a second time.

fixes #237
2016-05-07 08:12:39 -07:00
Andrew Miner 6fa18c764b Correct keyboard handling errors in item selector
fixes #227, #218
2016-05-06 21:30:41 -07:00
Andrew Miner c9796a142d Improve scrolling behavior on mobile
fixes #221
2016-05-05 21:20:41 -07:00
Andrew Miner 0718590f56 Don't use large inventory on mobile crafting page
fixes #219
2016-05-04 21:50:48 -07:00
Andrew Miner 51f566ebf1 Mark button for current page as active
fixes #232
2016-05-04 21:27:23 -07:00
Andrew Miner d2d904be7f Don't override index.html from prerendered pages 2016-05-04 20:20:44 -07:00
Andrew Miner 088994f366 Correct bug where prerendered pages don't display 2016-05-03 22:22:03 -07:00
Andrew Miner 184b64a6af No sourcemaps for CSS 2016-05-03 22:06:36 -07:00
Andrew Miner 4aca035709 Correct sizing problem with mod tiles 2016-05-03 20:42:36 -07:00
Andrew Miner ebf3443e96 Update Adsense to place ads on all devices
The current adsense implementation only places ads on desktop-sized
screens.  This change allows ads of the appropriate size to be
displayed on any device.

fixes #224
2016-05-03 20:25:56 -07:00
Andrew Miner fd5372b35d Add announcement of mobile site 2016-04-30 13:02:41 -07:00
Andrew Miner f464558cd2 Don't show "login" button on mobile 2016-04-30 13:00:14 -07:00
Andrew Miner e7cd3f0549 Complete mobile reactiveness in CSS layer 2016-04-30 11:31:49 -07:00
Andrew Miner 545408a7e7 Fixes for reactivity in Safari 2016-04-29 23:08:08 -07:00
Andrew Miner 83156c30c7 Initial progress towards responsive for mobile 2016-04-29 22:30:37 -07:00
Andrew Miner 636a8d061c Don't show page until fully loaded 2016-04-28 22:38:04 -07:00
Andrew Miner 2dbda99986 Allow FileCache to operate on file markers midline 2016-04-28 20:22:54 -07:00
Andrew Miner 7d83552013 Load all data files from a single archive 2016-04-27 22:47:44 -07:00
Andrew Miner 35bb12de6a Show crafting plan button only when craftable 2016-04-26 21:53:39 -07:00
Andrew Miner 1d1772e961 Make the mod version selector more clear
This change the single select box into a checkbox which toggles the
mod on/off.  If the mod is "on" and it has multiple versions, then
a selection list will be shown with the various possible versions.
If there is only a single available version, then the selector is
not shown.
2016-04-26 21:40:52 -07:00
Andrew Miner 6787063ac7 Prevent border around tool buttons on craft page 2016-04-26 20:31:51 -07:00
Andrew Miner 9e09b8d87c Make "outdated" background more pronounced 2016-04-26 20:25:20 -07:00
Andrew Miner 2c77972073 Correct several small bugs found in user testing
* The "Show Plan for Tools" link should open a new window each time
    it is clicked (i.e., don't re-use the same window)
  * Further customize the title of the crafting page to give some
    indication of what is being crafted
2016-04-25 21:54:28 -07:00
Andrew Miner 31f4594928 Don't show border on a pretending to be buttons 2016-04-24 15:21:12 -07:00
Andrew Miner eb9ac15de8 Show stack quantity tooltip for large quantities
When hovering over a quantity in an inventory display, if the
quantity is larger than one stack (i.e., 64 items), display a
tooltip showing the quantity in stacks (plus the remainder).
2016-04-24 15:17:46 -07:00
Andrew Miner e922f3c5cc Fix iOS viewport meta tag 2016-04-23 20:22:05 -07:00
Andrew Miner a8d08b93c5 Add reactive styles for Tablets 2016-04-23 20:10:09 -07:00
Andrew Miner 64e118a2c8 Open crafting plan for tools in a new window 2016-04-23 16:54:50 -07:00
Andrew Miner 6671541dcb Announce changes to crafting page 2016-04-23 11:58:48 -07:00
Andrew Miner 962165dc8e Don't automatically recalculate crafting plans
Instead, any time a change is made which invalidates a crafting plan,
update the visual display to show that the plan is out of date, and
add some extra affordances to recalculate.
2016-04-23 11:46:35 -07:00
Andrew Miner f9b65dd892 3.2.4 2016-04-21 22:59:37 -07:00
Andrew Miner 979586d9d3 Add Tinker's Construct 2016-04-21 22:59:00 -07:00
Andrew Miner c522e60e28 Fix router error on item page 2016-04-20 22:58:58 -07:00
Andrew Miner f9cd38947d Create item group controllers off main event loop 2016-04-20 22:30:55 -07:00
Andrew Miner 99b6cf2861 Don't clear user inventory between crafting plans 2016-04-20 22:30:14 -07:00
Andrew Miner d925a17940 Do not show pass-through items in derived items
For the various derived item groups on the item detail page, do not
show pass through items as being related (e.g., "Used to Make").
2016-04-20 22:28:42 -07:00
Andrew Miner a2bbdf4645 Improve perf. looking up item display data 2016-04-20 22:27:22 -07:00
Andrew Miner 93c98e16ac Further fixes of how passthrough items are handled
* When evaluating a plan, only give the pass-through treatment to
  items if the step they're part of was actually executed
* When marking a step "complete", ignore passthrough items
2016-04-16 20:33:05 -07:00
Andrew Miner 88e57b1200 Improve handling of pass-through items in recipes 2016-04-16 12:20:29 -07:00
Andrew Miner 1e96cf2d6c 3.2.3 2016-04-14 20:59:20 -07:00
Andrew Miner ccaf8e9842 Add ProjectRed 2016-04-14 20:54:44 -07:00
Andrew Miner e1f8282049 Fix bug with evaluating mod conditions 2016-04-10 14:10:23 -07:00
Andrew Miner d873c4b7f1 Fix layout bug on browse page in Safari 2016-04-10 14:09:56 -07:00
Andrew Miner 3529bccf3a Add back mods lost in website upgrade 2016-04-10 14:08:38 -07:00
95 changed files with 2301 additions and 462 deletions
+7 -2
View File
@@ -54,7 +54,7 @@ module.exports = (grunt)->
mode: 'gzip'
files: [
{expand: true, cwd:'./build/static', src:'**/*.css', dest:'./dist/'}
{expand: true, cwd:'./build/static', src:'**/*.html', dest:'./dist/'}
{expand: true, cwd:'./build/static', src:['**/*.html', '!**/index.html'], dest:'./dist/'}
{expand: true, cwd:'./build/static', src:'**/*.ugly.js', dest:'./dist/', ext: '.js'}
{expand: true, cwd:'./build/static', src:'**/*.json', dest:'./dist/'}
{expand: true, cwd:'./build/static', src:'**/*.ttf', dest:'./dist/'}
@@ -77,7 +77,10 @@ module.exports = (grunt)->
]
build_to_dist:
files: [
{expand:true, cwd:'./build/static/', src:['**/*', '!**/*.map', '!**/*.js'], dest:'./dist'}
expand: true
cwd: './build/static/'
src: ['**/*', '!**/*.map', '!**/*.js', '!index.html']
dest: './dist'
]
common_source:
files: [
@@ -135,6 +138,8 @@ module.exports = (grunt)->
sass:
all:
options:
sourcemap: 'none'
files:
'./build/static/main.css': [ './build/imports.scss' ]
Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "crafting-guide",
"version": "3.2.2",
"version": "3.2.4",
"description": "A guide for building anything in Minecraft or its many mods",
"main": "./dist/index.js",
"repository": "http://github.com/andrewminer/crafting-guide",
Binary file not shown.
@@ -0,0 +1,353 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ActiveLayerIndex</key>
<integer>0</integer>
<key>ApplicationVersion</key>
<array>
<string>com.omnigroup.OmniGraffle.MacAppStore</string>
<string>139.18</string>
</array>
<key>AutoAdjust</key>
<false/>
<key>BackgroundGraphic</key>
<dict>
<key>Bounds</key>
<string>{{0, 0}, {320, 320}}</string>
<key>Class</key>
<string>SolidGraphic</string>
<key>ID</key>
<integer>2</integer>
<key>Style</key>
<dict>
<key>shadow</key>
<dict>
<key>Draws</key>
<string>NO</string>
</dict>
<key>stroke</key>
<dict>
<key>Draws</key>
<string>NO</string>
</dict>
</dict>
</dict>
<key>BaseZoom</key>
<integer>0</integer>
<key>CanvasOrigin</key>
<string>{0, 0}</string>
<key>CanvasSize</key>
<string>{320, 320}</string>
<key>ColumnAlign</key>
<integer>1</integer>
<key>ColumnSpacing</key>
<real>36</real>
<key>CreationDate</key>
<string>2016-04-23 05:39:56 +0000</string>
<key>Creator</key>
<string>Andrew Miner</string>
<key>DisplayScale</key>
<string>1 pt = 1 px</string>
<key>GraphDocumentVersion</key>
<integer>8</integer>
<key>GraphicsList</key>
<array>
<dict>
<key>AllowConnections</key>
<string>NO</string>
<key>AllowLabelDrop</key>
<false/>
<key>AllowToConnect</key>
<false/>
<key>Class</key>
<string>LineGraphic</string>
<key>ID</key>
<integer>5</integer>
<key>Points</key>
<array>
<string>{160, 480}</string>
<string>{480, 160}</string>
</array>
<key>Style</key>
<dict>
<key>stroke</key>
<dict>
<key>Cap</key>
<integer>0</integer>
<key>Color</key>
<dict>
<key>a</key>
<string>0.2</string>
<key>b</key>
<string>0</string>
<key>g</key>
<string>1</string>
<key>r</key>
<string>1</string>
</dict>
<key>HeadArrow</key>
<string>0</string>
<key>Legacy</key>
<true/>
<key>TailArrow</key>
<string>0</string>
<key>Width</key>
<real>120</real>
</dict>
</dict>
</dict>
<dict>
<key>AllowConnections</key>
<string>NO</string>
<key>AllowLabelDrop</key>
<false/>
<key>AllowToConnect</key>
<false/>
<key>Class</key>
<string>LineGraphic</string>
<key>ID</key>
<integer>4</integer>
<key>Points</key>
<array>
<string>{-160, 160}</string>
<string>{160, -160}</string>
</array>
<key>Style</key>
<dict>
<key>stroke</key>
<dict>
<key>Cap</key>
<integer>0</integer>
<key>Color</key>
<dict>
<key>a</key>
<string>0.2</string>
<key>b</key>
<string>0</string>
<key>g</key>
<string>1</string>
<key>r</key>
<string>1</string>
</dict>
<key>HeadArrow</key>
<string>0</string>
<key>Legacy</key>
<true/>
<key>TailArrow</key>
<string>0</string>
<key>Width</key>
<real>120</real>
</dict>
</dict>
</dict>
<dict>
<key>AllowConnections</key>
<string>NO</string>
<key>AllowLabelDrop</key>
<false/>
<key>AllowToConnect</key>
<false/>
<key>Class</key>
<string>LineGraphic</string>
<key>ID</key>
<integer>3</integer>
<key>Points</key>
<array>
<string>{0, 320}</string>
<string>{320, 0}</string>
</array>
<key>Style</key>
<dict>
<key>stroke</key>
<dict>
<key>Cap</key>
<integer>0</integer>
<key>Color</key>
<dict>
<key>a</key>
<string>0.2</string>
<key>b</key>
<string>0</string>
<key>g</key>
<string>1</string>
<key>r</key>
<string>1</string>
</dict>
<key>HeadArrow</key>
<string>0</string>
<key>Legacy</key>
<true/>
<key>TailArrow</key>
<string>0</string>
<key>Width</key>
<real>120</real>
</dict>
</dict>
</dict>
</array>
<key>GridInfo</key>
<dict>
<key>GridSpacing</key>
<real>10</real>
<key>MajorGridSpacing</key>
<integer>10</integer>
<key>ShowsGrid</key>
<string>YES</string>
<key>SnapsToGrid</key>
<string>YES</string>
</dict>
<key>GuidesLocked</key>
<string>NO</string>
<key>GuidesVisible</key>
<string>YES</string>
<key>HPages</key>
<integer>1</integer>
<key>ImageCounter</key>
<integer>1</integer>
<key>KeepToScale</key>
<false/>
<key>Layers</key>
<array>
<dict>
<key>Lock</key>
<string>NO</string>
<key>Name</key>
<string>Layer 1</string>
<key>Print</key>
<string>YES</string>
<key>View</key>
<string>YES</string>
</dict>
</array>
<key>LayoutInfo</key>
<dict>
<key>Animate</key>
<string>NO</string>
<key>circoMinDist</key>
<real>18</real>
<key>circoSeparation</key>
<real>0.0</real>
<key>layoutEngine</key>
<string>dot</string>
<key>neatoSeparation</key>
<real>0.0</real>
<key>twopiSeparation</key>
<real>0.0</real>
</dict>
<key>LinksVisible</key>
<string>NO</string>
<key>MagnetsVisible</key>
<string>NO</string>
<key>MasterSheets</key>
<array/>
<key>ModificationDate</key>
<string>2016-04-27 03:11:38 +0000</string>
<key>Modifier</key>
<string>Andrew Miner</string>
<key>NotesVisible</key>
<string>NO</string>
<key>Orientation</key>
<integer>2</integer>
<key>OriginVisible</key>
<string>NO</string>
<key>PageBreaks</key>
<string>NO</string>
<key>PrintInfo</key>
<dict>
<key>NSBottomMargin</key>
<array>
<string>float</string>
<string>41</string>
</array>
<key>NSHorizonalPagination</key>
<array>
<string>coded</string>
<string>BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG</string>
</array>
<key>NSLeftMargin</key>
<array>
<string>float</string>
<string>18</string>
</array>
<key>NSPaperSize</key>
<array>
<string>size</string>
<string>{611.99998474121094, 792}</string>
</array>
<key>NSPrintReverseOrientation</key>
<array>
<string>int</string>
<string>0</string>
</array>
<key>NSRightMargin</key>
<array>
<string>float</string>
<string>18</string>
</array>
<key>NSTopMargin</key>
<array>
<string>float</string>
<string>18</string>
</array>
</dict>
<key>PrintOnePage</key>
<false/>
<key>ReadOnly</key>
<string>NO</string>
<key>RowAlign</key>
<integer>1</integer>
<key>RowSpacing</key>
<real>36</real>
<key>SheetTitle</key>
<string>Canvas 1</string>
<key>SmartAlignmentGuidesActive</key>
<string>YES</string>
<key>SmartDistanceGuidesActive</key>
<string>YES</string>
<key>UniqueID</key>
<integer>1</integer>
<key>UseEntirePage</key>
<false/>
<key>VPages</key>
<integer>1</integer>
<key>WindowInfo</key>
<dict>
<key>CurrentSheet</key>
<integer>0</integer>
<key>ExpandedCanvases</key>
<array>
<dict>
<key>name</key>
<string>Canvas 1</string>
</dict>
</array>
<key>Frame</key>
<string>{{215, 0}, {2134, 1417}}</string>
<key>ListView</key>
<true/>
<key>OutlineWidth</key>
<integer>142</integer>
<key>RightSidebar</key>
<false/>
<key>ShowRuler</key>
<true/>
<key>Sidebar</key>
<true/>
<key>SidebarWidth</key>
<integer>120</integer>
<key>VisibleRegion</key>
<string>{{-840, -477}, {1999, 1275}}</string>
<key>Zoom</key>
<real>1</real>
<key>ZoomValues</key>
<array>
<array>
<string>Canvas 1</string>
<real>1</real>
<real>1</real>
</array>
</array>
</dict>
</dict>
</plist>
@@ -0,0 +1,18 @@
//-
//- Crafting Guide - _google_sitelinks.jade
//-
//- Copyright © 2014-2016 by Redwood Labs
//- All rights reserved.
//-
script(type="application/ld+json").
{
"@context": "http://schema.org",
"@type": "WebSite",
"url": "http://crafting-guide.com/",
"potentialAction": {
"@type": "SearchAction",
"target": "http://crafting-guide.com?search={search_term}",
"query-input": "required name=search_term"
}
}
+11
View File
@@ -0,0 +1,11 @@
script.
! function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0],
p = /^http:/.test(d.location) ? 'http' : 'https';
if (!d.getElementById(id)) {
js = d.createElement(s);
js.id = id;
js.src = p + '://platform.twitter.com/widgets.js';
fjs.parentNode.insertBefore(js, fjs);
}
}(document, 'script', 'twitter-wjs');
+50 -9
View File
@@ -9,6 +9,9 @@
module.exports = class BaseModel extends Backbone.Model
@_loadingQueue = []
@_isDraining = false
constructor: (attributes={}, options={})->
options.logEvents ?= true
super attributes, options
@@ -19,10 +22,10 @@ module.exports = class BaseModel extends Backbone.Model
continue if name is 'id'
Object.defineProperty this, name, get:makeGetter(name), set:makeSetter(name)
@fileCache = options.fileCache or null
@loading = null
@logEvents = options.logEvents or false
@state = c.modelState.unloaded
@loading = null
@state = c.modelState.unloaded
Object.defineProperties this,
isUnloaded: { get:-> @state is c.modelState.unloaded }
@@ -60,12 +63,23 @@ module.exports = class BaseModel extends Backbone.Model
@state = c.modelState.loading
@trigger c.event.request, this
@loading = w.promise (resolve, reject)=>
$.ajax
url: url
dataType: 'text'
success: (text, status, xhr)=> resolve @onLoadSucceeded text, status, xhr
error: (xhr, status, error)=> reject @onLoadFailed error, status, xhr
loadFromServer = =>
w.promise (resolve, reject)=>
$.ajax
url: url
dataType: 'text'
success: (text, status, xhr)=> resolve @onLoadSucceeded text, status, xhr
error: (xhr, status, error)=> reject @onLoadFailed error, status, xhr
if @fileCache?
@loading = @fileCache.loading.then =>
if @fileCache.hasFile url
return @_addToLoadingQueue @fileCache.getFile(url), 'success', {url:url}
else
@loading = loadFromServer()
else
@loading = loadFromServer()
@loading.catch (e)-> # do nothing
return @loading
@@ -86,3 +100,30 @@ module.exports = class BaseModel extends Backbone.Model
toString: ->
return "#{@constructor.name}.#{@cid}"
# Private Methods ##############################################################################
_addToLoadingQueue: (text, status, xhr)->
deferred = w.defer()
BaseModel._loadingQueue.push resolve:deferred.resolve, func:(=> @onLoadSucceeded text, status, xhr)
@_drainLoadingQueue()
return deferred.promise
_drainLoadingQueue: ->
return if @_isDraining
@_isDraining = true
drainDelay = 50
drain = =>
toLoad = BaseModel._loadingQueue.shift()
if not toLoad?
@_isDraining = false
else
toLoad.func()
toLoad.resolve(true)
_.delay drain, drainDelay
_.delay drain, drainDelay
@@ -24,6 +24,7 @@ module.exports = class CraftingPlan
@_rawScores = {}
@_scores = {}
@_steps = steps
@_tools = null
@_want = want
@_numberSteps()
@@ -37,19 +38,32 @@ module.exports = class CraftingPlan
@_made = new SimpleInventory modPack:@_modPack
@_made.addInventory @_have
@_tools = new SimpleInventory modPack:@_modPack
for i in [@_steps.length-1..0] by -1
step = @_steps[i]
step.multiplier = 0
recipe = step.recipe
for stack in step.recipe.output
if not stack?
throw new Error 'stack should not be null here'
continue if recipe.isPassThroughFor stack.itemSlug
qualifiedSlug = @_modPack.qualifySlug stack.itemSlug
while @_need.quantityOf(qualifiedSlug) > 0
@_executeStep step
if step.multiplier > 0
for stack in step.recipe.output
qualifiedSlug = @_modPack.qualifySlug stack.itemSlug
continue unless recipe.isPassThroughFor stack.itemSlug
continue if @_made.hasAtLeast qualifiedSlug, 1
continue if @_need.hasAtLeast qualifiedSlug, 1
continue if @_tools.hasAtLeast qualifiedSlug, 1
@_need.add qualifiedSlug, 1
@_tools.add qualifiedSlug, 1
@_made.addInventory @_want
@_made.addInventory @_tools
@_pruneEmptySteps()
@_numberSteps()
@@ -63,6 +63,22 @@ describe 'crafting_plan.coffee', ->
'1x 8 test__iron_ore,test__coal>.0. ... .1.>test__furnace>8 test__iron_ingot'
]
it 'uses the correct amount of passthrough items', ->
plans = fixtures.makePlans [10, 'test__split_oak_wood'], [10, 'test__split_spruce_wood']
plan = plans[2]
plan.computeRequired()
plan.need.unparse().should.equal 'coal:8.iron_ore:6.oak_wood:5.spruce_wood'
plan.made.unparse().should.equal '4.iron_ingot:maul:2.oak_planks:10.split_oak_wood:10.split_spruce_wood:stick'
(s.toString() for s in plan.steps).should.eql [
'1x test__oak_wood>... .0. ...>>4 test__oak_planks'
'1x test__oak_planks>.0. .0. ...>>4 test__stick'
'1x 8 test__iron_ore,test__coal>.0. ... .1.>test__furnace>8 test__iron_ingot'
'1x test__iron_ingot,test__stick>001 001 ..1>test__crafting_table>test__maul'
'5x test__spruce_wood,test__maul>.1. .0. ...>>2 test__split_spruce_wood,test__maul'
'5x test__oak_wood,test__maul>.1. .0. ...>>2 test__split_oak_wood,test__maul'
]
it 'can compute multiple items with multiple plans', ->
plans = fixtures.makePlans [1, 'test__copper_block'], [1, 'test__iron_sword']
plans.length.should.equal 4
@@ -27,10 +27,11 @@ module.exports = class CraftingStep
addToolsTo: (targetInventory)->
for stack in @_recipe.tools
targetInventory.add stack.itemSlug, stack.quantity
targetInventory.add stack.itemSlug, stack.quantity, insert:true
completeInto: (targetInventory)->
for stack in @_recipe.output
continue if @_recipe.isPassThroughFor stack.itemSlug
quantity = @_recipe.getQuantityProduced stack.itemSlug
targetInventory.add stack.itemSlug, quantity * @_multiplier
@@ -67,4 +68,6 @@ module.exports = class CraftingStep
@_inventory = new SimpleInventory
for stack in @_recipe.input
qualifiedSlug = @_modPack.qualifySlug stack.itemSlug
@_inventory.add qualifiedSlug, @multiplier * @_recipe.getQuantityRequired stack.itemSlug
required = @_recipe.getQuantityRequired(stack.itemSlug) - @_recipe.getQuantityProduced(stack.itemSlug)
required = if required > 0 then required * @multiplier else 1
@_inventory.add qualifiedSlug, required
+20 -23
View File
@@ -22,57 +22,43 @@ module.exports = class Craftsman extends BaseModel
@::PLAN_STEP_INCREMENT = 39
@::STAGE =
WAITING: 'waiting'
EMPTY: 'empty'
READY: 'ready'
GRAPHING: 'examining recipes'
PLANNING: 'computing plans'
ANALYZING: 'analyzing plans'
COMPLETE: 'complete'
INVALID: 'invalid'
OUTDATED: 'outdated'
constructor: (modPack)->
if not modPack? then throw new Error 'modPack is required'
attributes =
paused: false
stage: @STAGE.WAITING
stage: @STAGE.READY
stageCount: 0
super attributes, {}
@_modPack = modPack
reset = _.debounce (=> @reset()), 100
reevaluatePlans = _.debounce (=> @reevaluatePlans()), 100
@_have = new Inventory modPack:@_modPack
@_have.on c.event.change, reevaluatePlans
@_have.on c.event.change, => @_resetStage()
@_want = new Inventory modPack:@_modPack
@_want.on c.event.change, reset
@_want.on c.event.change, => @_resetStage()
@on c.event.change + ':paused', reset
@on c.event.change + ':stage', => logger.info "Craftsman has started #{@stage}..."
@on 'scheduleNextWork', => @_scheduleNextWork()
@reset()
# Public Methods ###############################################################################
reevaluatePlans: ->
@_plans = null
@_planEvaluator = null
@stage = @STAGE.WAITING
@stageCount = 0
@_scheduleNextWork()
reset: ->
@_graphBuilder = null
@_planBuilder = null
@_planEvaluator = null
@_plans = null
@stage = @STAGE.WAITING
@stageCount = 0
@_scheduleNextWork()
@_resetStage()
work: ->
return if @_want.isEmpty
@@ -130,7 +116,7 @@ module.exports = class Craftsman extends BaseModel
Object.defineProperties @prototype,
complete:
get: -> @stage in [@STAGE.COMPLETE, @STAGE.INVALID]
get: -> @stage in [@STAGE.COMPLETE, @STAGE.INVALID, @STAGE.OUTDATED]
have:
get: -> @_have
@@ -143,8 +129,19 @@ module.exports = class Craftsman extends BaseModel
# Private Methods ##############################################################################
_resetStage: ->
@stageCount = 0
if @want.isEmpty
if @stage isnt @STAGE.EMPTY
@stage = @STAGE.EMPTY
@reset()
else if not @_plans?
@stage = @STAGE.READY
else
@stage = @STAGE.OUTDATED
_scheduleNextWork: ->
return if @paused
return if @want.isEmpty
return if @complete
@@ -98,6 +98,12 @@ MOD_VERSION_FILE =
input: Stick, Cobblestone
pattern: .0. .1. ...
item: Maul
recipe:
input: Iron Ingot, Stick
pattern: 001 001 ..1
tools: Crafting Table
item: Oak Planks
recipe:
input: Oak Wood
@@ -107,12 +113,29 @@ MOD_VERSION_FILE =
item: Oak Wood
gatherable: yes
item: Spruce Wood
gatherable: yes
item: Stick
recipe:
input: Oak Planks
pattern: .0. .0. ...
quantity: 4
item: Split Oak Wood
recipe:
extras: Maul
input: Oak Wood, Maul
pattern: .1. .0. ...
quantity: 2
item: Split Spruce Wood
recipe:
extras: Maul
input: Spruce Wood, Maul
pattern: .1. .0. ...
quantity: 2
item: String
gatherable: yes
@@ -44,7 +44,7 @@ module.exports = class SimpleInventory
@_itemSlugs = []
clone: ->
inventory = new Inventory
inventory = new SimpleInventory
inventory.addInventory this
return inventory
@@ -79,7 +79,7 @@ module.exports = class SimpleInventory
if qualifiedSlug?
newSlugs.push qualifiedSlug
newStacks.push new Stack itemSlug:qualifiedSlug, quantity:stack.quantity
newStacks.push new SimpleStack itemSlug:qualifiedSlug, quantity:stack.quantity
else
newSlugs.push itemSlug
newStacks.push stack
@@ -130,9 +130,9 @@ module.exports = class SimpleInventory
parse: (data)->
return this if not data? or data.length is 0
stacks = data.split Inventory.Delimiters.Stack
stacks = data.split SimpleInventory.Delimiters.Stack
for stackText in stacks
stackParts = stackText.split Inventory.Delimiters.Item
stackParts = stackText.split SimpleInventory.Delimiters.Item
if stackParts.length is 2
quantity = parseInt stackParts[0], 10
itemSlug = ItemSlug.slugify stackParts[1]
+3 -3
View File
@@ -1,9 +1,9 @@
###
#
# Crafting Guide - event_recorder.coffee
#
# Copyright (c) 2014-2015 by Redwood Labs
# Copyright © 2014-2016 by Redwood Labs
# All rights reserved.
###
#
util = require 'util'
+20 -4
View File
@@ -29,10 +29,10 @@ module.exports = class Inventory extends BaseModel
# Public Methods ###############################################################################
add: (itemSlug, quantity=1)->
add: (itemSlug, quantity=1, options={})->
return this unless quantity > 0
@_add itemSlug, quantity
@_add itemSlug, quantity, options
@trigger c.event.add, this, itemSlug, quantity
@trigger c.event.change, this
return this
@@ -141,6 +141,18 @@ module.exports = class Inventory extends BaseModel
@trigger c.event.change, this
return this
toDescription: ->
return null if @isEmpty
return null unless @modPack?
item = @modPack.findItem @_itemSlugs[0]
extras = @_itemSlugs.length - 1
result = "#{item.name}"
if extras > 0 then result += " and #{extras} more..."
return result
# Parsing Methods ##############################################################################
parse: (data)->
@@ -209,7 +221,8 @@ module.exports = class Inventory extends BaseModel
# Private Methods ##############################################################################
_add: (itemSlug, quantity=1)->
_add: (itemSlug, quantity=1, options={})->
options.insert ?= false
return unless itemSlug?
return unless quantity > 0
@@ -218,7 +231,10 @@ module.exports = class Inventory extends BaseModel
stack = new Stack itemSlug:itemSlug, quantity:quantity
@listenTo stack, c.event.change, => @trigger c.event.change, this
@_stacks[itemSlug] = stack
@_itemSlugs.push itemSlug
if options.insert
@_itemSlugs.unshift itemSlug
else
@_itemSlugs.push itemSlug
@_sort()
else
stack.quantity += quantity
+12 -2
View File
@@ -29,8 +29,6 @@ module.exports = class Mod extends BaseModel
@_modVersions = []
@_tutorials = []
@once c.event.sync, => @_verifyActiveModVersion()
# Class Methods ##################################################################################
@Version: Version =
@@ -95,6 +93,12 @@ module.exports = class Mod extends BaseModel
# Item Methods #################################################################################
chooseRandomItem: ->
effectiveModVersion = @_activeModVersion or @getModVersion Mod.Version.Latest
return null unless effectiveModVersion?
return effectiveModVersion.chooseRandomItem()
eachItem: (callback)->
effectiveModVersion = @_activeModVersion or @getModVersion Mod.Version.Latest
effectiveModVersion.eachItem callback
@@ -129,6 +133,7 @@ module.exports = class Mod extends BaseModel
@_modVersions.push modVersion
@listenTo modVersion, c.event.change, => @trigger c.event.change, this
modVersion.fileCache = this.fileCache
modVersion.mod = this
@trigger c.event.add + ':modVersion', modVersion, this
@@ -143,6 +148,9 @@ module.exports = class Mod extends BaseModel
for modVersion in @_modVersions
callback modVersion
getAllModVersions: ->
return @_modVersions[..]
getModVersion: (version)->
return null if version is Mod.Version.None
return @_modVersions[0] if version is Mod.Version.Latest
@@ -201,6 +209,8 @@ module.exports = class Mod extends BaseModel
@_parser ?= new ModParser model:this
@_parser.parse text
@_verifyActiveModVersion()
return null # prevent calling `set`
url: ->
+20 -7
View File
@@ -6,9 +6,10 @@
#
BaseModel = require '../base_model'
Inventory = require './inventory'
Mod = require './mod'
ModVersionParser = require '../parsing/mod_version_parser'
Recipe = require './recipe'
SimpleInventory = require '../crafting/simple_inventory'
########################################################################################################################
@@ -24,6 +25,12 @@ module.exports = class ModPack extends BaseModel
# Item Methods #################################################################################
chooseRandomItem: ->
return null unless @_mods.length > 0
modIndex = Math.floor Math.random() * @_mods.length
return @_mods[modIndex].chooseRandomItem()
findItem: (itemSlug, options={})->
options.includeDisabled ?= false
@@ -75,7 +82,7 @@ module.exports = class ModPack extends BaseModel
result.modSlug = @_mods[0].slug
result.modVersion = @_mods[0].activeVersion
craftingUrlInventory = new Inventory modPack:this
craftingUrlInventory = new SimpleInventory modPack:this
if item?.multiblock?
craftingUrlInventory.addInventory item.multiblock.inventory
else
@@ -165,12 +172,18 @@ module.exports = class ModPack extends BaseModel
# Private Methods ##############################################################################
_onModVersionLoaded: (modVersion)->
working = true
@eachMod (mod)->
mod.eachModVersion (modVersion)->
working = working and (modVersion.isUnloaded or modVersion.isLoading)
mods = @getAllMods()
return true unless mods.length > 0
return if working
for mod in mods
modVersions = mod.getAllModVersions()
return true unless modVersions.length > 0
continue if mod.activeVersion is Mod.Version.None
activeModVersion = mod.activeModVersion
return true unless activeModVersion?
return true if activeModVersion.isUnloaded
return true if activeModVersion.isLoading
@trigger c.event.change, this
@trigger c.event.sync, this
@@ -59,6 +59,10 @@ module.exports = class ModVersion extends BaseModel
return null if result.length is 0
return result
chooseRandomItem: ->
itemIndex = Math.floor Math.random() * @_slugs.length
return @_slugs[itemIndex]
eachItem: (callback)->
for slug in @_slugs
item = @findItem slug
+7 -12
View File
@@ -103,7 +103,7 @@ module.exports = class Recipe extends BaseModel
if modPack?.findItemByName(@condition.noun)?
result = true
else if @condition.verb is 'mod'
modPack.eachMod (mod)->
modPack.eachMod (mod)=>
if mod.name is @condition.noun
result = true
@@ -111,16 +111,7 @@ module.exports = class Recipe extends BaseModel
return result
isPassThroughFor: (itemSlug)->
amountCreated = 0
for stack in @output
if stack.itemSlug.matches itemSlug
amountCreated += stack.quantity
for stack in @input
if stack.itemSlug.matches itemSlug
amountCreated -= stack.quantity
return amountCreated <= 0
return @getQuantityProduced(itemSlug) is @getQuantityRequired(itemSlug)
produces: (itemSlug)->
if not @_produces?
@@ -221,7 +212,11 @@ module.exports = class Recipe extends BaseModel
_computeQuantities: (pattern)->
quantityMap = {}
for c in pattern.split ''
index = 0
while index < pattern.length
c = pattern[index]
index += 1
continue if c is '.'
continue if c is ' '
+1
View File
@@ -40,6 +40,7 @@ module.exports = class CraftPage extends BaseModel
inventory.each (stack)=>
item = @modPack.findItem stack.itemSlug, enableAsNeeded:true
return unless item? and item.isCraftable
@craftsman.want.add stack.itemSlug, stack.quantity
inventory.remove stack.itemSlug
+86
View File
@@ -0,0 +1,86 @@
#
# Crafting Guide - file_cache.coffee
#
# Copyright © 2014-2016 by Redwood Labs
# All rights reserved.
#
########################################################################################################################
module.exports = class FileCache extends Backbone.Events
@::FILE_TOKEN = '#file='
constructor: (url)->
@_ajax = $.ajax
@_files = {}
@_loading = w.resolve(true)
if url? then @loadArchive(url).catch(->)
# Public Methods ###############################################################################
getFile: (file)->
return null unless @hasFile file
return @_files[file]
hasFile: (file)->
return @_files[file]?
loadArchive: (url)->
if not _.isFunction(@_ajax) then throw new Error '$.ajax is required'
newLoading = w.promise (resolve, reject)=>
@_ajax
url: url
dataType: 'text'
success: (text, status, xhr)=> resolve @_onLoadSuccess text, status, xhr
error: (xhr, status, error)=> resolve @_onLoadError error, status, xhr
@_loading = w.join @_loading, newLoading
# Property Methods #############################################################################
Object.defineProperties @prototype,
loading:
get: -> return @_loading
# Private Methods ##############################################################################
_onLoadError: (error, status, xhr)->
console.error "Failed to load archive: #{xhr.responseText}"
return false
_onLoadSuccess: (text, status, xhr)->
return @_parseArchive text
_parseArchive: (text)->
file = null
tokenIndex = nameStartIndex = nameEndIndex = fileStartIndex = fileEndIndex = 0
fileCount = 0
while true
tokenIndex = text.indexOf @FILE_TOKEN, fileStartIndex
if tokenIndex is -1
if file?
@_files[file] = text.substring fileStartIndex, text.length
fileCount += 1
break
if file?
fileEndIndex = tokenIndex
@_files[file] = text.substring fileStartIndex, fileEndIndex
fileCount += 1
nameStartIndex = tokenIndex + @FILE_TOKEN.length
nameEndIndex = text.indexOf '\n', nameStartIndex
if nameEndIndex is -1
file = text.substring nameStartIndex, text.length
@_files[file] = ''
break
file = text.substring nameStartIndex, nameEndIndex
fileStartIndex = nameEndIndex + '\n'.length
return fileCount > 0
@@ -0,0 +1,72 @@
FileCache = require './file_cache'
########################################################################################################################
describe 'file_cache.coffee', ->
beforeEach ->
@cache = new FileCache
makeTestAjax = (text)->
return (options)->
options.success text, 'success', {url:options.url}
it 'can load an archive with a single file', ->
@cache._ajax = makeTestAjax '#file=alpha\nbravo charlie delta'
@cache.loadArchive 'http://test'
.then =>
@cache.hasFile('alpha').should.equal true
@cache.getFile('alpha').should.equal 'bravo charlie delta'
it 'can load an archive with multiple files', ->
@cache._ajax = makeTestAjax '#file=alpha\nbravo charlie\n#file=delta\necho foxtrot'
@cache.loadArchive 'http://test'
.then =>
@cache.hasFile('alpha').should.equal true
@cache.getFile('alpha').should.equal 'bravo charlie\n'
@cache.hasFile('delta').should.equal true
@cache.getFile('delta').should.equal 'echo foxtrot'
it 'can load an archive without newlines', ->
@cache._ajax = makeTestAjax '#file=alpha\nbravo charlie#file=delta\necho foxtrot'
@cache.loadArchive 'http://test'
.then =>
@cache.hasFile('alpha').should.equal true
@cache.getFile('alpha').should.equal 'bravo charlie'
@cache.hasFile('delta').should.equal true
@cache.getFile('delta').should.equal 'echo foxtrot'
it 'can cope with an empty file in the middle of an archive', ->
@cache._ajax = makeTestAjax '#file=alpha\nbravo charlie\n#file=delta\n#file=echo\nfoxtrot golf'
@cache.loadArchive 'http://test'
.then =>
@cache.hasFile('alpha').should.equal true
@cache.getFile('alpha').should.equal 'bravo charlie\n'
@cache.hasFile('delta').should.equal true
@cache.getFile('delta').should.equal ''
@cache.hasFile('echo').should.equal true
@cache.getFile('echo').should.equal 'foxtrot golf'
it 'can cope with an empty file at the end of an archive', ->
@cache._ajax = makeTestAjax '#file=alpha\nbravo charlie\n#file=delta'
@cache.loadArchive 'http://test'
.then =>
@cache.hasFile('alpha').should.equal true
@cache.getFile('alpha').should.equal 'bravo charlie\n'
@cache.hasFile('delta').should.equal true
@cache.getFile('delta').should.equal ''
it 'can load multiple, non-overlapping archives', ->
@cache._ajax = makeTestAjax '#file=alpha\nbravo charlie\n#file=delta\necho foxtrot'
@cache.loadArchive 'http://test'
@cache._ajax = makeTestAjax '#file=golf\nhotel india'
@cache.loadArchive 'http://test2'
.then =>
@cache.hasFile('alpha').should.equal true
@cache.getFile('alpha').should.equal 'bravo charlie\n'
@cache.hasFile('delta').should.equal true
@cache.getFile('delta').should.equal 'echo foxtrot'
@cache.hasFile('golf').should.equal true
@cache.getFile('golf').should.equal 'hotel india'
+1
View File
@@ -47,6 +47,7 @@ module.exports = class ItemPage extends BaseModel
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
@@ -7,7 +7,6 @@
.content.view__browse_page
.left
.view__adsense
.right
.tile_container
+22 -4
View File
@@ -10,14 +10,32 @@
.right {
.tile_container {
display : flex;
flex-wrap : wrap;
justify-content : space-between;
display : flex;
flex-wrap : wrap;
.view__mod_tile {
max-width : calc(50% - 12px); // $size-margin-large / 2
flex : 1 1 calc(50% - 12px); // $size-margin-large / 2
margin-right : $size-margin-medium;
margin-bottom : $size-margin-large;
}
}
}
}
@include screen-size(tablet) {
.view__browse_page {
.right {
.tile_container {
flex-direction: column;
flex-wrap: nowrap;
align-items: stretch;
.view__mod_tile {
flex: 0 0 auto;
margin-right: 0;
width: 100%;
}
}
}
}
}
@@ -5,7 +5,6 @@
# All rights reserved.
#
AdsenseController = require '../common/adsense/adsense_controller'
ModTileController = require './mod_tile/mod_tile_controller'
PageController = require '../page_controller'
@@ -32,8 +31,6 @@ module.exports = class BrowsePageController extends PageController
# BaseController Overrides #####################################################################
onDidRender: ->
@_adsenseController = @addChild AdsenseController, '.view__adsense', model:'skyscraper'
@$tileContainer = @$('.tile_container')
refresh: ->
@@ -6,16 +6,14 @@
//
.view__mod_tile {
min-width : $size-minecraft-block * 9;
min-width : $size-minecraft-block * 9;
display : flex;
justify-content : stretch;
align-items : stretch;
display: flex;
a {
max-width: 100%;
@include floating-panel;
flex: 1 1 auto;
border : $size-border-medium solid $color-background-panel;
color : $color-text;
text-decoration : none;
@@ -39,6 +37,7 @@
overflow : hidden;
.title {
max-width: 0;
margin-bottom : $size-margin-medium;
font-family : $font-family-header;
@@ -86,3 +85,20 @@
}
}
}
@include screen-size(mobile) {
.view__mod_tile {
min-width: 0;
a {
& > .left {
flex: 0 0 $size-minecraft-block * 2;
img {
width: $size-minecraft-block * 2;
max-height: $size-minecraft-block * 2;
}
}
}
}
}
@@ -12,6 +12,7 @@ BaseController = require '../../base_controller'
module.exports = class ModTileController extends BaseController
constructor: (options={})->
options.tagName = 'section'
options.templateName = 'browse_page/mod_tile'
super options
+52 -8
View File
@@ -6,20 +6,64 @@
//
.view__adsense {
.skyscraper {
height : $size-skyscraper-height;
width : $size-skyscraper-width;
position : relative;
left : 50%;
margin : $size-margin-large 0;
position : relative;
transform : translate(-50%);
border : 0.1em solid $color-gray-faint;
margin : $size-margin-large 0;
ins {
position: absolute; top: 0; right: 0; bottom: 0; left: 0;
}
&.large-mobile-banner {
height : $size-ad-large-mobile-banner-height;
width : $size-ad-large-mobile-banner-width;
&.placeholder:before {
font-size : $font-size-large;
}
}
&.leaderboard {
height : $size-ad-leaderboard-height;
width : $size-ad-leaderboard-width;
&.placeholder:before {
font-size : $font-size-xxlarge;
}
}
&.skyscraper {
height : $size-ad-skyscraper-height;
width : $size-ad-skyscraper-width;
&.placeholder:before {
transform : rotate(90deg);
font-size : $font-size-xxlarge;
}
&:first-child {
margin-top : 0;
}
}
ins {
position: absolute; top: 0; right: 0; bottom: 0; left: 0;
&.placeholder {
border : $size-border-small solid $color-gray-faint;
display : flex;
align-items : center;
justify-content : center;
&:before {
color : $color-gray-faint;
content : "GOOGLE ADSENSE";
font-family : $font-family-control;
letter-spacing : $size-margin-small;
white-space : nowrap;
}
}
}
.view__mod_tile + .view__adsense {
margin-top : 0;
}
@@ -5,63 +5,132 @@
# All rights reserved.
#
BaseController = require '../../base_controller'
########################################################################################################################
module.exports = class AdsenseController extends BaseController
constructor: (options={})->
options.templateName = 'common/adsense'
super options
module.exports = class AdsenseController
constructor: ->
@_adsEnabled = global.env in c.productionEnvs
@_adCount = 0
@_adsPlaced = 0
@_waiting = false
# Public Methods ###############################################################################
fillAdPositions: ->
if @_adCount > 0
return unless @$sidebar and @$mainBody
return unless @_adCount < @_computeMaxAds()
return unless @_adCount < c.adsense.slotIds.length
adType = @_computeAdType()
maxAds = c.adsense[adType].slotIds.length - @_adsPlaced
return if maxAds is 0
$adContainer = $('<div class="skyscraper"></div>')
@$el.append $adContainer
logger.verbose => "Looking to place #{maxAds} more #{adType} ads..."
if @_adsEnabled
$ad = $('<ins class="adsbygoogle"></ins>')
$ad.attr 'data-ad-client', c.adsense.clientId
$ad.attr 'data-ad-slot', c.adsense.slotIds[@_adCount]
$adContainer.append $ad
@_loadAds()
if adType is 'skyscraper'
placedNewAd = @_createSkyscraperPositions()
else
placedNewAd = @_createBannerPositions adType
@_adCount += 1
_.defer => @fillAdPositions()
if @_adsPlaced < c.adsense[adType].slotIds.length
duration = if placedNewAd then 0 else c.adsense.readinessCheckInterval
_.delay (=> @fillAdPositions()), duration
else
logger.verbose => "All #{adType} ad positions filled"
# BaseController Overrides #####################################################################
onDidRender: ->
@$mainBody = $('.page > .content > .right')
@$sidebar = $('.page > .content > .left')
super
refresh: ->
reset: ->
@_adsPlaced = 0
@_waitForPageReadiness()
super
# Private Methods #############################################################################
_computeMaxAds: ->
return null unless @$sidebar
result = Math.floor @$sidebar.height() / (c.adsense.skyscraper.height + c.adsense.skyscraper.margin)
_computeAdType: ->
return c.adsense.adTypeMap[c.screen.type.compute()]
_computeAdCount: (adType)->
result = c.adsense[adType].slotIds.length
if c.screen.type.compute() is c.screen.type.desktop
$sidebar = $('.page > .content > .left')
return 0 unless $sidebar?.length
available = $sidebar.height() + c.adsense.skyscraper.margin
available = Math.floor available / (c.adsense.skyscraper.height + c.adsense.skyscraper.margin)
result = Math.min available, result
return result
_loadAds: ->
_createSkyscraperPositions: ->
$sidebar = $('.page > .content > .left')
remaining = @_computeAdCount 'skyscraper'
remaining -= @_adsPlaced
placedNewAd = false
while remaining > 0
$el = $('<div class="view__adsense"></div>')
$el.addClass c.adsense.skyscraper.cssClass
if @_adsEnabled
$ad = $('<ins class="adsbygoogle"></ins>')
$ad.attr 'data-ad-client', c.adsense.clientId
$ad.attr 'data-ad-slot', c.adsense.skyscraper.slotIds[@_adsPlaced]
$el.append $ad
else
$el.addClass 'placeholder'
$sidebar.append $el
placedNewAd = true
@_adsPlaced += 1
remaining -= 1
logger.info => "Placed skyscraper ad ##{@_adsPlaced}"
@_loadAd()
return placedNewAd
_createBannerPositions: (adType)->
$pageContent = $('.page > .content > .right')
remaining = @_computeAdCount adType
remaining -= @_adsPlaced
sectionIndex = 0
placedNewAd = false
for sectionEl in $pageContent.find('section')
break unless remaining > 0
$section = $(sectionEl)
continue unless $section.is ':visible'
sectionIndex += 1
continue if sectionIndex % 2 is 0
continue if $section.next().hasClass 'view__adsense'
$el = $('<div class="view__adsense"></div>')
$el.addClass c.adsense[adType].cssClass
if @_adsEnabled
$ad = $('<ins class="adsbygoogle"></ins>')
$ad.attr 'data-ad-client', c.adsense.clientId
$ad.attr 'data-ad-slot', c.adsense[adType].slotIds[@_adsPlaced]
$el.append $ad
else
$el.addClass 'placeholder'
$section.after $el
placedNewAd = true
@_adsPlaced += 1
remaining -= 1
logger.info => "Placed #{adType} ad ##{@_adsPlaced}"
@_loadAd()
return placedNewAd
_isTooClose: ($priorEl, $el)->
return false if c.screen.type.compute() is c.screen.type.desktop
return false if not $priorEl?
priorBottom = $priorEl.position().top + $priorEl.height()
currentTop = $el.position().top
return priorBottom + c.adsense.minimumDistance > currentTop
_loadAd: ->
return unless @_adsEnabled
logger.info "Loading #{@_adCount} Google AdSense ads"
logger.info "Loading Google AdSense ads"
try
global.adsbygoogle ||= []
global.adsbygoogle.push {}
@@ -70,11 +139,12 @@ module.exports = class AdsenseController extends BaseController
_waitForPageReadiness: ->
return if @_waiting
adCount = @_computeAdCount @_computeAdType()
if @$sidebar.height() < c.adsense[@model].height / 2
if adCount is 0
logger.verbose "Adsense is waiting for room to insert ads"
@_waiting = true
_.delay (=> @_waiting = false; @_waitForPageReadiness()), c.duration.normal
_.delay (=> @_waiting = false; @_waitForPageReadiness()), c.adsense.readinessCheckInterval
else
logger.verbose "Adsense is ready to fill ads"
@fillAdPositions()
@@ -9,5 +9,5 @@
.item_container
.empty_placeholder nothing
.buttons
.button.item-selector: .bezel: p add an item...
.button.item-selector: .bezel: p add<span class="full"> an item</span>...
.button.clear: .bezel: p clear
@@ -38,12 +38,24 @@
margin-top: $size-margin-large;
.item-selector {
flex : 85%;
flex : 80%;
margin-right : $size-margin-medium;
@include screen-size(mobile) {
flex: 50%;
.full {
display: none;
}
}
}
.clear {
flex : 15%;
flex : 20%;
@include screen-size(mobile) {
flex: 50%;
}
}
}
}
@@ -61,8 +73,12 @@
.quantity {
padding-right : $size-margin-medium;
input {
width: 3em;
font-size : $font-size-xlarge;
width : 3em;
font-size : $font-size-xlarge;
@include screen-size(mobile) {
width : 2em;
}
}
}
@@ -17,3 +17,23 @@
}
}
}
@include screen-size(tablet) {
.view__item_group {
.panel {
.view__item_tile {
width: calc(50% - 8px); // $size-margin-xsmall * 2
}
}
}
}
@include screen-size(mobile) {
.view__item_group {
.panel {
.view__item_tile {
width: 100%;
}
}
}
}
@@ -10,7 +10,7 @@
overflow: visible;
display: flex;
align-items: center;
align-items: flex-start;
img {
height: $size-minecraft-block;
@@ -22,9 +22,19 @@
font-family: $font-family-text;
font-size: $font-size-medium;
line-height: $size-minecraft-block;
overflow-x: hidden;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
@include screen-size(mobile) {
.view__item_tile {
a {
p {
white-space: normal;
}
}
}
}
@@ -48,7 +48,6 @@
}
&.selected {
flex : 0 0 auto;
background : $color-active-hover;
.name {
@@ -9,6 +9,6 @@
.view__item_selector_popup
.search
img(src='/images/search.png')
input(placeholder='enter the name of an item')
input(placeholder='enter an item name')
img.close(src='/images/close.png')
.results
@@ -9,6 +9,7 @@
}
.view__item_selector_popup {
max-width: $size-minecraft-block * 20;
height : 66%;
background : $color-background-panel;
@@ -35,6 +36,7 @@
input {
flex: 1 1 100%;
min-width: $font-size-large * 10;
background: none;
border: 0;
@@ -50,8 +52,15 @@
.results {
flex: 1 1 100%;
position: relative;
overflow-x: hidden;
overflow-y: scroll;
}
}
@include screen-size(mobile) {
.view__item_selector_popup {
position: fixed; top: 0; left: 0; height: 100%; width: 100%;
}
}
@@ -71,10 +71,10 @@ module.exports = class ItemSelectorController extends BaseController
when c.key.enter
@_chooseSelected()
return false
when c.key.down
when c.key.downArrow
@_selectNext()
return false
when c.key.up
when c.key.upArrow
@_selectPrevious()
return false
@@ -82,6 +82,7 @@ module.exports = class ItemSelectorController extends BaseController
@model.hint = @$hintField.val()
@tryRefresh()
@onResultSelected @_elementControllers[0]
return false
onPopupClicked: (event)->
return false
@@ -90,6 +91,7 @@ module.exports = class ItemSelectorController extends BaseController
@_session.resolve controller.model.slug
@_session = null
@_close()
return false
onResultSelected: (controller)->
for c in @_elementControllers
@@ -98,6 +100,8 @@ module.exports = class ItemSelectorController extends BaseController
if controller?
controller.selected = true
return false
onScreenClicked: (event)->
@_close()
return false
@@ -169,6 +173,8 @@ module.exports = class ItemSelectorController extends BaseController
@_elementControllers.pop().remove()
_selectNext: ->
return unless @_elementControllers.length > 0
for i in [0...(@_elementControllers.length - 1)] by 1
controller = @_elementControllers[i]
nextController = @_elementControllers[i + 1]
@@ -179,7 +185,13 @@ module.exports = class ItemSelectorController extends BaseController
@_showElement nextController.$el
return
controller = @_elementControllers[0]
controller.selected = true
@_showElement controller.$el
_selectPrevious: ->
return unless @_elementControllers.length > 0
for i in [1...@_elementControllers.length] by 1
previousController = @_elementControllers[i - 1]
controller = @_elementControllers[i]
@@ -190,6 +202,10 @@ module.exports = class ItemSelectorController extends BaseController
@_showElement previousController.$el
return
controller = @_elementControllers[@_elementControllers.length - 1]
controller.selected = true
@_showElement controller.$el
_showElement: ($el)->
top = $el.position().top + @$resultsContainer.scrollTop()
@$resultsContainer.css 'scrollTop', top
@$resultsContainer.animate {scrollTop:top}, c.duration.snap
@@ -128,3 +128,15 @@
}
}
}
@include screen-size(mobile) {
.view__markdown_section {
.creating {
padding-bottom: $size-margin-xlarge;
}
.footer {
display: none;
}
}
}
@@ -60,16 +60,15 @@ module.exports = class MarkdownSectionController extends BaseController
# Event Methods ################################################################################
onCancelClicked: (event)->
event.preventDefault()
@model = @_originalModel
@resetToDefaultState()
@_imageListController.reset()
@_updatePreview()
return false
onEditClicked: (event)->
event.preventDefault()
return unless @editable
return false unless @editable
@_originalModel = @model
@state = @State.waiting
@@ -81,22 +80,22 @@ module.exports = class MarkdownSectionController extends BaseController
@state = @State.appologizing
w(true).delay(@_confirmDuration).then => @resetToDefaultState()
return false
onQuestionClicked: (event)->
event.preventDefault()
@_enterFeedback ''
return false
onPreviewClicked: (event)->
event.preventDefault()
@_updatePreview()
@state = @State.previewing
return false
onReturnClicked: (event)->
event.preventDefault()
@state = @State.editing
return false
onSaveClicked: (event)->
event.preventDefault()
@state = @State.waiting
@_endEditing()
.then =>
@@ -109,9 +108,11 @@ module.exports = class MarkdownSectionController extends BaseController
.then =>
@state = @State.viewing
return false
onTextChanged: (event)->
event.preventDefault()
@model = @$textarea.val()
return false
# Property Methods #############################################################################
+6 -2
View File
@@ -9,12 +9,16 @@
display: flex;
.input {
flex: 1 1 50%;
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;
@@ -24,7 +28,7 @@
}
.output {
flex: 1 1 50%;
flex: 1 1 100%;
margin-left: $size-margin-medium;
display : flex;
+3 -1
View File
@@ -6,7 +6,9 @@
//-
.view__stack
.quantity: input
.quantity
input
.hover
.icon: img(src='')
.name: a
.action.first(style="display: none")
+43
View File
@@ -21,6 +21,7 @@
.quantity {
padding-right : $size-margin-medium;
position : relative;
text-align : right;
input {
@@ -32,6 +33,38 @@
font-size : $font-size-large;
text-align : right;
}
.hover {
$backgroundColor: fade-out($color-black, 0.25);
display: none;
position: absolute; left: 50%; top: -($font-size-large * 2);
transform: translateX(-50%);
background: $backgroundColor;
color: $color-white;
font-family: $font-family-control;
font-size: $font-size-medium;
padding: $size-margin-small;
z-index: $layer-dialog;
&:after {
position: absolute; top: 100%; left: calc(50% - 9px); // $font-size-large / 2
content: "";
width: 0;
height: 0;
border-style: solid;
border-width: $size-margin-medium $size-margin-medium 0 $size-margin-medium;
border-color: $backgroundColor transparent transparent transparent;
}
}
&:hover {
.hover.enabled {
display: block;
}
}
}
.icon {
@@ -84,3 +117,13 @@
}
}
}
@include screen-size(mobile) {
.view__stack.editable {
.quantity {
input {
width : 1.5em;
}
}
}
}
@@ -19,6 +19,7 @@ Events:
module.exports = class StackController extends BaseController
@::MAX_QUANTITY = 9999
@::STACK_SIZE = 64
constructor: (options={})->
if not options.imageLoader? then throw new Error 'options.imageLoader is required'
@@ -107,6 +108,7 @@ module.exports = class StackController extends BaseController
@$image = @$('.icon img')
@$nameLink = @$('.name a')
@$quantityField = @$('.quantity input')
@$quantityHover = @$('.quantity .hover')
@$secondAction = @$('.action.second')
@$secondButton = @$('.action.second .button')
super
@@ -124,6 +126,7 @@ module.exports = class StackController extends BaseController
@$quantityField.val quantityText
@_refreshButtons()
@_refreshHover()
if @_editable
@$el.addClass 'editable'
@@ -169,6 +172,20 @@ module.exports = class StackController extends BaseController
when 'remove' then $label.text '-'
when 'up' then $label.text '⬆︎'
_refreshHover: ->
if @model.quantity > @STACK_SIZE
remainder = @model.quantity % @STACK_SIZE
stacks = (@model.quantity - remainder) / @STACK_SIZE
text = "#{stacks}x#{@STACK_SIZE}"
text += "+#{remainder}" if remainder > 0
@$quantityHover.text text
@$quantityHover.addClass 'enabled'
else
@$quantityHover.text ''
@$quantityHover.removeClass 'enabled'
_updateButtonType: ($button, type)->
for currentType in ['check', 'down', 'remove', 'up']
$button.removeClass currentType
@@ -0,0 +1,18 @@
//-
//- Crafting Guide - twitter.jade
//-
//- Copyright © 2014-2016 by Redwood Labs
//- All rights reserved.
//-
.view__twitter
.left
img(src="/images/twitter.png")
.right
.instructions Follow us for updates!
a(
href="https://twitter.com/Crafting_Guide"
class="twitter-follow-button"
data-show-count="false"
data-size="large"
) Follow @Crafting_Guide
@@ -0,0 +1,62 @@
//
// Crafting Guide - news_page.scss
//
// Copyright © 2014-2016 by Redwood Labs
// All rights reserved.
//
.view__twitter {
display: flex;
& > .left {
flex: 1 1 50%;
display: flex;
align-items: center;
justify-content: center;
img {
height: $size-minecraft-block * 4;
width: $size-minecraft-block * 4;
}
}
& > .right {
flex: 1 1 50%;
display: flex;
flex-direction: column;
align-items: center;
.instructions {
flex: 1 1 50%;
margin-bottom: $size-margin-medium;
margin-top: $size-margin-medium;
font-family: $font-family-header;
font-size: $font-size-xlarge;
text-align: center;
}
iframe {
flex: 1 1 50%;
}
}
}
@include screen-size(mobile) {
.view__twitter {
& > .left {
img {
height: $size-minecraft-block * 3;
width: $size-minecraft-block * 3;
}
}
& > .right {
.instructions {
font-size: $font-size-xlarge;
}
}
}
}
+1 -1
View File
@@ -6,5 +6,5 @@
//-
.view__video
iframe(width="356", height="267", src="", frameborder="0", allowfullscreen="true")
iframe(src="", frameborder="0", allowfullscreen="true")
.caption: p
+4
View File
@@ -11,6 +11,10 @@
align-items: center;
justify-content: center;
iframe {
max-width: 100%;
}
.caption {
margin-top: $size-margin-small;
+9 -17
View File
@@ -5,16 +5,8 @@
//- All rights reserved.
//-
- var quarryHref = '/craft/quarry'
- var quarry
- var quantumSuitHref = '/craft/quantumsuit_bodyarmor:quantumsuit_boots:quantumsuit_helmet:quantumsuit_leggings'
- var ic2Href = '/browse/industrial_craft_2'
- var solarPanelHref = '/craft/solar_panel_vi'
- var solarFluxHref = '/browse/solar_flux'
.content.view__craft_page
.left
.view__adsense
.right
section.instructions
@@ -26,19 +18,19 @@
p.
Not sure what you'd like to make? Try one of these:
.items
a(href="/craft/potion_of_strength_ii_1_30")
a(href="/" data-slug="potion_of_strength_ii_1_30")
img(src="/data/minecraft/items/potion_of_strength_ii_1_30/icon.png")
a(href="/craft/quarry")
a(href="/" data-slug="quarry")
img(src="/data/buildcraft/items/quarry/icon.png")
a(href="/craft/quantumsuit_bodyarmor:quantumsuit_boots:quantumsuit_helmet:quantumsuit_leggings")
a(href="/" data-slug="quantumsuit_bodyarmor:quantumsuit_boots:quantumsuit_helmet:quantumsuit_leggings")
img(src="/data/ic2_classic/items/quantumsuit_helmet/icon.png")
a(href="/craft/solar_panel_vi")
a(href="/" data-slug="solar_panel_vi")
img(src="/data/solar_flux/items/solar_panel_vi/icon.png")
a(href="/craft/crystal_chest")
a(href="/" data-slug="crystal_chest")
img(src="/data/iron_chests/items/crystal_chest/icon.png")
a(href="/craft/digital_miner")
a(href="/" data-slug="digital_miner")
img(src="/data/mekanism/items/digital_miner/icon.png")
a(href="/craft/2.tesseract")
a(href="/" data-slug="2.tesseract")
img(src="/data/thermal_expansion/items/tesseract/icon.png")
section.want
@@ -51,8 +43,6 @@
.panel
.view__inventory.large.editable
section.view__craftsman_working
section.need
h2 Need to Gather
.panel
@@ -61,3 +51,5 @@
section.steps
h2 Steps
.panel
section.view__craftsman_working
@@ -49,4 +49,14 @@
}
}
}
&.outdated {
section.need .panel {
background: $color-white url('/images/panel-background-outdated.png') repeat;
}
section.steps .panel {
background: $color-white url('/images/panel-background-outdated.png') repeat;
}
}
}
@@ -5,19 +5,21 @@
# All rights reserved.
#
AdsenseController = require '../common/adsense/adsense_controller'
BaseController = require '../base_controller'
CraftPage = require '../../models/site/craft_page'
Craftsman = require '../../models/crafting/craftsman'
CraftsmanWorkingController = require './craftsman_working/craftsman_working_controller'
InventoryController = require '../common/inventory/inventory_controller'
PageController = require '../page_controller'
SimpleInventory = require '../../models/crafting/simple_inventory'
StepController = require './step/step_controller'
########################################################################################################################
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'
@@ -33,10 +35,9 @@ module.exports = class CraftPageController extends PageController
@_router = options.router
@_storage = options.storage
# c.event Methods ################################################################################
# Event Methods ################################################################################
onHaveInventoryChanged: ->
logger.warning => "storing have: #{@model.craftsman.have.unparse()}"
@_storage.store 'crafting-plan:have', @model.craftsman.have.unparse()
onMoveNeedToHave: (itemSlug)->
@@ -50,27 +51,39 @@ module.exports = class CraftPageController extends PageController
@model.craftsman.want.remove itemSlug
@onWantInventoryChanged()
onSampleClicked: (event)->
$el = $(event.target)
while $el.length > 0
inventoryText = $el.attr 'data-slug'
break if inventoryText
$el = $el.parent()
if inventoryText?
sampleInventory = new SimpleInventory
sampleInventory.parse inventoryText
@model.craftsman.want.addInventory sampleInventory
@_scrollTo @$workingSection
return false
onWantInventoryChanged: ->
text = @model.craftsman.want.unparse()
url = c.url.crafting inventoryText:text
@router.navigate url
if @model.craftsman.want.isEmpty
@model.craftsman.have.clear()
# PageController Overrides #####################################################################
getMetaDescription: ->
return c.text.craftDescription()
getTitle: ->
return 'Craft'
description = @model.craftsman.want.toDescription()
return null unless description?
return "Crafting Plan for #{description}"
# BaseController Overrides #####################################################################
onDidRender: ->
@_adsenseController = @addChild AdsenseController, '.view__adsense', model:'skyscraper'
@_wantInventoryController = @addChild InventoryController, '.want .view__inventory',
firstButtonType: 'remove'
imageLoader: @_imageLoader
@@ -89,7 +102,6 @@ module.exports = class CraftPageController extends PageController
router: @_router
@_haveInventoryController.on c.event.button.first, (controller, itemSlug)=>
@onRemoveFromHaveInventory itemSlug
@_haveInventoryController.on c.event.change, (c)=> @onHaveInventoryChanged()
@_needInventoryController = @addChild InventoryController, '.need .view__inventory',
editable: false
@@ -102,6 +114,7 @@ module.exports = class CraftPageController extends PageController
@_workingSectionController = @addChild CraftsmanWorkingController, '.view__craftsman_working',
model: @model.craftsman
@_workingSectionController.on c.event.click, => @_scrollTo @$workingSection
@$haveSection = @$('section.have')
@$instructionsSection = @$('section.instructions')
@@ -112,25 +125,37 @@ module.exports = class CraftPageController extends PageController
@$toolsSection = @$('section.tools')
@$workingSection = @$('.view__craftsman_working')
if c.screen.type.compute() is c.screen.type.mobile
@$('.view__inventory.large').removeClass 'large'
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
super
refresh: ->
@_needInventoryController.model = @model.craftsman.plan?.need
@_refreshOutdated()
@_refreshSectionVisibility()
@_refreshSteps()
@_adsenseController.fillAdPositions()
super
# Backbone.View Overrides ########################################################################
events: ->
return _.extend super,
'click .instructions a': 'routeLinkClick'
'click .instructions a': 'onSampleClicked'
# Private Methods ################################################################################
@@ -138,7 +163,7 @@ module.exports = class CraftPageController extends PageController
controller.model.addToolsTo @model.craftsman.want
_completeStep: (controller)->
controller.model.completeInto @model.craftsman.have
controller.markComplete @model.craftsman.have
_isAddingToolsPossible: (controller)->
tools = controller.model.recipe.tools
@@ -160,6 +185,12 @@ module.exports = class CraftPageController extends PageController
return true
_refreshOutdated: ->
if @model.craftsman.stage is Craftsman::STAGE.OUTDATED
@$el.addClass 'outdated'
else
@$el.removeClass 'outdated'
_refreshSectionVisibility: ->
return unless @_rendered
@@ -172,11 +203,13 @@ module.exports = class CraftPageController extends PageController
if @model.craftsman.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, @$workingSection]
visibleSections.push el for el in [@$wantSection, @$haveSection, @$workingSection]
else if not @model.craftsman.complete
visibleSections.push el for el in [@$wantSection, @$workingSection]
visibleSections.push el for el in [@$wantSection, @$haveSection, @$workingSection]
else
visibleSections.push el for el in [@$haveSection, @$needSection, @$stepsSection, @$wantSection]
visibleSections.push el for el in [@$haveSection, @$wantSection, @$workingSection]
if @model.craftsman.plan?
visibleSections.push el for el in [@$needSection, @$stepsSection]
@hide $el for $el in allSections
@show $el for $el in visibleSections
@@ -209,3 +242,28 @@ module.exports = class CraftPageController extends PageController
while @_stepControllers.length > index
@_stepControllers.pop().remove()
_scrollTo: ($targetEl)->
@_$scrollTarget = $targetEl
if @_scrollTimer?
clearTimeout @_scrollTimer
@_scrollTimer = setTimeout(=>
$el = @_$scrollTarget
@_scrollTimer = null
minScrollPosition = $el.offset().top + $el.height() - $(window).height() - @SCROLL_BUFFER
maxScrollPosition = $el.offset().top + @SCROLL_BUFFER
scrollPosition = $(window).scrollTop()
scrollTarget = scrollPosition
if scrollPosition > maxScrollPosition
scrollTarget = maxScrollPosition
else if scrollPosition < minScrollPosition
scrollTarget = minScrollPosition
else
return
$('html, body').animate {scrollTop:scrollTarget}, c.duration.normal
, c.duration.slow)
@@ -5,11 +5,16 @@
//- All rights reserved.
//-
.view__item_group.section
.content
.view__craftsman_working
.panel
.waiting
img(src='/images/wait.gif')
.message
p
.count
p
.button: .bezel: p Calculate
.outdated
.message Your crafting plan is out of date!
.button: .bezel: p Recalculate
@@ -6,32 +6,78 @@ All rights reserved.
*/
.view__craftsman_working {
.content {
background: $color-white;
box-shadow: none;
.panel {
align-items : center;
display : flex;
flex-direction : column;
padding : $size-margin-xlarge;
.waiting {
margin-bottom: $size-margin-xlarge;
margin-bottom : $size-margin-xlarge;
}
.message {
margin-bottom: $size-margin-medium;
margin-bottom : $size-margin-medium;
p {
font-family: $font-family-header;
font-size: $font-size-large;
font-family : $font-family-header;
font-size : $font-size-large;
text-align : center;
}
}
.count {
p {
font-family: $font-family-header;
font-size: $font-size-medium;
font-family : $font-family-header;
font-size : $font-size-medium;
text-align : center;
}
}
.button {
margin-top : $size-margin-large;
min-width: $size-minecraft-block * 6;
}
}
.outdated {
position: fixed; top: 0; left: 0; right: 0;
background : fade-out($color-white, 0.15) url('/images/panel-background-outdated.png');
border-bottom : $size-border-medium solid $color-black;
display : flex;
flex-direction : column;
align-items : center;
.message {
margin-top : $size-margin-medium;
font-family : $font-family-header;
font-size : $font-size-xlarge;
text-align : center;
}
.button {
width : $size-minecraft-block * 6;
margin : $size-margin-medium;
}
}
}
@include screen-size(not-mobile) {
.view__craftsman_working {
.panel {
.button {
margin-top : $size-margin-large;
height : $size-minecraft-block * 2;
width : $size-minecraft-block * 10;
p {
font-size : $font-size-xxlarge;
transform : translateY(-25%);
}
}
}
}
@@ -12,48 +12,94 @@ Craftsman = require '../../../models/crafting/craftsman'
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
@model.on c.event.change, => @_refreshStatusText()
@_hideTimer = null
# Event Methods ################################################################################
onButtonClicked: ->
@trigger c.event.click
@model.reset()
@model.work()
return false
# BaseController Methods #######################################################################
onDidModelChange: ->
@refresh()
onDidRender: ->
@$message = @$('.message p')
@$count = @$('.count p')
@$waiting = @$('.waiting')
@$button = @$('.button')
@$count = @$('.count p')
@$message = @$('.message p')
@$outdated = @$('.outdated')
@$waiting = @$('.waiting')
@_controls = [@$button, @$count, @$message, @$outdated, @$waiting]
super
refresh: ->
@_refreshStatusText()
super
# Private Methods ##############################################################################
_refreshStatusText: ->
return unless @$message? and @$count?
@show @$waiting
button = count = message = outdated = waiting = null
switch @model.stage
when Craftsman::STAGE.WAITING
@$message.html 'Preparing crafting calculation...'
@$count.html ''
when Craftsman::STAGE.READY
message = 'Ready to compute crafting plan!'
count = 'Click "Calculate" to continue.'
button = true
when Craftsman::STAGE.GRAPHING
@$message.html 'Researching recipes...'
@$count.html "Found #{@model.stageCount} recipes so far..."
message = 'Researching recipes...'
count = "Found #{@model.stageCount} recipes so far..."
watiing = true
when Craftsman::STAGE.PLANNING
@$message.html 'Figuring out possible crafting plans...'
@$count.html "Found #{@model.stageCount} possibilities so far..."
message = 'Figuring out possible crafting plans...'
count = "Found #{@model.stageCount} possibilities so far..."
watiing = true
when Craftsman::STAGE.ANALYZING
@$message.html 'Looking for the best plan...'
@$count.html "Finished checking #{@model.stageCount} so far..."
message = 'Looking for the best plan...'
count = "Finished checking #{@model.stageCount} so far..."
watiing = true
when Craftsman::STAGE.COMPLETE
@$message.html 'All done!'
@$count.html ''
message = 'Crafting plan is complete.'
when Craftsman::STAGE.INVALID
@$message.html 'Couldn\'t make a crafting plan'
@$count.html ''
@hide @waiting
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'
+2 -2
View File
@@ -11,5 +11,5 @@
.view__inventory
.view__recipe
.buttons
.button.complete: .bezel: p complete step
.button.tool: .bezel: p make this tool
a.button.tool: .bezel: p <span class="full">show plan for </span>tools
.button.complete: .bezel: p complete<span class="full"> step</span>
+50
View File
@@ -31,6 +31,10 @@
.view__inventory {
flex: 50%;
margin-left: $size-margin-large;
.buttons {
display: none;
}
}
.view__recipe {
@@ -52,5 +56,51 @@
margin-left: $size-margin-medium;
}
}
a {
border: 0;
.bezel {
border-top : 3px solid $color-button-highlight;
border-left : 3px solid $color-button-highlight;
border-bottom : 6px solid $color-button-shadow;
border-right : 3px solid $color-button-shadow;
}
}
}
&.complete {
opacity: 0.25;
h3 {
text-decoration: line-through;
}
}
}
@include screen-size(mobile) {
.view__step {
.main_content {
flex-direction: column-reverse;
.view__inventory {
flex: 0 0 auto;
margin: $size-margin-large $size-margin-large 0 $size-margin-large;
}
.view__recipe {
flex: 0 0 auto;
}
}
.buttons {
opacity: 1.0;
.button {
.full {
display: none;
}
}
}
}
}
@@ -8,6 +8,7 @@
BaseController = require '../../base_controller'
InventoryController = require '../../common/inventory/inventory_controller'
RecipeController = require '../../common/recipe/recipe_controller'
SimpleInventory = require '../../../models/crafting/simple_inventory'
########################################################################################################################
@@ -29,16 +30,19 @@ module.exports = class StepController extends BaseController
@onComplete = options.onComplete or (controller)-> # do nothing
@onAddTools = options.onAddTools or (controller)-> # do nothing
# Public Methods ###############################################################################
markComplete: (targetInventory)->
@$el.addClass 'complete'
@$completeButton.addClass 'disabled'
@model.completeInto targetInventory
# Event Methods ################################################################################
onCompleteButtonClicked: (event)->
return if @$completeButton.hasClass 'disabled'
@onComplete this
onToolButtonClicked: (event)->
return if @$toolButton.hasClass 'disabled'
@onAddTools this
# BaseController Overrides #####################################################################
onDidRender: ->
@@ -63,6 +67,9 @@ module.exports = class StepController extends BaseController
onWillChangeModel: (oldModel, newModel)->
if not newModel? then throw new Error 'model cannot be null'
if @rendered
@$el.removeClass 'complete'
@$completeButton.removeClass 'disabled'
return super
refresh: ->
@@ -83,11 +90,19 @@ module.exports = class StepController extends BaseController
events: ->
return _.extend super,
'click .button.complete': 'onCompleteButtonClicked'
'click .button.tool': 'onToolButtonClicked'
# Private Methods ##############################################################################
_refreshToolButton: ->
inventory = new SimpleInventory {}, modPack:@_modPack
for toolStack in @model.recipe.tools
inventory.add toolStack.itemSlug, toolStack.quantity
inventory.localize()
inventoryText = inventory.unparse()
@$toolButton.attr 'href', "/craft/#{inventoryText}"
@$toolButton.attr 'target', inventoryText
if @canAddTools this
@$toolButton.removeClass 'disabled'
else
+7 -5
View File
@@ -15,6 +15,10 @@
display: flex;
@include screen-size(mobile) {
display: none;
}
.form-content {
flex: 1 1 100%;
@@ -73,13 +77,11 @@
background: $color-gray-light;
border: $size-border-medium solid $color-black;
border-left: 0;
display: flex;
align-items: center;
justify-content: center;
position: relative;
p {
transform: rotate(-90deg);
position: absolute; top: 50%; left: 50%;
transform: translateX(-50%) rotate(-90deg) translateX(10%);
font-family: $font-family-header;
font-size: $label-size;
+19
View File
@@ -19,12 +19,20 @@
> .content {
display: flex;
@include screen-size(mobile) {
flex-direction: column;
}
color: $color-text-light;
.left, .center, .right {
flex: 1 1 33%;
margin: $size-margin-large $size-margin-large $size-margin-large 0;
@include screen-size(mobile) {
margin-left: $size-margin-large;
}
display: flex;
flex-direction: column;
@@ -38,6 +46,7 @@
.action {
flex: 1 1 auto;
align-self: center;
margin-top: $size-margin-large;
margin-bottom: $size-margin-large;
display: flex;
@@ -55,3 +64,13 @@
height: $size-minecraft-block;
}
}
@include screen-size(mobile) {
.view__footer {
> .content {
.left, .center, .right {
flex: 0 0 auto;
}
}
}
}
+3 -1
View File
@@ -21,4 +21,6 @@
.button.search: .bezel: p Search
.button.login: .bezel: p Login
.breadcrumbs
.breadcrumb-bar
.breadcrumbs
.extra-nav
+86 -21
View File
@@ -23,24 +23,22 @@
img {
position : relative;
top : -$size-minecraft-block * 0.5;
left : -$size-minecraft-block * 0.5;
height : $size-minecraft-block * 2.0;
width : $size-minecraft-block * 2.0;
height : $size-minecraft-block * 1.5;
width : $size-minecraft-block * 1.5;
}
}
h1 {
flex: 1 1 auto;
white-space: nowrap;
}
.addthis_sharing_toolbox {
flex : 0 0 auto;
min-height : 37px;
min-height : 37px; // actual size of addthis component
min-width : 144px;
margin-right : $size-margin-small;
&.placeholder {
border : 1px solid orange;
text-align : center;
@@ -62,36 +60,103 @@
align-items : center;
display : flex;
flex-wrap : wrap;
justify-content : space-around;
justify-content : center;
padding : $size-margin-medium $size-margin-medium;
padding-top : 0;
.button {
flex : 1 1 20%;
min-width : 4 * $size-minecraft-block;
max-width : 5 * $size-minecraft-block;
margin-top: $size-margin-medium;
flex-grow : 1;
flex-shrink : 1;
min-width : 3 * $size-minecraft-block;
max-width : 5 * $size-minecraft-block;
margin-top : $size-margin-medium;
margin-right : $size-margin-small;
&:last-child {
margin-right: 0;
}
}
}
.breadcrumbs {
.breadcrumb-bar {
background: $color-screen;
padding: 0 ($size-margin-medium + $size-margin-large);
font-family: $font-family-control;
font-size: $font-size-medium;
line-height: $font-size-medium + 2 * $size-margin-small;
padding: $size-margin-small $size-margin-medium;
display: flex;
&:before {
content: "";
margin-right: $size-margin-medium;
.breadcrumbs {
flex: 1 1 75%;
text-indent: -$size-margin-large;
&:before {
content: "";
margin-right: $size-margin-medium;
}
a {
text-decoration: underline;
}
span {
margin: 0 $size-margin-medium;
}
}
a {
text-decoration: underline;
}
.extra-nav {
flex: 1 1 25%;
align-self: flex-end;
span {
margin: 0 $size-margin-medium;
text-align: right;
}
}
}
@include screen-size(desktop) {
.view__header {
.top-row {
a {
img {
top : -$size-minecraft-block * 0.5;
left : -$size-minecraft-block * 0.5;
height : $size-minecraft-block * 2.0;
width : $size-minecraft-block * 2.0;
}
}
}
}
}
@include screen-size(tablet) {
.view__header {
.top-row {
h1 {
font-size : $font-size-xlarge;
}
}
}
}
@include screen-size(mobile) {
.view__header {
.top-row {
display : none;
}
.divider {
.button.login {
display: none;
}
}
.breadcrumb-bar {
.extra-nav {
display: none;
}
}
}
}
@@ -7,6 +7,7 @@
BaseController = require '../base_controller'
ItemSelectorController = require '../common/item_selector/item_selector_controller'
UrlParams = require '../url_params'
########################################################################################################################
@@ -43,9 +44,11 @@ module.exports = class HeaderController extends BaseController
@router.navigate '/news', trigger:true
return false
onSearch: ->
@_selector.launch()
onSearch: (event, hint='')->
@_selector.launch hint
.then (itemSlug)=>
return unless itemSlug?
itemDisplay = @_modPack.findItemDisplay itemSlug
@router.navigate itemDisplay.itemUrl, trigger:true
return false
@@ -62,8 +65,11 @@ module.exports = class HeaderController extends BaseController
@$('.addthis_sharing_toolbox').addClass 'placeholder'
@$breadcrumbs = @$('.breadcrumbs')
@$extraNav = @$('.extra-nav')
@$loginButtonLabel = @$('.button.login p')
@$title = $('title')
@_checkForSearchRequest()
super
onWillChangeModel: (oldModel, newModel)->
@@ -75,6 +81,8 @@ module.exports = class HeaderController extends BaseController
@$loginButtonLabel.text if global.site.user? then "Logout" else "Login"
@_refreshBreadcrumbs()
@_refreshExtraNav()
@_refreshSelectedNavButton()
@_refreshTitle()
super
@@ -82,15 +90,21 @@ module.exports = class HeaderController extends BaseController
events: ->
_.extend super,
'click .craft': 'onCraft'
'click .browse': 'onBrowse'
'click .login': 'onLogin'
'click .news': 'onNews'
'click .search': 'onSearch'
'click .breadcrumbs a': 'routeLinkClick'
'click .craft': 'onCraft'
'click .browse': 'onBrowse'
'click .login': 'onLogin'
'click .news': 'onNews'
'click .search': 'onSearch'
'click .breadcrumb-bar a': 'routeLinkClick'
# Private Methods ##############################################################################
_checkForSearchRequest: ->
params = new UrlParams search:{type:'string'}
return unless params.search?
_.delay (=> @onSearch {}, params.search), c.duration.slow
_refreshBreadcrumbs: ->
breadcrumbs = @model?.controller?.getBreadcrumbs()
breadcrumbs ?= []
@@ -106,6 +120,23 @@ module.exports = class HeaderController extends BaseController
else
@hide @$breadcrumbs
_refreshExtraNav: ->
extraNavContent = @model?.controller?.getExtraNav()
if extraNavContent?
@$extraNav.empty()
@$extraNav.append extraNavContent
@show @$extraNav
else
@hide @$extraNav
_refreshSelectedNavButton: ->
return unless @model?.page?
@$('.button').removeClass 'active'
@$(".button.#{@model.page}").addClass 'active'
_refreshTitle: ->
title = @model?.controller?.getTitle()
if title
+4 -2
View File
@@ -12,7 +12,7 @@ html
link(href="/images/favicon.png" rel="icon" type="image/png")
link(href="/main.css" rel="stylesheet" type="text/css" )
meta(charset="UTF-8")
meta(name="viewport" content="width=480")
meta(name="viewport" content="user-scalable=no, width=device-width")
body
.view__feedback
@@ -21,7 +21,7 @@ html
.page
.view__header
.content(style="display: none")
.content.hidden
.content-loading
img(src="/images/wait.gif")
@@ -32,4 +32,6 @@ html
include ../includes/_google_adsense.jade
include ../includes/_google_analytics.jade
include ../includes/_google_sitelinks.jade
include ../includes/_twitter_follow.jade
+6 -3
View File
@@ -36,19 +36,22 @@ html {
}
& > *:first-child {
flex: 0 0 50%;
flex: 1 1 100%;
box-shadow : $size-margin-small $size-margin-small $size-margin-large $color-shadow;
}
}
.page {
margin : $size-margin-large 0;
max-width : $size-page-width;
width : 100%;
@include screen-size(desktop) {
margin : $size-margin-large 0;
box-shadow : $size-margin-small $size-margin-small $size-margin-large $color-shadow;
}
background : $color-background-page;
box-shadow : $size-margin-small $size-margin-small $size-margin-large $color-shadow;
display : flex;
flex-direction : column;
+1 -2
View File
@@ -7,7 +7,6 @@
.content.view__item_page
.left
.view__adsense
.right
.about
@@ -17,7 +16,7 @@
.title
a.sourceMod
.button-row
.button.craftingPlan: .bezel: p View Crafting Plan
.button.craftingPlan: .bezel: p View <span class="full">Crafting </span>Plan
.right
p Official Link:
a.officialLink project page
+48 -1
View File
@@ -48,7 +48,7 @@
.button {
flex: 1 1 100%;
max-width: 66%;
max-width: $size-minecraft-block * 10;
}
}
}
@@ -58,3 +58,50 @@
}
}
}
@include screen-size(mobile) {
.view__item_page {
.about {
flex-direction: column;
& > .left {
margin: 0 $size-margin-medium;
display: flex;
flex-direction: column;
align-items: center;
img {
}
}
& > .center {
flex: 0 0 auto;
margin: 0 $size-margin-medium;
.sourceMod, .title {
text-align: center;
}
a.sourceMod {
}
.button-row {
flex: 0 0 auto;
margin: $size-margin-large 0;
.button {
max-width: $size-minecraft-block * 8;
.full {
display: none;
}
}
}
}
& > .right {
margin: 0 $size-margin-medium;
}
}
}
}
@@ -5,7 +5,6 @@
# All rights reserved.
#
AdsenseController = require '../common/adsense/adsense_controller'
EditableFile = require '../../models/site/editable_file'
Item = require '../../models/game/item'
ItemGroupController = require '../common/item_group/item_group_controller'
@@ -42,6 +41,7 @@ module.exports = class ItemPageController extends PageController
@_itemSlug = options.itemSlug
@_modPack = options.modPack
@_router = options.router
@_triggerEditing = options.login
@_modPack.on c.event.change, =>
@tryRefresh()
@@ -68,6 +68,13 @@ module.exports = class ItemPageController extends PageController
$("<b>#{display.itemName}</b>")
]
getExtraNav: ->
itemSlug = @_modPack.chooseRandomItem()
return null unless itemSlug?
itemDisplay = @_modPack.findItemDisplay itemSlug
return $("<a href='#{itemDisplay.itemUrl}'>Random Item</a>")
getMetaDescription: ->
return null unless @_itemSlug?
display = @_modPack.findItemDisplay @_itemSlug
@@ -83,9 +90,11 @@ module.exports = class ItemPageController extends PageController
# BaseController Overrides #####################################################################
onDidRender: ->
@_adsenseController = @addChild AdsenseController, '.view__adsense', model:'skyscraper', router: @_router
onDidModelChange: ->
@trigger c.event.change
super
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
@@ -101,11 +110,12 @@ module.exports = class ItemPageController extends PageController
endEditing: => @_endEditingDescription()
enterFeedback: @_enterFeedback
@$aboutImage = @$('.about img')
@$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')
@@ -135,6 +145,15 @@ module.exports = class ItemPageController extends PageController
else
@hide @$aboutLinks
if @model.item.isCraftable
@show @$craftingPlanButton
else
@hide @$craftingPlanButton
if @_triggerEditing
@_triggerEditing = false
@_descriptionController.onEditClicked {}
@show()
else
@hide()
@@ -317,7 +336,7 @@ module.exports = class ItemPageController extends PageController
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
@_router.navigate c.url.item(modSlug:item.slug.mod, itemSlug:item.slug.item), trigger:true
return
@model.item = item
@@ -75,3 +75,20 @@
}
}
}
@include screen-size(mobile) {
.view__multiblock_viewer {
flex-direction: column-reverse;
.left {
flex: 0 0 auto;
border: 0;
}
.right {
flex: 0 0 auto;
margin-bottom: $size-margin-large;
}
}
}
@@ -8,7 +8,7 @@
.view__recipe_detail {
display : flex;
.input, .output{
.input, .output {
flex : 0 1 33%;
h3 {
@@ -20,8 +20,13 @@
}
}
.input {
order: 10;
}
.pattern {
flex : 0 1 33%;
order: 20;
display : flex;
flex-direction : column;
@@ -36,9 +41,48 @@
}
}
.output {
order: 30;
}
&:not(:first-child) {
border-top : 1px solid $color-gray-light;
margin-top : $size-margin-medium;
padding-top : $size-margin-large;
}
}
@include screen-size(mobile) {
.view__recipe_detail {
flex-direction: column;
> :not(:last-child) {
margin-bottom: $size-margin-large;
}
.input, .output {
flex: 0 0 auto;
h3 {
}
.view__inventory {
}
}
.input {
order: 21;
}
.pattern {
flex: 0 0 auto;
.tool {
}
}
&:not(:first-child) {
}
}
}
@@ -0,0 +1,11 @@
//-
//- Crafting Guide - mod_editor_page.jade
//-
//- Copyright © 2014-2016 by Redwood Labs
//- All rights reserved.
//-
.content.view__mod_editor_page
.left
.right
@@ -0,0 +1,9 @@
//
// Crafting Guide - mod_editor_page.scss
//
// Copyright © 2014-2016 by Redwood Labs
// All rights reserved.
//
.view__mod_editor_page {
}
@@ -0,0 +1,46 @@
#
# Crafting Guide - mod_page_controller.coffee
#
# Copyright © 2014-2016 by Redwood Labs
# All rights reserved.
#
PageController = require '../page_controller'
########################################################################################################################
module.exports = class ModPageController extends PageController
constructor: (options={})->
if not options.imageLoader? then throw new Error 'options.imageLoader is required'
if not options.modPack? then throw new Error 'options.modPack is required'
options.templateName = 'mod_editor_page'
super options
@_imageLoader = options.imageLoader
@_modPack = options.modPack
# Event Methods ################################################################################
# Property Methods #############################################################################
# PageController Overrides #####################################################################
getBreadcrumbs: ->
getTitle: ->
# BaseController Overrides #####################################################################
onDidRender: ->
super
refresh: ->
super
# Backbone.View Overrides ######################################################################
events: ->
return _.extend super,
# Private Methods ##############################################################################
+5 -3
View File
@@ -1,5 +1,5 @@
//-
//- Crafting Guide - item_page.jade
//- Crafting Guide - mod_page.jade
//-
//- Copyright © 2014-2016 by Redwood Labs
//- All rights reserved.
@@ -7,7 +7,6 @@
.content.view__mod_page
.left
.view__adsense
.right
.about
@@ -17,8 +16,11 @@
.title
.author
.description
.modpack
span.checkbox
span.label I have this mod in my modpack
.version
span in my mod pack
span I'm using version:
select
.warning.
<b>PLEASE NOTE:</b> By selecting "no", crafting plans, search, and other features will ignore items
+77 -2
View File
@@ -1,5 +1,5 @@
//
// Crafting Guide - item_page.scss
// Crafting Guide - mod_page.scss
//
// Copyright © 2014-2016 by Redwood Labs
// All rights reserved.
@@ -49,8 +49,44 @@
line-height: $font-size-medium * 1.25;
}
.modpack {
margin-top : $size-margin-large;
cursor : pointer;
font-family : $font-family-control;
font-size : $font-size-medium;
display : flex;
.checkbox {
display : inline-block;
height : $font-size-medium;
margin-right : $size-margin-small;
position : relative;
width : $font-size-medium;
background : $color-white;
border : $size-border-small solid $color-black;
}
.label {
color: $color-gray-medium;
}
&.enabled {
.checkbox:before {
position: absolute; top: 0; left: 1.5px; // adjust for glyph position
content: "";
}
.label {
color: $color-black;
}
}
}
.version {
margin-top: $size-margin-large;
margin-top: $size-margin-medium;
font-family: $font-family-control;
font-size: $font-size-medium;
@@ -92,3 +128,42 @@
}
}
}
@include screen-size(mobile) {
.view__mod_page {
.about {
flex-direction: column;
& > * {
margin-left: $size-margin-medium;
margin-right: $size-margin-medium;
}
.left {
margin-bottom: $size-margin-large;
margin-left: $size-margin-medium;
margin-right: $size-margin-medium;
display : flex;
flex-direction : column;
align-items : center;
}
.center {
flex: 0 0 auto;
margin-bottom: $size-margin-xlarge;
margin-left: $size-margin-medium;
margin-right: $size-margin-medium;
.author, .title {
text-align: center;
}
}
.right {
margin-left: $size-margin-medium;
margin-right: $size-margin-medium;
}
}
}
}
@@ -5,7 +5,6 @@
# All rights reserved.
#
AdsenseController = require '../common/adsense/adsense_controller'
BaseController = require '../base_controller'
Item = require '../../models/game/item'
ItemGroupController = require '../common/item_group/item_group_controller'
@@ -29,6 +28,14 @@ module.exports = class ModPageController extends BaseController
# Event Methods ################################################################################
onToggleEnabled: ->
if @model.activeVersion is Mod.Version.None
@model.activeVersion = Mod.Version.Latest
else
@model.activeVersion = Mod.Version.None
return false
onVersionChanged: ->
@model.activeVersion = @$versionSelector.val()
return false
@@ -58,8 +65,6 @@ module.exports = class ModPageController extends BaseController
# BaseController Overrides #####################################################################
onDidRender: ->
@_adsenseController = @addChild AdsenseController, '.view__adsense', model: 'skyscraper'
@$author = @$('.about .author')
@$description = @$('.about .description')
@$documentationLink = @$('.about .documentation')
@@ -67,15 +72,18 @@ module.exports = class ModPageController extends BaseController
@$homePageLink = @$('.about .homePage')
@$itemGroups = @$(".itemGroups")
@$logo = @$('.about img')
@$modpackSection = @$('.modpack')
@$title = @$('.about .title')
@$tutorialsContainer = @$('section.tutorials .panel')
@$tutorialsSection = @$('section.tutorials')
@$versionSection = @$('.version')
@$versionSelector = @$('.version select')
@$warning = @$('.warning')
super
refresh: ->
@_refreshAboutBlock()
@_refreshEnabled()
@_refreshItemGroups()
@_refreshTutorials()
@_refreshVersionSelector()
@@ -86,6 +94,7 @@ module.exports = class ModPageController extends BaseController
events: ->
return _.extend super,
'change .version select': 'onVersionChanged'
'click .modpack': 'onToggleEnabled'
# Private Methods ##############################################################################
@@ -107,6 +116,19 @@ module.exports = class ModPageController extends BaseController
@$logo.attr 'src', ''
@$title.text ''
_refreshEnabled: ->
if @model.slug in c.requiredMods
@hide @$modpackSection
else
@show @$modpackSection
if @model.activeVersion is Mod.Version.None
@$modpackSection.removeClass 'enabled'
@show @$warning
else
@$modpackSection.addClass 'enabled'
@hide @$warning
_refreshItemGroups: ->
@_groupControllers ?= []
groupIndex = 0
@@ -124,9 +146,10 @@ module.exports = class ModPageController extends BaseController
router: @_router
title: if group is Item.Group.Other then 'Items' else group
@_groupControllers.push controller
@$itemGroups.append controller.$el
controller.render()
_.defer =>
@_groupControllers.push controller
@$itemGroups.append controller.$el
controller.render()
else
controller.modVersion = modVersion
controller.model = items
@@ -163,19 +186,16 @@ module.exports = class ModPageController extends BaseController
_refreshVersionSelector: ->
modVersions = @model.modVersions
if (@model.activeVersion is Mod.Version.None) or modVersions.length < 2
@hide @$versionSection
else
@show @$versionSection
selectedModVersion = @effectiveModVersion
@$versionSelector.empty()
$option = $("<option value=\"none\">no</option>")
if not @model.enabled
@$warning.css display:''
selectedModVersion = null
$option.attr 'selected', true
else
@$warning.css display:'none'
@$versionSelector.append $option
for modVersion in @model.modVersions
$option = $("<option value=\"#{modVersion.version}\">#{modVersion.version}</option>")
if modVersion is selectedModVersion
+78 -52
View File
@@ -7,9 +7,86 @@
.content.view__news_page
.left
.view__adsense
.right
include ../common/twitter/twitter.jade
section
h3 2016-04-30
.panel
p.
Big news... no, huge news... no, tiny news! Crafting Guide is now fully functional on any size
screen from a 30" desktop monitor all the way down to a 4" phone. Just grab your favorite mobile
device and give it a try!
section
h3 2016-04-24
.panel
p.
I've been knocking off a few more feature requests over the weekend. First, I've made the entire
site respond to being on a smaller screen (tablet-sized for now, phone-sized will be next).
Hopefully, it should just feel pretty natural on whatever screen size, and you won't notice any big
differences from one to the other.
p.
The second small change is that whenever you're looking at a recipe which calls for a <i>lot</i> of
some item, you can hover over the quantity to see what it would be in stacks + the remainder. For
example, 127 translates to: 1x64+63. That should make it easier to think about large builds.
section
h3 2016-04-23
.panel
p.
I've spent some time working on the crafting page today, and I think you'll find it a lot easier to
adjust your plans now. The big difference is that the site no longer automatically calculate.
Instead, you have to deliberately press a button when you're ready for a new plan. This allows you
to check out an existing plan, mark certain steps complete, adjust your inventory, and only when
you're ready, click the button for a new plan. Not a huge change, but I think you'll find yourself
adjusting a not-quite-right plan a lot more often now!
section
h3 2016-04-21
.panel
p.
The most highly-requested mod currently on my list is <a href="/browse/tinkers_construct">Tinker's
Construct</a>, and I'm pleased to announce that it is now available on Crafting Guide! In case you
aren't familiar with it, it adds the ability to create tools by crafting together individual parts
made from different materials, and adds a complex smelting mechanic which allows you to create a
variety of useful metal alloys. This smelting has the side-effect of producing two ingots for every
block of ore as well, so you can very rapidly get to ore-doubling without having to have already got
a complex power system up and running.
p.
There is <i>one</i> thing missing. I didn't include any recipes for the actual tools themselves.
The problem, of course, is that you can mix and match parts made from any of the supported
materials, and that leads to thousands upon thousands of possible tools: way more than would ever be
practical to include in Crafting Guide in the obvious way other items are included.
p.
The plan, then, is to create a feature just for Tinker's Construct which allows you to select a tool
to create, and then pick and choose the material types for each part. You'll then be able to make a
crafting plan for those parts. If that sounds like something you'd use, head over to <a
href="https://github.com/andrewminer/crafting-guide/issues/214">GitHub</a> and add your vote!
section
h3 2016-04-16
.panel
p.
I've been working on adding a new mod, and I ran across a bug which has been in the system for a
while now, but which will cause serious problems with a lot of the recipes in the new mod. So, I put
the mod aside for a bit to fix it.
p.
The bug was that when you are making something like an <a
href="/browse/forge_multipart/oak_wood_cover">Oak Wood Cover</a> the <a
href="/browse/forge_multipart/stone_saw">saw</a> wouldn't be part of the crafting plan. This isn't
such a big deal for most things, but for this new mod, it would have been a major problem.
section
h3 2016-04-14
.panel
p.
In between adding new features to the website, I've taken a little break to add support for
<a href="/browse/projectred">ProjectRed</a>. It takes up the mantle of the retired RedPower mod
and adds a lot of what that one used to provide: logic gates, cables, pneumatic tubes, and lots and
lots of new lights and lamps.
section
h3 2016-04-05
.panel
@@ -79,54 +156,3 @@
p.
With many thanks to <a href="https://github.com/pkmnfrk">Mike Caron</a>, I'm pleased to announce
support for <a href="/browse/storage_drawers">Storage Drawers</a>!
section
h3 2015-12-13
.panel
p.
I'm super excited to announce that I've added full multi-block support for Crafting Guide! For
example, check out a <a href="/browse/big_reactors/5_core_passive_reactor">5-Core Reactor</a>
from Big Reactors, or the <a href="/browse/railcraft/steel_tank_5x5x5">5x5x5 Steel Tank</a> from
Railcraft. I'm really pleased with how it turned out!
section
h3 2015-11-17
.panel
p.
And today, it's <a href="/browse/extra_cells">Extra Cells</a>!
section
h3 2015-11-16
.panel
p.
It's a small one, but also highly requested... Here's <a
href="/browse/computercraft">ComputerCraft</a>!
section
h3 2015-11-14
.panel
p.
One more small one over the weekend... <a href="/browse/advanced_solar_panels">Advanced Solar
Panels</a> has been added to crafting guide!
section
h3 2015-11-14
.panel
p.
For a long while now, <a href="/browse/galacticraft">Galacticraft</a> has been the most
requested mod, and it's finally here! Enjoy!
section
h3 2015-11-10
.panel
p.
Remember me? They guy who runs the site. Yeah, I'm back, and with big news! The site now has
a completely new crafting algorithm. Instead of just taking the first crafting plan it comes up
with, it tries to compute every possible plan, rates them, and then picks the best one. This
also clears up a lot of bugs related to the old algorithm. The one drawback is that some items
can take a bit longer to compute than with the old way, but I think you'll find it's worth it!
p.
On a personal note, I think it's clear that I don't have nearly as much time to dedicate to the
site as I used to. That's mostly because I started a new job which keeps me away from working
on the site so much. I hope to be able to get into a more regular pace now things my personal
life has settled down again.
+22 -12
View File
@@ -8,22 +8,32 @@
.view__news_page {
@include layout-body-with-sidebar;
section {
&:not(:first-child) {
margin-top : $size-margin-large;
& > .right {
display: flex;
flex-direction: column;
align-items: stretch;
.view__twitter {
align-self: center;
}
h3 {
margin-bottom : $size-margin-small;
}
section {
&:not(:first-child) {
margin-top : $size-margin-large;
}
p {
font-family : $font-family-text;
font-size : $font-size-medium;
line-height : $font-size-medium * 1.5;
h3 {
margin-bottom : $size-margin-small;
}
&:not(:last-child) {
margin-bottom : $size-margin-medium;
p {
font-family : $font-family-text;
font-size : $font-size-medium;
line-height : $font-size-medium * 1.5;
&:not(:last-child) {
margin-bottom : $size-margin-medium;
}
}
}
}
@@ -5,8 +5,7 @@
# All rights reserved.
#
AdsenseController = require '../common/adsense/adsense_controller'
PageController = require '../page_controller'
PageController = require '../page_controller'
########################################################################################################################
@@ -24,11 +23,6 @@ module.exports = class NewsPageController extends PageController
getTitle: ->
return "News"
# BaseController Overrides #####################################################################
onDidRender: ->
@_adsenseController = @addChild AdsenseController, '.view__adsense', model:'skyscraper'
# Backbone.View Overrides ######################################################################
events: ->
+4
View File
@@ -19,6 +19,10 @@ module.exports = class PageController extends BaseController
getBreadcrumbs: ->
return []
getExtraNav: ->
# subclasses may override this to provide extra content in the right-hand side of the breadcrumb bar
return null
getMetaDescription: ->
# subclasses should override this to return the page-specific text for the meta description tag
return null
+15 -2
View File
@@ -11,6 +11,7 @@ ItemPageController = require './item_page/item_page_controller'
ItemSlug = require '../models/game/item_slug'
LoginPageController = require './login_page/login_page_controller'
ModPageController = require './mod_page/mod_page_controller'
ModEditorPageController = require './mod_editor_page/mod_editor_page_controller'
NewsPageController = require './news_page/news_page_controller'
TutorialPageController = require './tutorial_page/tutorial_page_controller'
UrlParams = require './url_params'
@@ -66,6 +67,10 @@ module.exports = class Router extends Backbone.Router
'craft/:text/': 'route__craft'
'craft/:text/index.html': 'route__craft'
'edit/:modSlug': 'route__editMod'
'edit/:modSlug/': 'route__editMod'
'edit/:modSlug/index.html': 'route__editMod'
'login': 'route__login'
'login/': 'route__login'
'login/index.html': 'route__login'
@@ -98,17 +103,25 @@ module.exports = class Router extends Backbone.Router
@_siteController.setPage 'browseMod', controller
route__browseModItem: (modSlug, itemSlug)->
params = new UrlParams login:{type:'boolean', default:false}
slug = new ItemSlug modSlug, itemSlug
controller = new ItemPageController @_makeOptions {itemSlug:slug}
controller = new ItemPageController @_makeOptions {itemSlug:slug, login:params.login}
@_siteController.setPage 'browseModItem', controller
route__browseTutorial: (modSlug, tutorialSlug)->
controller = new TutorialPageController @_makeOptions {modSlug:modSlug, tutorialSlug:tutorialSlug}
params = new UrlParams login:{type:'boolean', default:false}
controller = new TutorialPageController @_makeOptions
login:params.login, modSlug:modSlug, tutorialSlug:tutorialSlug
@_siteController.setPage 'browseTutorial', controller
route__configure: ->
@route__craft()
route__editMod: (modSlug)->
controller = new ModEditorPageController @_makeOptions()
controller.model = @_siteController.modPack.getMod modSlug
@_siteController.setPage 'editMod', controller
route__craft: (text)->
controller = new CraftPageController @_makeOptions {}
controller.model.params = inventoryText:text
+15 -6
View File
@@ -5,8 +5,10 @@
# All rights reserved.
#
AdsenseController = require './common/adsense/adsense_controller'
BaseController = require './base_controller'
FeedbackController = require './feedback/feedback_controller'
FileCache = require '../models/site/file_cache'
FooterController = require './footer/footer_controller'
GitHubUser = require '../models/site/github_user'
HeaderController = require './header/header_controller'
@@ -26,11 +28,13 @@ module.exports = class SiteController extends BaseController
super options
@client = options.client
@fileCache = new FileCache c.url.modpackArchive()
@imageLoader = new ImageLoader defaultUrl:'/images/unknown.png'
@modPack = new ModPack
@modPack = new ModPack {}, fileCache:@fileCache
@router = new Router this
@storage = options.storage
@_adsenseController = new AdsenseController
@_currentPage = null
@_currentPageController = null
@_user = null
@@ -42,7 +46,7 @@ module.exports = class SiteController extends BaseController
m.activeModVersion.fetch() if m.activeModVersion?
for modSlug, modData of c.defaultMods
mod = new Mod slug:modSlug
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()
@@ -51,8 +55,8 @@ module.exports = class SiteController extends BaseController
if global.env isnt 'prerender'
@modPack.once c.event.sync, =>
@$pageContent.css 'display', ''
@$pageContentLoading.css 'display', 'none'
@$pageContent.removeClass 'hidden'
@$pageContentLoading.addClass 'hidden'
loadCurrentUser: ->
@client.fetchCurrentUser()
@@ -80,7 +84,7 @@ module.exports = class SiteController extends BaseController
resumeAfterLogin: ->
url = @storage.load 'post-login-url'
url = if (not url? or url is 'null') then null else url
url = if (not url? or url is 'null') then null else url + '?login=true'
if url? then @router.navigate url, trigger:true
@storage.store 'post-login-url', null
@@ -142,16 +146,21 @@ module.exports = class SiteController extends BaseController
$pageContent = $('.page > .content')
$pageContent.removeClass()
$pageContent.addClass 'content'
$pageContent.css display:''
if not @$pageContentLoading.hasClass 'hidden'
$pageContent.addClass 'hidden'
window.scrollTo 0, 0
@_headerController.model = controller: controller
@_headerController.model = controller: controller, page: page
@_currentPageController.user = @user
@_currentPageController.onWillShow()
@_currentPageController.$el = $pageContent
@_currentPageController.render()
@_adsenseController.reset()
_resetGlobals: ->
if global.env in c.productionEnvs
for key, value of global
@@ -7,7 +7,6 @@
.view__tutorial_page
.left
.view__adsense
.right
.about
@@ -51,12 +51,28 @@
margin-top : -$size-margin-medium;
display : flex;
flex-wrap : wrap;
justify-content: space-between;
padding-right : -$size-margin-medium;
& > * {
flex : 1 1 100%;
margin-right : $size-margin-medium;
margin-top : $size-margin-medium;
max-width : calc(50% - 12px); // $size-margin-medium
width : calc(50% - 12px); // $size-margin-medium;
}
}
}
@include screen-size(mobile) {
.view__tutorial_page {
.video-container {
flex-direction: column;
flex-wrap: nowrap;
justify-content: stretch;
& > * {
width: inherit;
}
}
}
}
@@ -5,7 +5,6 @@
# All rights reserved.
#
AdsenseController = require '../common/adsense/adsense_controller'
PageController = require '../page_controller'
MarkdownSectionController = require '../common/markdown_section/markdown_section_controller'
VideoController = require '../common/video/video_controller'
@@ -60,8 +59,6 @@ module.exports = class TutorialPageController extends PageController
# BaseController Overrides #####################################################################
onDidRender: ->
@_adsenseController = @addChild AdsenseController, '.view__adsense', model:'skyscraper'
@$sourceModLink = @$('.sourceMod a')
@$officialLink = @$('.officialLink a')
@$officialLinkPanel = @$('.officialLink')
+5 -8
View File
@@ -47,7 +47,7 @@
background : url('/images/button-background-hover.png') repeat;
}
&:active {
&:active, &.active {
background : url('/images/button-background-active.png') repeat;
.bezel {
@@ -69,15 +69,12 @@
}
}
.page > .content {
min-height: $size-skyscraper-height;
.hidden {
display: none !important;
}
.skyscraper {
height : $size-skyscraper-height - 2px;
width : $size-skyscraper-width - 2px;
border : 1px solid $color-gray-medium;
.page > .content {
min-height: $size-ad-skyscraper-height;
}
.scrollDisabled {
+3
View File
@@ -8,6 +8,9 @@
// normalize all values
@import './reset';
// define media breakpoints
@import './media';
// define variables
@import './colors';
@import './fonts';
+22
View File
@@ -0,0 +1,22 @@
//
// Crafting Guide - fonts.scss
//
// Copyright © 2014-2016 by Redwood Labs
// All rights reserved.
//
$tablet : 960px;
$mobile : 568px;
@mixin screen-size($screenType) {
@if $screenType == desktop {
@media (min-width: $tablet + 1) { @content; }
} @else if $screenType == tablet {
@media (max-width: $tablet) { @content; }
} @else if $screenType == mobile {
@media (max-width: $mobile) { @content; }
} @else if $screenType == not-mobile {
@media (min-width: $mobile + 1) { @content }
}
}
+65 -47
View File
@@ -10,6 +10,11 @@
filter : blur($radius);
}
@mixin floating-panel {
background: $color-background-panel;
box-shadow: $size-margin-xxsmall $size-margin-xxsmall $size-margin-xsmall $color-shadow;
}
@mixin grayscale {
-webkit-filter : grayscale(100%);
-moz-filter : grayscale(100%);
@@ -18,6 +23,66 @@
filter : gray;
}
@mixin layout-body-with-sidebar {
display: flex;
& > .left {
flex : 0 0 $size-ad-skyscraper-width + $size-margin-medium;
min-height : $size-ad-skyscraper-height;
padding-right : $size-margin-medium;
@include screen-size(tablet) {
display : none;
}
@include screen-size(mobile) {
display : none;
}
}
& > .right {
flex : 1 1 100%;
@include screen-size(tablet) {
margin : 0 $size-margin-xlarge;
max-width: calc(100% - 2 * 48px); // 2 * $size-margin-xlarge
}
@include screen-size(mobile) {
margin : 0;
max-width: 100%;
}
section {
margin-bottom : $size-margin-large;
}
}
}
@mixin layout-link-list {
display : flex;
flex-direction : column;
justify-content : center;
p {
margin-bottom : $size-margin-small;
font-family : $font-family-text;
font-size : $font-size-large;
}
a {
margin-left : $size-margin-medium;
font-family : $font-family-text;
font-size : $font-size-medium;
text-decoration : underline;
&:not(:last-child) {
margin-bottom : $size-margin-medium;
}
}
}
@mixin no-select {
-webkit-touch-callout : none; /* iOS Safari */
-webkit-user-select : none; /* Chrome/Safari/Opera */
@@ -26,36 +91,6 @@
user-select : none; /* non-prefixed version, currently not supported by any browser */
}
@mixin floating-panel {
background: $color-background-panel;
box-shadow: $size-margin-xxsmall $size-margin-xxsmall $size-margin-xsmall $color-shadow;
}
@mixin layout-link-list {
display: flex;
flex-direction: column;
justify-content: center;
p {
margin-bottom: $size-margin-small;
font-family: $font-family-text;
font-size: $font-size-large;
}
a {
margin-left: $size-margin-medium;
font-family: $font-family-text;
font-size: $font-size-medium;
text-decoration: underline;
&:not(:last-child) {
margin-bottom: $size-margin-medium;
}
}
}
@mixin pixel-image {
image-rendering : -moz-crisp-edges; /* Firefox */
image-rendering : -o-crisp-edges; /* Opera */
@@ -63,20 +98,3 @@
image-rendering : crisp-edges;
-ms-interpolation-mode : nearest-neighbor; /* IE (non-standard property) */
}
@mixin layout-body-with-sidebar {
display: flex;
& > .left {
flex: 0 0 $size-skyscraper-width + $size-margin-medium;
padding-right: $size-margin-medium;
}
& > .right {
flex: 1 1 auto;
section {
margin-bottom: $size-margin-large;
}
}
}
+6 -2
View File
@@ -25,5 +25,9 @@ $size-minecraft-block : 32px;
$size-page-width : $size-rem * 80;
$size-skyscraper-height : 600px;
$size-skyscraper-width : 160px;
$size-ad-large-mobile-banner-height : 100px;
$size-ad-large-mobile-banner-width : 320px;
$size-ad-leaderboard-height : 90px;
$size-ad-leaderboard-width : 728px;
$size-ad-skyscraper-height : 600px;
$size-ad-skyscraper-width : 160px;
+42 -8
View File
@@ -7,24 +7,39 @@
########################################################################################################################
exports.adsense = adsense = {}
adsense.clientId = 'ca-pub-6593013914878730'
adsense.skyscraper = {}
adsense.skyscraper.height = 600
adsense.skyscraper.width = 160
adsense.skyscraper.margin = 24
adsense.slotIds = ['7613920409', '9574673605', '3388539204']
exports.adsense = adsense = {}
adsense.adTypeMap = desktop:'skyscraper', tablet:'leaderboard', mobile:'largeMobileBanner'
adsense.clientId = 'ca-pub-6593013914878730'
adsense.largeMobileBanner = {}
adsense.largeMobileBanner.cssClass = 'large-mobile-banner'
adsense.largeMobileBanner.height = 100 # px
adsense.largeMobileBanner.slotIds = ['6651071600', '2081271209', '3558004401']
adsense.largeMobileBanner.width = 320 # px
adsense.leaderboard = {}
adsense.leaderboard.cssClass = 'leaderboard'
adsense.leaderboard.height = 90 # px
adsense.leaderboard.slotIds = ['6790672401', '8267405609', '5174338406']
adsense.leaderboard.width = 728 # px
adsense.minimumDistance = 100 # px
adsense.readinessCheckInterval = 1000 # ms
adsense.skyscraper = {}
adsense.skyscraper.cssClass = 'skyscraper'
adsense.skyscraper.height = 600 # px
adsense.skyscraper.margin = 24 # px
adsense.skyscraper.slotIds = ['7613920409', '9574673605', '3388539204']
adsense.skyscraper.width = 160 # px
exports.defaultMods = defaultMods = {}
defaultMods.minecraft = { defaultVersion: '1.7.10' } # Minecraft must be first
defaultMods.advanced_solar_panels = { defaultVersion: '3.5.1' }
defaultMods.agricraft = { defaultVersion: '1.4.6' }
defaultMods.applied_energistics_2 = { defaultVersion: 'rv1-stable-1' }
defaultMods.big_reactors = { defaultVersion: '0.4.2A2' }
defaultMods.buildcraft = { defaultVersion: '6.4.6' }
defaultMods.computercraft = { defaultVersion: '1.74' }
defaultMods.enderio = { defaultVersion: '2.2.7.325' }
defaultMods.ender_storage = { defaultVersion: '1.4.5.29' }
defaultMods.enderio = { defaultVersion: '2.2.7.325' }
defaultMods.extra_cells = { defaultVersion: '2.2.73b129' }
defaultMods.extra_utilities = { defaultVersion: '1.2.2' }
defaultMods.forestry = { defaultVersion: '3.4.0.7' }
@@ -35,16 +50,20 @@ defaultMods.ic2_classic = { defaultVersion: 'none' }
defaultMods.industrial_craft_2 = { defaultVersion: '2.2.663' }
defaultMods.iron_chests = { defaultVersion: '6.0.62.742' }
defaultMods.jabba = { defaultVersion: '1.2.1a' }
defaultMods.logistics_pipes = { defaultVersion: '0.9.3.100' }
defaultMods.mekanism = { defaultVersion: '7.1.1.127' }
defaultMods.minefactory_reloaded = { defaultVersion: '2.8.0RC8-86' }
defaultMods.modular_powersuits = { defaultVersion: '0.11.0-300-thermal-expansion' }
defaultMods.opencomputers = { defaultVersion: '1.5.22' }
defaultMods.quantum_flux = { defaultVersion: '1.3.4' }
defaultMods.project_red = { defaultVersion: '4.5.16.77' }
defaultMods.railcraft = { defaultVersion: '9.5.0' }
defaultMods.simply_jetpacks = { defaultVersion: '1.4.1' }
defaultMods.solar_flux = { defaultVersion: '0.5b' }
defaultMods.storage_drawers = { defaultVersion: '1.7.10-1.6.2' }
defaultMods.thermal_dynamics = { defaultVersion: '1.0.0RC7-98' }
defaultMods.thermal_expansion = { defaultVersion: '4.0.0B8-23' }
defaultMods.tinkers_construct = { defaultVersion: '1.7.10-1.8.8' }
exports.duration = duration = {}
duration.snap = 100
@@ -109,6 +128,20 @@ exports.productionEnvs = [ 'staging', 'production' ]
exports.requiredMods = [ 'minecraft' ]
exports.screen = screen = {}
screen.mobileMaxWidth = 568 # px
screen.tabletMaxWidth = 960 # px
screen.type = {}
screen.type.desktop = 'desktop'
screen.type.mobile = 'mobile'
screen.type.tablet = 'tablet'
screen.type.compute = ->
width = $(document).width()
return screen.type.mobile if width <= screen.mobileMaxWidth
return screen.type.tablet if width <= screen.tabletMaxWidth
return screen.type.desktop
exports.server = {}
exports.server.defaultPort = 8080
@@ -133,6 +166,7 @@ url.login = _.template "/login"
url.mod = _.template "/browse/<%= modSlug %>/"
url.modData = _.template "/data/<%= modSlug %>/mod.cg"
url.modIcon = _.template "/data/<%= modSlug %>/icon.png"
url.modpackArchive = _.template "/data/modpack.cg"
url.modVersionData = _.template "/data/<%= modSlug %>/versions/<%= modVersion %>/mod-version.cg"
url.root = _.template "/"
url.tutorial = _.template "/browse/<%= modSlug %>/tutorials/<%= tutorialSlug %>/"
+1
View File
@@ -16,5 +16,6 @@ sendIndex = (request, response)->
router.get '/browse*', sendIndex
router.get '/craft*', sendIndex
router.get '/edit*', sendIndex
router.get '/login*', sendIndex
router.get '/news*', sendIndex