Compare commits
52
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
240a14da58 | ||
|
|
c441d75529 | ||
|
|
1bc89c1c89 | ||
|
|
43202e9917 | ||
|
|
05bc1a271d | ||
|
|
da1419d6b6 | ||
|
|
841fac38d3 | ||
|
|
2b8e23b32f | ||
|
|
5eae2bb488 | ||
|
|
6fa18c764b | ||
|
|
c9796a142d | ||
|
|
0718590f56 | ||
|
|
51f566ebf1 | ||
|
|
d2d904be7f | ||
|
|
088994f366 | ||
|
|
184b64a6af | ||
|
|
4aca035709 | ||
|
|
ebf3443e96 | ||
|
|
fd5372b35d | ||
|
|
f464558cd2 | ||
|
|
e7cd3f0549 | ||
|
|
545408a7e7 | ||
|
|
83156c30c7 | ||
|
|
636a8d061c | ||
|
|
2dbda99986 | ||
|
|
7d83552013 | ||
|
|
35bb12de6a | ||
|
|
1d1772e961 | ||
|
|
6787063ac7 | ||
|
|
9e09b8d87c | ||
|
|
2c77972073 | ||
|
|
31f4594928 | ||
|
|
eb9ac15de8 | ||
|
|
e922f3c5cc | ||
|
|
a8d08b93c5 | ||
|
|
64e118a2c8 | ||
|
|
6671541dcb | ||
|
|
962165dc8e | ||
|
|
f9b65dd892 | ||
|
|
979586d9d3 | ||
|
|
c522e60e28 | ||
|
|
f9cd38947d | ||
|
|
99b6cf2861 | ||
|
|
d925a17940 | ||
|
|
a2bbdf4645 | ||
|
|
93c98e16ac | ||
|
|
88e57b1200 | ||
|
|
1e96cf2d6c | ||
|
|
ccaf8e9842 | ||
|
|
e1f8282049 | ||
|
|
d873c4b7f1 | ||
|
|
3529bccf3a |
+7
-2
@@ -54,7 +54,7 @@ module.exports = (grunt)->
|
|||||||
mode: 'gzip'
|
mode: 'gzip'
|
||||||
files: [
|
files: [
|
||||||
{expand: true, cwd:'./build/static', src:'**/*.css', dest:'./dist/'}
|
{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:'**/*.ugly.js', dest:'./dist/', ext: '.js'}
|
||||||
{expand: true, cwd:'./build/static', src:'**/*.json', dest:'./dist/'}
|
{expand: true, cwd:'./build/static', src:'**/*.json', dest:'./dist/'}
|
||||||
{expand: true, cwd:'./build/static', src:'**/*.ttf', dest:'./dist/'}
|
{expand: true, cwd:'./build/static', src:'**/*.ttf', dest:'./dist/'}
|
||||||
@@ -77,7 +77,10 @@ module.exports = (grunt)->
|
|||||||
]
|
]
|
||||||
build_to_dist:
|
build_to_dist:
|
||||||
files: [
|
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:
|
common_source:
|
||||||
files: [
|
files: [
|
||||||
@@ -135,6 +138,8 @@ module.exports = (grunt)->
|
|||||||
|
|
||||||
sass:
|
sass:
|
||||||
all:
|
all:
|
||||||
|
options:
|
||||||
|
sourcemap: 'none'
|
||||||
files:
|
files:
|
||||||
'./build/static/main.css': [ './build/imports.scss' ]
|
'./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
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "crafting-guide",
|
"name": "crafting-guide",
|
||||||
"version": "3.2.2",
|
"version": "3.2.4",
|
||||||
"description": "A guide for building anything in Minecraft or its many mods",
|
"description": "A guide for building anything in Minecraft or its many mods",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"repository": "http://github.com/andrewminer/crafting-guide",
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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');
|
||||||
@@ -9,6 +9,9 @@
|
|||||||
|
|
||||||
module.exports = class BaseModel extends Backbone.Model
|
module.exports = class BaseModel extends Backbone.Model
|
||||||
|
|
||||||
|
@_loadingQueue = []
|
||||||
|
@_isDraining = false
|
||||||
|
|
||||||
constructor: (attributes={}, options={})->
|
constructor: (attributes={}, options={})->
|
||||||
options.logEvents ?= true
|
options.logEvents ?= true
|
||||||
super attributes, options
|
super attributes, options
|
||||||
@@ -19,10 +22,10 @@ module.exports = class BaseModel extends Backbone.Model
|
|||||||
continue if name is 'id'
|
continue if name is 'id'
|
||||||
Object.defineProperty this, name, get:makeGetter(name), set:makeSetter(name)
|
Object.defineProperty this, name, get:makeGetter(name), set:makeSetter(name)
|
||||||
|
|
||||||
|
@fileCache = options.fileCache or null
|
||||||
|
@loading = null
|
||||||
@logEvents = options.logEvents or false
|
@logEvents = options.logEvents or false
|
||||||
@state = c.modelState.unloaded
|
@state = c.modelState.unloaded
|
||||||
|
|
||||||
@loading = null
|
|
||||||
|
|
||||||
Object.defineProperties this,
|
Object.defineProperties this,
|
||||||
isUnloaded: { get:-> @state is c.modelState.unloaded }
|
isUnloaded: { get:-> @state is c.modelState.unloaded }
|
||||||
@@ -60,12 +63,23 @@ module.exports = class BaseModel extends Backbone.Model
|
|||||||
|
|
||||||
@state = c.modelState.loading
|
@state = c.modelState.loading
|
||||||
@trigger c.event.request, this
|
@trigger c.event.request, this
|
||||||
@loading = w.promise (resolve, reject)=>
|
|
||||||
$.ajax
|
loadFromServer = =>
|
||||||
url: url
|
w.promise (resolve, reject)=>
|
||||||
dataType: 'text'
|
$.ajax
|
||||||
success: (text, status, xhr)=> resolve @onLoadSucceeded text, status, xhr
|
url: url
|
||||||
error: (xhr, status, error)=> reject @onLoadFailed error, status, xhr
|
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
|
@loading.catch (e)-> # do nothing
|
||||||
return @loading
|
return @loading
|
||||||
@@ -86,3 +100,30 @@ module.exports = class BaseModel extends Backbone.Model
|
|||||||
|
|
||||||
toString: ->
|
toString: ->
|
||||||
return "#{@constructor.name}.#{@cid}"
|
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 = {}
|
@_rawScores = {}
|
||||||
@_scores = {}
|
@_scores = {}
|
||||||
@_steps = steps
|
@_steps = steps
|
||||||
|
@_tools = null
|
||||||
@_want = want
|
@_want = want
|
||||||
|
|
||||||
@_numberSteps()
|
@_numberSteps()
|
||||||
@@ -37,19 +38,32 @@ module.exports = class CraftingPlan
|
|||||||
@_made = new SimpleInventory modPack:@_modPack
|
@_made = new SimpleInventory modPack:@_modPack
|
||||||
@_made.addInventory @_have
|
@_made.addInventory @_have
|
||||||
|
|
||||||
|
@_tools = new SimpleInventory modPack:@_modPack
|
||||||
|
|
||||||
for i in [@_steps.length-1..0] by -1
|
for i in [@_steps.length-1..0] by -1
|
||||||
step = @_steps[i]
|
step = @_steps[i]
|
||||||
step.multiplier = 0
|
step.multiplier = 0
|
||||||
|
recipe = step.recipe
|
||||||
|
|
||||||
for stack in step.recipe.output
|
for stack in step.recipe.output
|
||||||
if not stack?
|
continue if recipe.isPassThroughFor stack.itemSlug
|
||||||
throw new Error 'stack should not be null here'
|
|
||||||
|
|
||||||
qualifiedSlug = @_modPack.qualifySlug stack.itemSlug
|
qualifiedSlug = @_modPack.qualifySlug stack.itemSlug
|
||||||
|
|
||||||
while @_need.quantityOf(qualifiedSlug) > 0
|
while @_need.quantityOf(qualifiedSlug) > 0
|
||||||
@_executeStep step
|
@_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 @_want
|
||||||
|
@_made.addInventory @_tools
|
||||||
@_pruneEmptySteps()
|
@_pruneEmptySteps()
|
||||||
@_numberSteps()
|
@_numberSteps()
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,22 @@ describe 'crafting_plan.coffee', ->
|
|||||||
'1x 8 test__iron_ore,test__coal>.0. ... .1.>test__furnace>8 test__iron_ingot'
|
'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', ->
|
it 'can compute multiple items with multiple plans', ->
|
||||||
plans = fixtures.makePlans [1, 'test__copper_block'], [1, 'test__iron_sword']
|
plans = fixtures.makePlans [1, 'test__copper_block'], [1, 'test__iron_sword']
|
||||||
plans.length.should.equal 4
|
plans.length.should.equal 4
|
||||||
|
|||||||
@@ -27,10 +27,11 @@ module.exports = class CraftingStep
|
|||||||
|
|
||||||
addToolsTo: (targetInventory)->
|
addToolsTo: (targetInventory)->
|
||||||
for stack in @_recipe.tools
|
for stack in @_recipe.tools
|
||||||
targetInventory.add stack.itemSlug, stack.quantity
|
targetInventory.add stack.itemSlug, stack.quantity, insert:true
|
||||||
|
|
||||||
completeInto: (targetInventory)->
|
completeInto: (targetInventory)->
|
||||||
for stack in @_recipe.output
|
for stack in @_recipe.output
|
||||||
|
continue if @_recipe.isPassThroughFor stack.itemSlug
|
||||||
quantity = @_recipe.getQuantityProduced stack.itemSlug
|
quantity = @_recipe.getQuantityProduced stack.itemSlug
|
||||||
targetInventory.add stack.itemSlug, quantity * @_multiplier
|
targetInventory.add stack.itemSlug, quantity * @_multiplier
|
||||||
|
|
||||||
@@ -67,4 +68,6 @@ module.exports = class CraftingStep
|
|||||||
@_inventory = new SimpleInventory
|
@_inventory = new SimpleInventory
|
||||||
for stack in @_recipe.input
|
for stack in @_recipe.input
|
||||||
qualifiedSlug = @_modPack.qualifySlug stack.itemSlug
|
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
|
||||||
|
|||||||
@@ -22,57 +22,43 @@ module.exports = class Craftsman extends BaseModel
|
|||||||
@::PLAN_STEP_INCREMENT = 39
|
@::PLAN_STEP_INCREMENT = 39
|
||||||
|
|
||||||
@::STAGE =
|
@::STAGE =
|
||||||
WAITING: 'waiting'
|
EMPTY: 'empty'
|
||||||
|
READY: 'ready'
|
||||||
GRAPHING: 'examining recipes'
|
GRAPHING: 'examining recipes'
|
||||||
PLANNING: 'computing plans'
|
PLANNING: 'computing plans'
|
||||||
ANALYZING: 'analyzing plans'
|
ANALYZING: 'analyzing plans'
|
||||||
COMPLETE: 'complete'
|
COMPLETE: 'complete'
|
||||||
INVALID: 'invalid'
|
INVALID: 'invalid'
|
||||||
|
OUTDATED: 'outdated'
|
||||||
|
|
||||||
constructor: (modPack)->
|
constructor: (modPack)->
|
||||||
if not modPack? then throw new Error 'modPack is required'
|
if not modPack? then throw new Error 'modPack is required'
|
||||||
attributes =
|
attributes =
|
||||||
paused: false
|
stage: @STAGE.READY
|
||||||
stage: @STAGE.WAITING
|
|
||||||
stageCount: 0
|
stageCount: 0
|
||||||
super attributes, {}
|
super attributes, {}
|
||||||
|
|
||||||
@_modPack = modPack
|
@_modPack = modPack
|
||||||
|
|
||||||
reset = _.debounce (=> @reset()), 100
|
|
||||||
reevaluatePlans = _.debounce (=> @reevaluatePlans()), 100
|
|
||||||
|
|
||||||
@_have = new Inventory modPack:@_modPack
|
@_have = new Inventory modPack:@_modPack
|
||||||
@_have.on c.event.change, reevaluatePlans
|
@_have.on c.event.change, => @_resetStage()
|
||||||
|
|
||||||
@_want = new Inventory modPack:@_modPack
|
@_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 c.event.change + ':stage', => logger.info "Craftsman has started #{@stage}..."
|
||||||
@on 'scheduleNextWork', => @_scheduleNextWork()
|
@on 'scheduleNextWork', => @_scheduleNextWork()
|
||||||
@reset()
|
@reset()
|
||||||
|
|
||||||
# Public Methods ###############################################################################
|
# Public Methods ###############################################################################
|
||||||
|
|
||||||
reevaluatePlans: ->
|
|
||||||
@_plans = null
|
|
||||||
@_planEvaluator = null
|
|
||||||
@stage = @STAGE.WAITING
|
|
||||||
@stageCount = 0
|
|
||||||
|
|
||||||
@_scheduleNextWork()
|
|
||||||
|
|
||||||
reset: ->
|
reset: ->
|
||||||
@_graphBuilder = null
|
@_graphBuilder = null
|
||||||
@_planBuilder = null
|
@_planBuilder = null
|
||||||
@_planEvaluator = null
|
@_planEvaluator = null
|
||||||
@_plans = null
|
@_plans = null
|
||||||
|
|
||||||
@stage = @STAGE.WAITING
|
@_resetStage()
|
||||||
@stageCount = 0
|
|
||||||
|
|
||||||
@_scheduleNextWork()
|
|
||||||
|
|
||||||
work: ->
|
work: ->
|
||||||
return if @_want.isEmpty
|
return if @_want.isEmpty
|
||||||
@@ -130,7 +116,7 @@ module.exports = class Craftsman extends BaseModel
|
|||||||
Object.defineProperties @prototype,
|
Object.defineProperties @prototype,
|
||||||
|
|
||||||
complete:
|
complete:
|
||||||
get: -> @stage in [@STAGE.COMPLETE, @STAGE.INVALID]
|
get: -> @stage in [@STAGE.COMPLETE, @STAGE.INVALID, @STAGE.OUTDATED]
|
||||||
|
|
||||||
have:
|
have:
|
||||||
get: -> @_have
|
get: -> @_have
|
||||||
@@ -143,8 +129,19 @@ module.exports = class Craftsman extends BaseModel
|
|||||||
|
|
||||||
# Private Methods ##############################################################################
|
# 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: ->
|
_scheduleNextWork: ->
|
||||||
return if @paused
|
|
||||||
return if @want.isEmpty
|
return if @want.isEmpty
|
||||||
return if @complete
|
return if @complete
|
||||||
|
|
||||||
|
|||||||
@@ -98,6 +98,12 @@ MOD_VERSION_FILE =
|
|||||||
input: Stick, Cobblestone
|
input: Stick, Cobblestone
|
||||||
pattern: .0. .1. ...
|
pattern: .0. .1. ...
|
||||||
|
|
||||||
|
item: Maul
|
||||||
|
recipe:
|
||||||
|
input: Iron Ingot, Stick
|
||||||
|
pattern: 001 001 ..1
|
||||||
|
tools: Crafting Table
|
||||||
|
|
||||||
item: Oak Planks
|
item: Oak Planks
|
||||||
recipe:
|
recipe:
|
||||||
input: Oak Wood
|
input: Oak Wood
|
||||||
@@ -107,12 +113,29 @@ MOD_VERSION_FILE =
|
|||||||
item: Oak Wood
|
item: Oak Wood
|
||||||
gatherable: yes
|
gatherable: yes
|
||||||
|
|
||||||
|
item: Spruce Wood
|
||||||
|
gatherable: yes
|
||||||
|
|
||||||
item: Stick
|
item: Stick
|
||||||
recipe:
|
recipe:
|
||||||
input: Oak Planks
|
input: Oak Planks
|
||||||
pattern: .0. .0. ...
|
pattern: .0. .0. ...
|
||||||
quantity: 4
|
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
|
item: String
|
||||||
gatherable: yes
|
gatherable: yes
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ module.exports = class SimpleInventory
|
|||||||
@_itemSlugs = []
|
@_itemSlugs = []
|
||||||
|
|
||||||
clone: ->
|
clone: ->
|
||||||
inventory = new Inventory
|
inventory = new SimpleInventory
|
||||||
inventory.addInventory this
|
inventory.addInventory this
|
||||||
return inventory
|
return inventory
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ module.exports = class SimpleInventory
|
|||||||
|
|
||||||
if qualifiedSlug?
|
if qualifiedSlug?
|
||||||
newSlugs.push qualifiedSlug
|
newSlugs.push qualifiedSlug
|
||||||
newStacks.push new Stack itemSlug:qualifiedSlug, quantity:stack.quantity
|
newStacks.push new SimpleStack itemSlug:qualifiedSlug, quantity:stack.quantity
|
||||||
else
|
else
|
||||||
newSlugs.push itemSlug
|
newSlugs.push itemSlug
|
||||||
newStacks.push stack
|
newStacks.push stack
|
||||||
@@ -130,9 +130,9 @@ module.exports = class SimpleInventory
|
|||||||
parse: (data)->
|
parse: (data)->
|
||||||
return this if not data? or data.length is 0
|
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
|
for stackText in stacks
|
||||||
stackParts = stackText.split Inventory.Delimiters.Item
|
stackParts = stackText.split SimpleInventory.Delimiters.Item
|
||||||
if stackParts.length is 2
|
if stackParts.length is 2
|
||||||
quantity = parseInt stackParts[0], 10
|
quantity = parseInt stackParts[0], 10
|
||||||
itemSlug = ItemSlug.slugify stackParts[1]
|
itemSlug = ItemSlug.slugify stackParts[1]
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
###
|
#
|
||||||
# Crafting Guide - event_recorder.coffee
|
# Crafting Guide - event_recorder.coffee
|
||||||
#
|
#
|
||||||
# Copyright (c) 2014-2015 by Redwood Labs
|
# Copyright © 2014-2016 by Redwood Labs
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
###
|
#
|
||||||
|
|
||||||
util = require 'util'
|
util = require 'util'
|
||||||
|
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ module.exports = class Inventory extends BaseModel
|
|||||||
|
|
||||||
# Public Methods ###############################################################################
|
# Public Methods ###############################################################################
|
||||||
|
|
||||||
add: (itemSlug, quantity=1)->
|
add: (itemSlug, quantity=1, options={})->
|
||||||
return this unless quantity > 0
|
return this unless quantity > 0
|
||||||
|
|
||||||
@_add itemSlug, quantity
|
@_add itemSlug, quantity, options
|
||||||
@trigger c.event.add, this, itemSlug, quantity
|
@trigger c.event.add, this, itemSlug, quantity
|
||||||
@trigger c.event.change, this
|
@trigger c.event.change, this
|
||||||
return this
|
return this
|
||||||
@@ -141,6 +141,18 @@ module.exports = class Inventory extends BaseModel
|
|||||||
@trigger c.event.change, this
|
@trigger c.event.change, this
|
||||||
return 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 ##############################################################################
|
# Parsing Methods ##############################################################################
|
||||||
|
|
||||||
parse: (data)->
|
parse: (data)->
|
||||||
@@ -209,7 +221,8 @@ module.exports = class Inventory extends BaseModel
|
|||||||
|
|
||||||
# Private Methods ##############################################################################
|
# Private Methods ##############################################################################
|
||||||
|
|
||||||
_add: (itemSlug, quantity=1)->
|
_add: (itemSlug, quantity=1, options={})->
|
||||||
|
options.insert ?= false
|
||||||
return unless itemSlug?
|
return unless itemSlug?
|
||||||
return unless quantity > 0
|
return unless quantity > 0
|
||||||
|
|
||||||
@@ -218,7 +231,10 @@ module.exports = class Inventory extends BaseModel
|
|||||||
stack = new Stack itemSlug:itemSlug, quantity:quantity
|
stack = new Stack itemSlug:itemSlug, quantity:quantity
|
||||||
@listenTo stack, c.event.change, => @trigger c.event.change, this
|
@listenTo stack, c.event.change, => @trigger c.event.change, this
|
||||||
@_stacks[itemSlug] = stack
|
@_stacks[itemSlug] = stack
|
||||||
@_itemSlugs.push itemSlug
|
if options.insert
|
||||||
|
@_itemSlugs.unshift itemSlug
|
||||||
|
else
|
||||||
|
@_itemSlugs.push itemSlug
|
||||||
@_sort()
|
@_sort()
|
||||||
else
|
else
|
||||||
stack.quantity += quantity
|
stack.quantity += quantity
|
||||||
|
|||||||
@@ -29,8 +29,6 @@ module.exports = class Mod extends BaseModel
|
|||||||
@_modVersions = []
|
@_modVersions = []
|
||||||
@_tutorials = []
|
@_tutorials = []
|
||||||
|
|
||||||
@once c.event.sync, => @_verifyActiveModVersion()
|
|
||||||
|
|
||||||
# Class Methods ##################################################################################
|
# Class Methods ##################################################################################
|
||||||
|
|
||||||
@Version: Version =
|
@Version: Version =
|
||||||
@@ -95,6 +93,12 @@ module.exports = class Mod extends BaseModel
|
|||||||
|
|
||||||
# Item Methods #################################################################################
|
# Item Methods #################################################################################
|
||||||
|
|
||||||
|
chooseRandomItem: ->
|
||||||
|
effectiveModVersion = @_activeModVersion or @getModVersion Mod.Version.Latest
|
||||||
|
return null unless effectiveModVersion?
|
||||||
|
|
||||||
|
return effectiveModVersion.chooseRandomItem()
|
||||||
|
|
||||||
eachItem: (callback)->
|
eachItem: (callback)->
|
||||||
effectiveModVersion = @_activeModVersion or @getModVersion Mod.Version.Latest
|
effectiveModVersion = @_activeModVersion or @getModVersion Mod.Version.Latest
|
||||||
effectiveModVersion.eachItem callback
|
effectiveModVersion.eachItem callback
|
||||||
@@ -129,6 +133,7 @@ module.exports = class Mod extends BaseModel
|
|||||||
|
|
||||||
@_modVersions.push modVersion
|
@_modVersions.push modVersion
|
||||||
@listenTo modVersion, c.event.change, => @trigger c.event.change, this
|
@listenTo modVersion, c.event.change, => @trigger c.event.change, this
|
||||||
|
modVersion.fileCache = this.fileCache
|
||||||
modVersion.mod = this
|
modVersion.mod = this
|
||||||
|
|
||||||
@trigger c.event.add + ':modVersion', modVersion, this
|
@trigger c.event.add + ':modVersion', modVersion, this
|
||||||
@@ -143,6 +148,9 @@ module.exports = class Mod extends BaseModel
|
|||||||
for modVersion in @_modVersions
|
for modVersion in @_modVersions
|
||||||
callback modVersion
|
callback modVersion
|
||||||
|
|
||||||
|
getAllModVersions: ->
|
||||||
|
return @_modVersions[..]
|
||||||
|
|
||||||
getModVersion: (version)->
|
getModVersion: (version)->
|
||||||
return null if version is Mod.Version.None
|
return null if version is Mod.Version.None
|
||||||
return @_modVersions[0] if version is Mod.Version.Latest
|
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 ?= new ModParser model:this
|
||||||
@_parser.parse text
|
@_parser.parse text
|
||||||
|
|
||||||
|
@_verifyActiveModVersion()
|
||||||
|
|
||||||
return null # prevent calling `set`
|
return null # prevent calling `set`
|
||||||
|
|
||||||
url: ->
|
url: ->
|
||||||
|
|||||||
@@ -6,9 +6,10 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
BaseModel = require '../base_model'
|
BaseModel = require '../base_model'
|
||||||
Inventory = require './inventory'
|
Mod = require './mod'
|
||||||
ModVersionParser = require '../parsing/mod_version_parser'
|
ModVersionParser = require '../parsing/mod_version_parser'
|
||||||
Recipe = require './recipe'
|
Recipe = require './recipe'
|
||||||
|
SimpleInventory = require '../crafting/simple_inventory'
|
||||||
|
|
||||||
########################################################################################################################
|
########################################################################################################################
|
||||||
|
|
||||||
@@ -24,6 +25,12 @@ module.exports = class ModPack extends BaseModel
|
|||||||
|
|
||||||
# Item Methods #################################################################################
|
# Item Methods #################################################################################
|
||||||
|
|
||||||
|
chooseRandomItem: ->
|
||||||
|
return null unless @_mods.length > 0
|
||||||
|
|
||||||
|
modIndex = Math.floor Math.random() * @_mods.length
|
||||||
|
return @_mods[modIndex].chooseRandomItem()
|
||||||
|
|
||||||
findItem: (itemSlug, options={})->
|
findItem: (itemSlug, options={})->
|
||||||
options.includeDisabled ?= false
|
options.includeDisabled ?= false
|
||||||
|
|
||||||
@@ -75,7 +82,7 @@ module.exports = class ModPack extends BaseModel
|
|||||||
result.modSlug = @_mods[0].slug
|
result.modSlug = @_mods[0].slug
|
||||||
result.modVersion = @_mods[0].activeVersion
|
result.modVersion = @_mods[0].activeVersion
|
||||||
|
|
||||||
craftingUrlInventory = new Inventory modPack:this
|
craftingUrlInventory = new SimpleInventory modPack:this
|
||||||
if item?.multiblock?
|
if item?.multiblock?
|
||||||
craftingUrlInventory.addInventory item.multiblock.inventory
|
craftingUrlInventory.addInventory item.multiblock.inventory
|
||||||
else
|
else
|
||||||
@@ -165,12 +172,18 @@ module.exports = class ModPack extends BaseModel
|
|||||||
# Private Methods ##############################################################################
|
# Private Methods ##############################################################################
|
||||||
|
|
||||||
_onModVersionLoaded: (modVersion)->
|
_onModVersionLoaded: (modVersion)->
|
||||||
working = true
|
mods = @getAllMods()
|
||||||
@eachMod (mod)->
|
return true unless mods.length > 0
|
||||||
mod.eachModVersion (modVersion)->
|
|
||||||
working = working and (modVersion.isUnloaded or modVersion.isLoading)
|
|
||||||
|
|
||||||
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.change, this
|
||||||
@trigger c.event.sync, this
|
@trigger c.event.sync, this
|
||||||
|
|||||||
@@ -59,6 +59,10 @@ module.exports = class ModVersion extends BaseModel
|
|||||||
return null if result.length is 0
|
return null if result.length is 0
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
chooseRandomItem: ->
|
||||||
|
itemIndex = Math.floor Math.random() * @_slugs.length
|
||||||
|
return @_slugs[itemIndex]
|
||||||
|
|
||||||
eachItem: (callback)->
|
eachItem: (callback)->
|
||||||
for slug in @_slugs
|
for slug in @_slugs
|
||||||
item = @findItem slug
|
item = @findItem slug
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ module.exports = class Recipe extends BaseModel
|
|||||||
if modPack?.findItemByName(@condition.noun)?
|
if modPack?.findItemByName(@condition.noun)?
|
||||||
result = true
|
result = true
|
||||||
else if @condition.verb is 'mod'
|
else if @condition.verb is 'mod'
|
||||||
modPack.eachMod (mod)->
|
modPack.eachMod (mod)=>
|
||||||
if mod.name is @condition.noun
|
if mod.name is @condition.noun
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
@@ -111,16 +111,7 @@ module.exports = class Recipe extends BaseModel
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
isPassThroughFor: (itemSlug)->
|
isPassThroughFor: (itemSlug)->
|
||||||
amountCreated = 0
|
return @getQuantityProduced(itemSlug) is @getQuantityRequired(itemSlug)
|
||||||
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
|
|
||||||
|
|
||||||
produces: (itemSlug)->
|
produces: (itemSlug)->
|
||||||
if not @_produces?
|
if not @_produces?
|
||||||
@@ -221,7 +212,11 @@ module.exports = class Recipe extends BaseModel
|
|||||||
_computeQuantities: (pattern)->
|
_computeQuantities: (pattern)->
|
||||||
quantityMap = {}
|
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 '.'
|
||||||
continue if c is ' '
|
continue if c is ' '
|
||||||
|
|
||||||
|
|||||||
@@ -1,143 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - lexical_analyzer.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
ParserCommand = require './parser_command'
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
module.exports = class LexicalAnalyzer
|
|
||||||
|
|
||||||
constructor: (fileName, rawText)->
|
|
||||||
if not fileName? then throw new Error 'fileName is required'
|
|
||||||
if not rawText? then throw new Error 'rawText is required'
|
|
||||||
|
|
||||||
@_commands = []
|
|
||||||
@_fileName = fileName
|
|
||||||
@_rawText = rawText
|
|
||||||
@_lines = rawText.split '\n'
|
|
||||||
@_lineIndex = -1
|
|
||||||
@_lineNumber = 0
|
|
||||||
|
|
||||||
# Class Methods ################################################################################
|
|
||||||
|
|
||||||
@::COMMAND = /\ *([^:]*):?(.*)/
|
|
||||||
|
|
||||||
@::COMMENT = /([^\\]?)#.*/
|
|
||||||
|
|
||||||
@::FILE = /^#FILE +(.*)/
|
|
||||||
|
|
||||||
# Public Methods ###############################################################################
|
|
||||||
|
|
||||||
next: ->
|
|
||||||
command = @peek()
|
|
||||||
@_commands.shift()
|
|
||||||
return command
|
|
||||||
|
|
||||||
peek: ->
|
|
||||||
while @_commands.length is 0
|
|
||||||
break if @_lineNumber > @_lines.length
|
|
||||||
@_parseLine()
|
|
||||||
|
|
||||||
return null unless @_commands.length > 0
|
|
||||||
return @_commands[0]
|
|
||||||
|
|
||||||
push: (command)->
|
|
||||||
@_commands.unshift command
|
|
||||||
|
|
||||||
# Property Methods #############################################################################
|
|
||||||
|
|
||||||
getIsFinished: ->
|
|
||||||
return @peek() is null
|
|
||||||
|
|
||||||
Object.defineProperties @prototype,
|
|
||||||
isFinished: { get:@::getIsFinished }
|
|
||||||
|
|
||||||
# Private Methods ##############################################################################
|
|
||||||
|
|
||||||
_currentLine: ->
|
|
||||||
return null if @_lineIndex >= @_lines.length
|
|
||||||
return @_lines[@_lineIndex]
|
|
||||||
|
|
||||||
_nextLine: ->
|
|
||||||
if @_lineIndex < @_lines.length
|
|
||||||
while true
|
|
||||||
@_lineIndex += 1
|
|
||||||
@_lineNumber += 1
|
|
||||||
break if @_lineIndex >= @_lines.length
|
|
||||||
|
|
||||||
line = @_lines[@_lineIndex]
|
|
||||||
|
|
||||||
fileMatch = line.match @FILE, '$1'
|
|
||||||
if fileMatch?
|
|
||||||
@_fileName = fileMatch[1]
|
|
||||||
@_lineNumber = 0
|
|
||||||
else
|
|
||||||
line = line.replace @COMMENT, '$1'
|
|
||||||
@_lines[@_lineIndex] = line
|
|
||||||
|
|
||||||
break if line.trim().length > 0
|
|
||||||
|
|
||||||
return @_currentLine()
|
|
||||||
|
|
||||||
_parseHereDoc: ->
|
|
||||||
line = @_currentLine()
|
|
||||||
hereDocIndex = line.indexOf '<<-'
|
|
||||||
return [line, null] unless hereDocIndex isnt -1
|
|
||||||
|
|
||||||
hereDocStopText = line[hereDocIndex+3...line.length]
|
|
||||||
line = line[0...hereDocIndex]
|
|
||||||
|
|
||||||
hereDocLines = []
|
|
||||||
while true
|
|
||||||
nextLine = @_nextLine()
|
|
||||||
break unless nextLine?
|
|
||||||
break if nextLine.trim() is hereDocStopText
|
|
||||||
hereDocLines.push nextLine
|
|
||||||
|
|
||||||
shortestIndent = Number.MAX_VALUE
|
|
||||||
for hereDocLine in hereDocLines
|
|
||||||
continue if hereDocLine.trim().length is 0
|
|
||||||
shortestIndent = Math.min hereDocLine.match(/( *).*/)[1].length, shortestIndent
|
|
||||||
|
|
||||||
for i in [0...hereDocLines.length]
|
|
||||||
hereDocLines[i] = hereDocLines[i][shortestIndent..]
|
|
||||||
|
|
||||||
return [line, null] unless hereDocLines.length > 0
|
|
||||||
return [line, hereDocLines.join('\n')]
|
|
||||||
|
|
||||||
_parseLine: ->
|
|
||||||
line = @_nextLine()
|
|
||||||
return unless line?
|
|
||||||
|
|
||||||
startingLineNumber = @_lineNumber
|
|
||||||
[line, lineHereDoc] = @_parseHereDoc()
|
|
||||||
|
|
||||||
lineParts = (part.trim() for part in line.split(';'))
|
|
||||||
for linePart, index in lineParts
|
|
||||||
continue if linePart.length is 0
|
|
||||||
|
|
||||||
hereDoc = lineHereDoc if index is lineParts.length - 1
|
|
||||||
|
|
||||||
match = @COMMAND.exec linePart
|
|
||||||
if not match? then throw new Error "Expected <command>: <args>, but found: \"#{linePart}\""
|
|
||||||
|
|
||||||
argText = if match[2] then match[2].trim() else ''
|
|
||||||
args = (arg.trim() for arg in argText.split(','))
|
|
||||||
args = (arg for arg in args when arg.length > 0)
|
|
||||||
|
|
||||||
if hereDoc?
|
|
||||||
if argText.length > 0 then argText += ', '
|
|
||||||
argText += hereDoc
|
|
||||||
args.push hereDoc
|
|
||||||
|
|
||||||
@_commands.push new ParserCommand
|
|
||||||
argText: argText
|
|
||||||
args: args
|
|
||||||
fileName: @_fileName
|
|
||||||
hereDoc: hereDoc
|
|
||||||
lineNumber: startingLineNumber
|
|
||||||
name: match[1]
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - lexical_analyzer.test.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
LexicalAnalyzer = require './lexical_analyzer'
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
lexer = null
|
|
||||||
|
|
||||||
createLexer = (text)->
|
|
||||||
return new LexicalAnalyzer 'file.cg', text
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
describe 'lexical_analyzer.coffee', ->
|
|
||||||
|
|
||||||
describe 'a document with', ->
|
|
||||||
|
|
||||||
it 'no content returns null immediately', ->
|
|
||||||
lexer = createLexer ''
|
|
||||||
expect(lexer.next()).to.be.null
|
|
||||||
|
|
||||||
it 'only whitespace returns null immediately', ->
|
|
||||||
lexer = createLexer '\n\n \n \n\n'
|
|
||||||
expect(lexer.next()).to.be.null
|
|
||||||
|
|
||||||
it 'a single command returns only that command', ->
|
|
||||||
lexer = createLexer 'alpha: bravo'
|
|
||||||
lexer.next().name.should.equal 'alpha'
|
|
||||||
expect(lexer.next()).to.be.null
|
|
||||||
|
|
||||||
it 'multiple commands on a single line returns all commands', ->
|
|
||||||
lexer = createLexer 'alpha: bravo; charlie: delta; echo: foxtrot'
|
|
||||||
lexer.next().name.should.equal 'alpha'
|
|
||||||
lexer.next().name.should.equal 'charlie'
|
|
||||||
lexer.next().name.should.equal 'echo'
|
|
||||||
expect(lexer.next()).to.be.null
|
|
||||||
|
|
||||||
it 'multiple commands on separate lines returns all commands', ->
|
|
||||||
lexer = createLexer 'alpha: bravo \n charlie: delta \n echo: foxtrot'
|
|
||||||
lexer.next().name.should.equal 'alpha'
|
|
||||||
lexer.next().name.should.equal 'charlie'
|
|
||||||
lexer.next().name.should.equal 'echo'
|
|
||||||
expect(lexer.next()).to.be.null
|
|
||||||
|
|
||||||
describe 'a command with', ->
|
|
||||||
|
|
||||||
it 'only a name has no arguments', ->
|
|
||||||
command = createLexer('alpha:').next()
|
|
||||||
command.argText.should.equal ''
|
|
||||||
command.args.should.eql []
|
|
||||||
|
|
||||||
it 'one argument has only that argument', ->
|
|
||||||
command = createLexer('alpha: bravo').next()
|
|
||||||
command.argText.should.equal 'bravo'
|
|
||||||
command.args.should.eql ['bravo']
|
|
||||||
|
|
||||||
it 'multiple arguments has all of them', ->
|
|
||||||
command = createLexer('alpha: bravo, charlie, delta').next()
|
|
||||||
command.argText.should.equal 'bravo, charlie, delta'
|
|
||||||
command.args.should.eql ['bravo', 'charlie', 'delta']
|
|
||||||
|
|
||||||
it 'only a heredoc has it recorded in the right places', ->
|
|
||||||
command = createLexer('alpha: <<-END\nbravo charlie\nEND').next()
|
|
||||||
command.hereDoc.should.equal 'bravo charlie'
|
|
||||||
command.args.should.eql ['bravo charlie']
|
|
||||||
command.argText.should.equal 'bravo charlie'
|
|
||||||
|
|
||||||
it 'multiple args and a hereDoc is built correctly', ->
|
|
||||||
command = createLexer('alpha: bravo, charlie <<-END\ndelta echo\nfoxtrot\nEND').next()
|
|
||||||
command.hereDoc.should.equal 'delta echo\nfoxtrot'
|
|
||||||
command.argText.should.equal 'bravo, charlie, delta echo\nfoxtrot'
|
|
||||||
command.args.should.eql ['bravo', 'charlie', 'delta echo\nfoxtrot']
|
|
||||||
|
|
||||||
describe 'file name is assigned correctly when', ->
|
|
||||||
|
|
||||||
it 'no file markers are given', ->
|
|
||||||
lexer = createLexer 'alpha: bravo\ncharlie: delta'
|
|
||||||
lexer.next().fileName.should.equal 'file.cg'
|
|
||||||
lexer.next().fileName.should.equal 'file.cg'
|
|
||||||
|
|
||||||
it 'commands appear before the first file marker', ->
|
|
||||||
lexer = createLexer 'alpha: bravo\n#FILE file2.cg\ncharlie: delta'
|
|
||||||
lexer.next().fileName.should.equal 'file.cg'
|
|
||||||
lexer.next().fileName.should.equal 'file2.cg'
|
|
||||||
|
|
||||||
it 'multiple file markers are used', ->
|
|
||||||
lexer = createLexer '#FILE file1.cg\na: b\n#FILE file2.cg\nc: d\n#FILE file3.cg\ne: f'
|
|
||||||
lexer.next().fileName.should.equal 'file1.cg'
|
|
||||||
lexer.next().fileName.should.equal 'file2.cg'
|
|
||||||
lexer.next().fileName.should.equal 'file3.cg'
|
|
||||||
|
|
||||||
describe 'line numbers are assigned correctly when', ->
|
|
||||||
|
|
||||||
it 'commands are listed one after another', ->
|
|
||||||
lexer = createLexer 'alpha: bravo\ncharlie: delta\necho: foxtrot'
|
|
||||||
lexer.next().lineNumber.should.equal 1
|
|
||||||
lexer.next().lineNumber.should.equal 2
|
|
||||||
lexer.next().lineNumber.should.equal 3
|
|
||||||
|
|
||||||
it 'commands are separated by blank lines and comments', ->
|
|
||||||
lexer = createLexer '# foo\n\nalpha: bravo\n\ncharlie: delta\n\n# bar\n\necho: foxtrot'
|
|
||||||
lexer.next().lineNumber.should.equal 3
|
|
||||||
lexer.next().lineNumber.should.equal 5
|
|
||||||
lexer.next().lineNumber.should.equal 9
|
|
||||||
|
|
||||||
it 'commands include hereDocs', ->
|
|
||||||
lexer = createLexer 'alpha: <<-END\nbravo charlie\nEND\ndelta: \n\necho: '
|
|
||||||
lexer.next().lineNumber.should.equal 1
|
|
||||||
lexer.next().lineNumber.should.equal 4
|
|
||||||
lexer.next().lineNumber.should.equal 6
|
|
||||||
|
|
||||||
it 'file markers are used', ->
|
|
||||||
lexer = createLexer '#FILE file1.cg\nalpha: \n#FILE file2.cg\n\nbravo: \n\n#FILE file3.cg\n\n\ncharlie: '
|
|
||||||
lexer.next().lineNumber.should.equal 1
|
|
||||||
lexer.next().lineNumber.should.equal 2
|
|
||||||
lexer.next().lineNumber.should.equal 3
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - parser.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
LexicalAnalyzer = require './lexical_analyzer'
|
|
||||||
ModPack = require '../game/mod_pack'
|
|
||||||
ParserData = require './parser_data'
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
module.exports = class Parser
|
|
||||||
|
|
||||||
constructor: (modPack, fileName, rawText)->
|
|
||||||
@_extensions = []
|
|
||||||
@_fileName = fileName
|
|
||||||
@_lexer = new LexicalAnalyzer fileName, rawText
|
|
||||||
@_modPack = new ModPack
|
|
||||||
@_data = new ParserData
|
|
||||||
|
|
||||||
modPackData = @_data.create {}, 'modPack'
|
|
||||||
modPackData.instance = @_modPack
|
|
||||||
|
|
||||||
@_loadSchema()
|
|
||||||
|
|
||||||
# Public Methods ###############################################################################
|
|
||||||
|
|
||||||
next: ->
|
|
||||||
if not @_lexer.isFinished
|
|
||||||
@_processNextCommand()
|
|
||||||
else if not @_data.isValidated
|
|
||||||
@_validateNextEntry()
|
|
||||||
else if not @_data.isBuilt
|
|
||||||
@_buildNextEntry()
|
|
||||||
else if not @_data.isAssembled
|
|
||||||
@_assembleNextEntry()
|
|
||||||
|
|
||||||
# Property Methods #############################################################################
|
|
||||||
|
|
||||||
getIsFinished: ->
|
|
||||||
return @_lexer.isFinished and @_data.isValidated and @_data.isBuilt and @_data.isAssembled
|
|
||||||
|
|
||||||
getData: ->
|
|
||||||
return @_data
|
|
||||||
|
|
||||||
getModPack: ->
|
|
||||||
return @_modPack
|
|
||||||
|
|
||||||
Object.defineProperties @prototype,
|
|
||||||
data: { get:@::getData }
|
|
||||||
isFinished: { get:@::getIsFinished }
|
|
||||||
modPack: { get:@::getModPack }
|
|
||||||
|
|
||||||
# Private Methods ##############################################################################
|
|
||||||
|
|
||||||
_assembleNextEntry: ->
|
|
||||||
entry = @_data.popNextToAssemble()
|
|
||||||
return unless entry?
|
|
||||||
|
|
||||||
for extensions in @_extensions
|
|
||||||
continue unless extension.canAssemble entry
|
|
||||||
extension.assemble entry
|
|
||||||
return
|
|
||||||
|
|
||||||
_buildNextEntry: ->
|
|
||||||
entry = @_data.popNextToBuild()
|
|
||||||
return unless entry?
|
|
||||||
|
|
||||||
for extensions in @_extensions
|
|
||||||
continue unless extension.canBuild entry
|
|
||||||
extension.build entry
|
|
||||||
return
|
|
||||||
|
|
||||||
_loadSchema: ->
|
|
||||||
command = @_lexer.next()
|
|
||||||
if command.name isnt 'schema' then throw new Error "#{@_fileName} must start with the \"schema\" command"
|
|
||||||
|
|
||||||
schema = command.argText
|
|
||||||
if schema is '1'
|
|
||||||
@_use new require './parser_extensions/current_pe_v1'
|
|
||||||
@_use new require './parser_extensions/item_pe_v1'
|
|
||||||
@_use new require './parser_extensions/mod_pe_v1'
|
|
||||||
@_use new require './parser_extensions/mod_version_pe_v1'
|
|
||||||
@_use new require './parser_extensions/recipe_pe_v1'
|
|
||||||
else
|
|
||||||
throw new Error "unknown schema version: #{schema}"
|
|
||||||
|
|
||||||
_processNextCommand: ->
|
|
||||||
command = @_lexer.next()
|
|
||||||
return unless command?
|
|
||||||
|
|
||||||
for extension in @_extensions
|
|
||||||
continue unless extension.canExecute command
|
|
||||||
extension.execute command
|
|
||||||
return
|
|
||||||
|
|
||||||
@_data.addError command, "unknown command: #{command.name}"
|
|
||||||
|
|
||||||
_use: (parserExtension)->
|
|
||||||
parserExtension.state = @_state
|
|
||||||
@_extensions.push parserExtension
|
|
||||||
|
|
||||||
_validateNextEntry: ->
|
|
||||||
entry = @_data.popNextToValidate()
|
|
||||||
return unless entry?
|
|
||||||
|
|
||||||
for extensions in @_extensions
|
|
||||||
continue unless extension.canValidate entry
|
|
||||||
extension.validate entry
|
|
||||||
return
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - parser_command.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
module.exports = class ParserCommand
|
|
||||||
|
|
||||||
constructor: (options={})->
|
|
||||||
if not options.name? then throw 'options.name is required'
|
|
||||||
if not options.fileName? then throw new 'options.fileName is required'
|
|
||||||
if not options.lineNumber? then throw 'options.lineNumber is required'
|
|
||||||
|
|
||||||
{@name, @fileName, @lineNumber, @argText, @args, @hereDoc} = options
|
|
||||||
|
|
||||||
# Property Methods #############################################################################
|
|
||||||
|
|
||||||
getLocation: ->
|
|
||||||
return "#{@fileName}:#{@lineNumber}"
|
|
||||||
|
|
||||||
Object.defineProperties @prototype,
|
|
||||||
location: { get:@::getLocation }
|
|
||||||
|
|
||||||
# Object Overrides #############################################################################
|
|
||||||
|
|
||||||
toString: ->
|
|
||||||
result = "#{@fileName}:#{@lineNumber} #{@name}: #{@argText}"
|
|
||||||
if @hereDoc?
|
|
||||||
result += " <<- END\n#{@hereDoc}\nEND"
|
|
||||||
return result
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - parser_data.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
module.exports = class ParserData
|
|
||||||
|
|
||||||
constructor: ->
|
|
||||||
@clear()
|
|
||||||
|
|
||||||
@_toAssemble = []
|
|
||||||
@_toBuild = []
|
|
||||||
@_toValidate = []
|
|
||||||
|
|
||||||
# Public Methods ###############################################################################
|
|
||||||
|
|
||||||
addError: (command, message)->
|
|
||||||
if not command? then throw new Error 'command is required'
|
|
||||||
message ?= 'is not valid'
|
|
||||||
@_errors.push command:command, message:message
|
|
||||||
|
|
||||||
create: (command, type, id=null)->
|
|
||||||
id ?= _.uniqueId "#{type}-"
|
|
||||||
|
|
||||||
@clearCurrent type
|
|
||||||
typeData = @_findOrCreateType type
|
|
||||||
itemData = @_current = typeData['current'] = typeData[id] = id:id, command:command, type:type
|
|
||||||
|
|
||||||
@_toAssemble.push itemData
|
|
||||||
@_toBuild.push itemData
|
|
||||||
@_toValidate.push itemData
|
|
||||||
|
|
||||||
return itemData
|
|
||||||
|
|
||||||
clear: ->
|
|
||||||
@_current = null
|
|
||||||
@_data =
|
|
||||||
mod: {}
|
|
||||||
modVersion: {}
|
|
||||||
tutorial: {}
|
|
||||||
itemGroup: {}
|
|
||||||
item: {}
|
|
||||||
multiblock: {}
|
|
||||||
recipe: {}
|
|
||||||
@_errors = []
|
|
||||||
|
|
||||||
clearCurrent: (type)->
|
|
||||||
switch type
|
|
||||||
when 'mod'
|
|
||||||
delete @_data.mod.current
|
|
||||||
delete @_data.modVersion.current
|
|
||||||
delete @_data.tutorial.current
|
|
||||||
delete @_data.itemGroup.current
|
|
||||||
delete @_data.item.current
|
|
||||||
delete @_data.multiblock.current
|
|
||||||
delete @_data.recipe.current
|
|
||||||
when 'modVersion'
|
|
||||||
delete @_data.modVersion.current
|
|
||||||
delete @_data.tutorial.current
|
|
||||||
delete @_data.itemGroup.current
|
|
||||||
delete @_data.item.current
|
|
||||||
delete @_data.multiblock.current
|
|
||||||
delete @_data.recipe.current
|
|
||||||
when 'tutorial'
|
|
||||||
delete @_data.tutorial.current
|
|
||||||
when 'itemGroup'
|
|
||||||
delete @_data.itemGroup.current
|
|
||||||
delete @_data.item.current
|
|
||||||
delete @_data.multiblock.current
|
|
||||||
delete @_data.recipe.current
|
|
||||||
when 'item'
|
|
||||||
delete @_data.item.current
|
|
||||||
delete @_data.multiblock.current
|
|
||||||
delete @_data.recipe.current
|
|
||||||
when 'multiblock'
|
|
||||||
delete @_data.multiblock.current
|
|
||||||
when 'recipe'
|
|
||||||
delete @_data.recipe.current
|
|
||||||
|
|
||||||
get: (type, id)->
|
|
||||||
typeData = @_findOrCreateType type
|
|
||||||
itemData = typeData[id] or null
|
|
||||||
return itemData
|
|
||||||
|
|
||||||
getCurrent: (type)->
|
|
||||||
return @_current unless type?
|
|
||||||
|
|
||||||
typeData = @_findOrCreateType type
|
|
||||||
current = typeData['current'] or null
|
|
||||||
return current
|
|
||||||
|
|
||||||
popNextToAssemble: ->
|
|
||||||
return @_toAssemble.pop() or null
|
|
||||||
|
|
||||||
popNextToBuild: ->
|
|
||||||
return @_toBuild.pop() or null
|
|
||||||
|
|
||||||
popNextToValidate: ->
|
|
||||||
return @_toValidate.pop() or null
|
|
||||||
|
|
||||||
# Property Methods #############################################################################
|
|
||||||
|
|
||||||
getErrors: ->
|
|
||||||
return @_errors[..]
|
|
||||||
|
|
||||||
getIsAssembled: ->
|
|
||||||
return @_toAssemble.length > 0
|
|
||||||
|
|
||||||
getIsBuilt: ->
|
|
||||||
return @_toBuild.length > 0
|
|
||||||
|
|
||||||
getIsValidated: ->
|
|
||||||
return @_toValidate.length > 0
|
|
||||||
|
|
||||||
Object.defineProperties @prototype,
|
|
||||||
errors: { get:@::getErrors }
|
|
||||||
isAssembled: { get:@::getIsAssembled }
|
|
||||||
isBuilt: { get:@::getIsBuilt }
|
|
||||||
isValidated: { get:@::getIsValidated }
|
|
||||||
|
|
||||||
|
|
||||||
# Private Methods ##############################################################################
|
|
||||||
|
|
||||||
_findOrCreateType: (type)->
|
|
||||||
typeData = @_data[type]
|
|
||||||
if not typeData?
|
|
||||||
typeData = @_data[type] = {}
|
|
||||||
typeData.type = type
|
|
||||||
|
|
||||||
return typeData
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - parser_data.test.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
ParserCommand = require './parser_command'
|
|
||||||
ParserData = require './parser_data'
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
command = state = null
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
describe 'parser_data.coffee', ->
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
state = new ParserData
|
|
||||||
command = new ParserCommand name:'alpha', fileName:'file.cg', lineNumber:1
|
|
||||||
|
|
||||||
describe 'create', ->
|
|
||||||
|
|
||||||
it 'returns an object with the given id', ->
|
|
||||||
alpha = state.create command, 'alpha', 0
|
|
||||||
alpha.id.should.equal 0
|
|
||||||
alpha.command.location.should.equal 'file.cg:1'
|
|
||||||
|
|
||||||
it 'returns an object with a newly created id when none is given', ->
|
|
||||||
alpha = state.create command, 'alpha'
|
|
||||||
alpha.id.should.not.be.null
|
|
||||||
alpha.id.should.match /^alpha-[0-9]+$/
|
|
||||||
alpha.command.location.should.equal 'file.cg:1'
|
|
||||||
|
|
||||||
describe 'get', ->
|
|
||||||
|
|
||||||
it 'returns a previously created item', ->
|
|
||||||
alpha1 = state.create command, 'alpha', 0
|
|
||||||
alpha2 = state.get 'alpha', 0
|
|
||||||
alpha1.should.equal alpha2
|
|
||||||
|
|
||||||
it 'returns null when no such item exists', ->
|
|
||||||
alpha = state.create command, 'alpha', 0
|
|
||||||
expect(state.get 'alpha', 1).to.be.null
|
|
||||||
expect(state.get 'bravo', 0).to.be.null
|
|
||||||
|
|
||||||
describe 'getCurrent', ->
|
|
||||||
|
|
||||||
it 'returns the new item each time one is created', ->
|
|
||||||
alpha1 = state.create command, 'alpha', 0
|
|
||||||
state.getCurrent('alpha').id.should.equal 0
|
|
||||||
|
|
||||||
alpha2 = state.create command, 'alpha', 1
|
|
||||||
state.getCurrent('alpha').id.should.equal 1
|
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - parser_extension.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
module.exports = class ParserExtension
|
|
||||||
|
|
||||||
constructor: (data, type, commandFunctions)->
|
|
||||||
@data = data
|
|
||||||
|
|
||||||
@_commandFunctions = commandFunctions or {}
|
|
||||||
@_type = type or null
|
|
||||||
|
|
||||||
# Public Methods ###############################################################################
|
|
||||||
|
|
||||||
canAssemble: (entry)->
|
|
||||||
return entry.type is @_type
|
|
||||||
|
|
||||||
canBuild: (entry)->
|
|
||||||
return entry.type is @_type
|
|
||||||
|
|
||||||
canExecute: (command)->
|
|
||||||
_.isFunction @_commandFunctions[command.name]
|
|
||||||
|
|
||||||
canValidate: (entry)->
|
|
||||||
return entry.type is @_type
|
|
||||||
|
|
||||||
execute: (command)->
|
|
||||||
if not @_data? then throw new Error '@data must be defined before executing commands'
|
|
||||||
|
|
||||||
func = @_commandFunctions[command.name]
|
|
||||||
if not func then throw new Error "#{@constructor.name} cannot handle command: #{command.name}"
|
|
||||||
|
|
||||||
func.call this, command
|
|
||||||
return this
|
|
||||||
|
|
||||||
# Error Checking Helpers #######################################################################
|
|
||||||
|
|
||||||
alreadyExists: (command, type, id)->
|
|
||||||
obj = @data.get(type, id)
|
|
||||||
if obj?
|
|
||||||
@data.addError command, "a #{type} called #{id} has already been declared"
|
|
||||||
return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
|
|
||||||
duplicateField: (command, obj, field)->
|
|
||||||
if obj[field]?
|
|
||||||
@data.addError command, "duplicate #{field}"
|
|
||||||
return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
|
|
||||||
incompatibleField: (command, obj, field, otherCommandName)->
|
|
||||||
otherCommandName ?= field
|
|
||||||
if obj[field]?
|
|
||||||
@data.addError "#{command.name} cannot be used with #{otherCommandName}"
|
|
||||||
return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
|
|
||||||
missingCurrent: (command, type)->
|
|
||||||
obj = @data.getCurrent type
|
|
||||||
if not obj?
|
|
||||||
@data.addError command, "you must declare a #{type} before using #{command.name}"
|
|
||||||
return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
|
|
||||||
missingArgs: (command)->
|
|
||||||
if not command.args or command.args.length is 0
|
|
||||||
@data.addError command, "#{command.name} requires at least one item"
|
|
||||||
return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
|
|
||||||
missingArgText: (command)->
|
|
||||||
if command.argText.length is 0
|
|
||||||
@data.addError command, "#{command.name} cannot be empty"
|
|
||||||
return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
|
|
||||||
invalidVerb: (command, verb)->
|
|
||||||
if not verb in ['mod', 'item']
|
|
||||||
@data.addError command, "#{command.name} only applies to either `mod` or `item`"
|
|
||||||
return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
|
|
||||||
tooFewArguments: (command, minimum)->
|
|
||||||
if command.args.length < minimum
|
|
||||||
@data.addError command, "#{command.name} requires at least #{minimum} arguments"
|
|
||||||
return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
|
|
||||||
# Parsing Helpers ##############################################################################
|
|
||||||
|
|
||||||
parseBoolean: (command, text)->
|
|
||||||
return null unless text?
|
|
||||||
|
|
||||||
switch text.toLowerCase()
|
|
||||||
when "yes" then return true
|
|
||||||
when "no" then return false
|
|
||||||
|
|
||||||
@data.addError command, "#{command.name} requires \"yes\" or \"no\""
|
|
||||||
return null
|
|
||||||
|
|
||||||
parseInt: (command, text)->
|
|
||||||
return null unless text?
|
|
||||||
|
|
||||||
value = Number.parseInt text
|
|
||||||
if isNaN value
|
|
||||||
@addError command, "#{command.name} requires a number"
|
|
||||||
return null
|
|
||||||
|
|
||||||
return value
|
|
||||||
|
|
||||||
# Property Methods #############################################################################
|
|
||||||
|
|
||||||
getData: ->
|
|
||||||
return @_data
|
|
||||||
|
|
||||||
setData: (data)->
|
|
||||||
if not data? then throw new Error 'data cannot be undefined'
|
|
||||||
@_data = data
|
|
||||||
|
|
||||||
Object.defineProperties @prototype,
|
|
||||||
data: { get:@::getData, set:@::setData }
|
|
||||||
|
|
||||||
# Overridable Methods ##########################################################################
|
|
||||||
|
|
||||||
assmeble: (entry)->
|
|
||||||
throw new Error "#{@constructor.name} must override the `assemble` method"
|
|
||||||
|
|
||||||
build: (entry)->
|
|
||||||
throw new Error "#{@constructor.name} must override the `build` method"
|
|
||||||
|
|
||||||
validate: (entry)->
|
|
||||||
throw new Error "#{@constructor.name} must override the `validate` method"
|
|
||||||
|
|
||||||
# Private Methods ##############################################################################
|
|
||||||
|
|
||||||
_findBuildMethod: (entry)->
|
|
||||||
methodName = "_build_#{entry.type}"
|
|
||||||
method = this[methodName]
|
|
||||||
return null unless _.isFunction method
|
|
||||||
return method
|
|
||||||
|
|
||||||
_findCommandMethod: (command)->
|
|
||||||
methodName = "_command_#{command.name}"
|
|
||||||
method = this[methodName]
|
|
||||||
return null unless _.isFunction method
|
|
||||||
return method
|
|
||||||
|
|
||||||
_findValidateMethod: (command)->
|
|
||||||
methodName = "_validate_#{command.name}"
|
|
||||||
method = this[methodName]
|
|
||||||
return null unless _.isFunction method
|
|
||||||
return method
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - current_pe_v1.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
ParserExtension = require '../parser_extension'
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
module.exports = class CurrentParserExtensionV1 extends ParserExtension
|
|
||||||
|
|
||||||
constructor: (data)->
|
|
||||||
super data, null,
|
|
||||||
description: @_command_description
|
|
||||||
name: @_command_name
|
|
||||||
officialUrl: @_command_officialUrl
|
|
||||||
video: @_command_video
|
|
||||||
|
|
||||||
# Command Methods ##############################################################################
|
|
||||||
|
|
||||||
_command_description: (command)->
|
|
||||||
current = @data.getCurrent()
|
|
||||||
return if @duplicateField command, current, 'description'
|
|
||||||
return if @missingArgText command
|
|
||||||
|
|
||||||
current.description = command.argText
|
|
||||||
|
|
||||||
_command_name: (command)->
|
|
||||||
current = @data.getCurrent()
|
|
||||||
return if @duplicateField command, current, 'name'
|
|
||||||
return if @missingArgText command
|
|
||||||
|
|
||||||
current.name = command.argText
|
|
||||||
|
|
||||||
_command_officialUrl: (command)->
|
|
||||||
current = @data.getCurrent()
|
|
||||||
return if @duplicateField command, current, 'officialUrl'
|
|
||||||
return if @missingArgText command
|
|
||||||
|
|
||||||
current.officialUrl = command.argText
|
|
||||||
|
|
||||||
_command_video: (command)->
|
|
||||||
current = @data.getCurrent()
|
|
||||||
return if @missingArgs command
|
|
||||||
return if @tooFewArguments command, 2
|
|
||||||
|
|
||||||
current.videos ?= []
|
|
||||||
current.videos.push youTubeId:command.args[0], caption:command.args[1..].join(', ')
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - current_pe_v1.test.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
CurrentParserExtensionV1 = require './current_pe_v1'
|
|
||||||
ParserData = require '../parser_data'
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
parser = state = null
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
describe 'current_pe_v1.coffee', ->
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
state = new ParserData
|
|
||||||
parser = new CurrentParserExtensionV1 state
|
|
||||||
|
|
||||||
state.create {}, 'alpha'
|
|
||||||
|
|
||||||
describe 'description', ->
|
|
||||||
|
|
||||||
it 'assigns to the current object', ->
|
|
||||||
parser.execute name:'description', argText:'bravo'
|
|
||||||
state.getCurrent().description.should.equal 'bravo'
|
|
||||||
state.errors.should.eql []
|
|
||||||
|
|
||||||
describe 'name', ->
|
|
||||||
|
|
||||||
it 'assigns to the current object', ->
|
|
||||||
parser.execute name:'name', argText:'bravo'
|
|
||||||
state.getCurrent().name.should.equal 'bravo'
|
|
||||||
state.errors.should.eql []
|
|
||||||
|
|
||||||
describe 'officialUrl', ->
|
|
||||||
|
|
||||||
it 'assigns to the current object', ->
|
|
||||||
parser.execute name:'officialUrl', argText:'bravo'
|
|
||||||
state.getCurrent().officialUrl.should.equal 'bravo'
|
|
||||||
state.errors.should.eql []
|
|
||||||
|
|
||||||
describe 'video', ->
|
|
||||||
|
|
||||||
it 'assigns to the current object', ->
|
|
||||||
parser.execute name:'video', args:['alpha', 'bravo']
|
|
||||||
videos = state.getCurrent().videos
|
|
||||||
videos[0].youTubeId.should.equal 'alpha'
|
|
||||||
videos[0].caption.should.equal 'bravo'
|
|
||||||
state.errors.should.eql []
|
|
||||||
|
|
||||||
it 'can assign multiple videos', ->
|
|
||||||
parser.execute name:'video', args:['alpha', 'bravo']
|
|
||||||
parser.execute name:'video', args:['charlie', 'delta']
|
|
||||||
state.getCurrent().videos.length.should.equal 2
|
|
||||||
state.errors.should.eql []
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - item_pe_v1.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
ParserExtension = require '../parser_extension'
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
module.exports = class ItemParserExtensionV1 extends ParserExtension
|
|
||||||
|
|
||||||
constructor: (data)->
|
|
||||||
super data, 'item',
|
|
||||||
gatherable: @_command_gatherable
|
|
||||||
item: @_command_item
|
|
||||||
update: @_command_update
|
|
||||||
|
|
||||||
# ParserExtensions Overrides ###################################################################
|
|
||||||
|
|
||||||
assmeble: (entry)->
|
|
||||||
throw new Error "#{@constructor.name} must override the `assemble` method"
|
|
||||||
|
|
||||||
build: (entry)->
|
|
||||||
entry.instance = new
|
|
||||||
throw new Error "#{@constructor.name} must override the `build` method"
|
|
||||||
|
|
||||||
validate: (entry)-> # do nothing
|
|
||||||
|
|
||||||
# Command Methods ##############################################################################
|
|
||||||
|
|
||||||
_command_gatherable: (command)->
|
|
||||||
return if @missingArgText command
|
|
||||||
return if @missingCurrent command, 'item'
|
|
||||||
|
|
||||||
item = @data.getCurrent 'item'
|
|
||||||
return if @duplicateField command, item, 'gatherable'
|
|
||||||
|
|
||||||
gatherable = @parseBoolean command, command.argText
|
|
||||||
return unless gatherable?
|
|
||||||
|
|
||||||
item.gatherable = gatherable
|
|
||||||
|
|
||||||
_command_item: (command)->
|
|
||||||
return if @missingArgText command
|
|
||||||
return if @missingCurrent command, 'modVersion'
|
|
||||||
return if @alreadyExists command, 'item', command.argText
|
|
||||||
|
|
||||||
item = @data.create command, 'item', command.argText
|
|
||||||
item.name = command.argText
|
|
||||||
item.isUpdate = false
|
|
||||||
|
|
||||||
group = @data.getCurrent 'itemGroup'
|
|
||||||
if group? then item.group = group
|
|
||||||
|
|
||||||
item.modVersion = @data.getCurrent 'modVersion'
|
|
||||||
|
|
||||||
_command_update: (command)->
|
|
||||||
return if @missingArgText command
|
|
||||||
return if @missingCurrent command, 'modVersion'
|
|
||||||
return if @alreadyExists command, 'item', command.argText
|
|
||||||
|
|
||||||
item = @data.create command, 'item', command.argText
|
|
||||||
item.name = command.argText
|
|
||||||
item.isUpdate = true
|
|
||||||
item.modVersion = @data.getCurrent 'modVersion'
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - item_pe_v1.test.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
ItemParserExtensionV1 = require './item_pe_v1'
|
|
||||||
ParserData = require '../parser_data'
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
parser = data = null
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
describe 'item_pe_v1.coffee', ->
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
data = new ParserData
|
|
||||||
parser = new ItemParserExtensionV1 data
|
|
||||||
|
|
||||||
data.create {}, 'modVersion', 0
|
|
||||||
|
|
||||||
describe 'gatherable', ->
|
|
||||||
|
|
||||||
it 'assigns to the current item', ->
|
|
||||||
data.create {}, 'item', 1
|
|
||||||
|
|
||||||
parser.execute name:'gatherable', argText:'yes'
|
|
||||||
data.getCurrent('item').gatherable.should.be.true
|
|
||||||
data.errors.should.eql []
|
|
||||||
|
|
||||||
describe 'item', ->
|
|
||||||
|
|
||||||
it 'creates a new item', ->
|
|
||||||
data.create {}, 'itemGroup', 2
|
|
||||||
|
|
||||||
parser.execute name:'item', argText:'alpha'
|
|
||||||
item = data.getCurrent 'item'
|
|
||||||
item.id.should.equal 'alpha'
|
|
||||||
item.isUpdate.should.equal false
|
|
||||||
item.name.should.equal 'alpha'
|
|
||||||
item.modVersion.id.should.equal 0
|
|
||||||
item.group.id.should.equal 2
|
|
||||||
data.getErrors().should.eql []
|
|
||||||
|
|
||||||
describe 'update', ->
|
|
||||||
|
|
||||||
it 'creates an item update', ->
|
|
||||||
parser.execute name:'update', argText:'alpha'
|
|
||||||
item = data.getCurrent 'item'
|
|
||||||
item.isUpdate.should.equal true
|
|
||||||
data.getErrors().should.eql []
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - mod_pe_v1.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
ParserExtension = require '../parser_extension'
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
module.exports = class ModParserExtensionV1 extends ParserExtension
|
|
||||||
|
|
||||||
constructor: (data)->
|
|
||||||
super data, 'mod',
|
|
||||||
author: @_command_author
|
|
||||||
documentationUrl: @_command_documentationUrl
|
|
||||||
downloadUrl: @_command_downloadUrl
|
|
||||||
homePageUrl: @_command_homePageUrl
|
|
||||||
mod: @_command_mod
|
|
||||||
|
|
||||||
# Command Methods ##############################################################################
|
|
||||||
|
|
||||||
_command_author: (command)->
|
|
||||||
return if @missingCurrent command, 'mod'
|
|
||||||
|
|
||||||
mod = @data.getCurrent 'mod'
|
|
||||||
return if @duplicateField command, mod, 'author'
|
|
||||||
return if @missingArgText command
|
|
||||||
|
|
||||||
mod.author = command.argText
|
|
||||||
|
|
||||||
_command_documentationUrl: (command)->
|
|
||||||
current = @data.getCurrent()
|
|
||||||
return if @duplicateField command, current, 'documentationUrl'
|
|
||||||
return if @missingArgText command
|
|
||||||
|
|
||||||
current.documentationUrl = command.argText
|
|
||||||
|
|
||||||
_command_downloadUrl: (command)->
|
|
||||||
return if @missingCurrent command, 'mod'
|
|
||||||
|
|
||||||
mod = @data.getCurrent 'mod'
|
|
||||||
return if @duplicateField command, mod, 'downloadUrl'
|
|
||||||
return if @missingArgText command
|
|
||||||
|
|
||||||
mod.downloadUrl = command.argText
|
|
||||||
|
|
||||||
_command_homePageUrl: (command)->
|
|
||||||
return if @missingCurrent command, 'mod'
|
|
||||||
|
|
||||||
mod = @data.getCurrent 'mod'
|
|
||||||
return if @duplicateField command, mod, 'homePageUrl'
|
|
||||||
return if @missingArgText command
|
|
||||||
|
|
||||||
mod.homePageUrl = command.argText
|
|
||||||
|
|
||||||
_command_mod: (command)->
|
|
||||||
return if @missingArgText command
|
|
||||||
return if @alreadyExists command, 'mod', command.argText
|
|
||||||
|
|
||||||
@data.create command, 'mod', command.argText
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - mod_pe_v1.test.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
ModParserExtensionV1 = require './mod_pe_v1'
|
|
||||||
ParserData = require '../parser_data'
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
parser = data = null
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
describe 'mod_pe_v1.coffee', ->
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
data = new ParserData
|
|
||||||
parser = new ModParserExtensionV1 data
|
|
||||||
|
|
||||||
data.create {}, 'mod', 0
|
|
||||||
|
|
||||||
describe 'author', ->
|
|
||||||
|
|
||||||
it 'assigns to the current mod', ->
|
|
||||||
parser.execute name:'author', argText:'alpha'
|
|
||||||
data.getCurrent('mod').author.should.equal 'alpha'
|
|
||||||
data.errors.should.eql []
|
|
||||||
|
|
||||||
describe 'documentationUrl', ->
|
|
||||||
|
|
||||||
it 'assigns to the current mod', ->
|
|
||||||
parser.execute name:'documentationUrl', argText:'alpha'
|
|
||||||
data.getCurrent('mod').documentationUrl.should.equal 'alpha'
|
|
||||||
data.errors.should.eql []
|
|
||||||
|
|
||||||
describe 'downloadUrl', ->
|
|
||||||
|
|
||||||
it 'assigns to the current mod', ->
|
|
||||||
parser.execute name:'downloadUrl', argText:'alpha'
|
|
||||||
data.getCurrent('mod').downloadUrl.should.equal 'alpha'
|
|
||||||
data.errors.should.eql []
|
|
||||||
|
|
||||||
describe 'homePageUrl', ->
|
|
||||||
|
|
||||||
it 'assigns to the current mod', ->
|
|
||||||
parser.execute name:'homePageUrl', argText:'alpha'
|
|
||||||
data.getCurrent('mod').homePageUrl.should.equal 'alpha'
|
|
||||||
data.errors.should.eql []
|
|
||||||
|
|
||||||
describe 'mod', ->
|
|
||||||
|
|
||||||
it 'creates a new mod', ->
|
|
||||||
parser.execute name:'mod', argText:'alpha'
|
|
||||||
mod = data.getCurrent 'mod'
|
|
||||||
mod.id.should.equal 'alpha'
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - mod_version_pe_v1.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
ParserExtension = require '../parser_extension'
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
module.exports = class ModVersionParserExtensionV1 extends ParserExtension
|
|
||||||
|
|
||||||
constructor: (data)->
|
|
||||||
super data, 'modVersion',
|
|
||||||
group: @_command_group
|
|
||||||
version: @_command_version
|
|
||||||
|
|
||||||
# Command Methods ##############################################################################
|
|
||||||
|
|
||||||
_command_group: (command)->
|
|
||||||
return if @missingArgText command
|
|
||||||
return if @missingCurrent command, 'modVersion'
|
|
||||||
|
|
||||||
group = @data.create command, 'itemGroup', command.argText
|
|
||||||
group.modVersion = @data.getCurrent 'modVersion'
|
|
||||||
|
|
||||||
_command_version: (command)->
|
|
||||||
return if @missingArgText command
|
|
||||||
return if @missingCurrent command, 'mod'
|
|
||||||
|
|
||||||
modVersion = @data.create command, 'modVersion', command.argText
|
|
||||||
modVersion.mod = @data.getCurrent 'mod'
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - mod_version_pe_v1.test.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
ModVersionParserExtensionV1 = require './mod_version_pe_v1'
|
|
||||||
ParserData = require '../parser_data'
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
parser = data = null
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
describe 'mod_version_pe_v1.coffee', ->
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
data = new ParserData
|
|
||||||
parser = new ModVersionParserExtensionV1 data
|
|
||||||
|
|
||||||
data.create {}, 'mod', 0
|
|
||||||
|
|
||||||
describe 'group', ->
|
|
||||||
|
|
||||||
it 'creates a new item group', ->
|
|
||||||
data.create {}, 'modVersion', 1
|
|
||||||
|
|
||||||
parser.execute name:'group', argText:'alpha'
|
|
||||||
itemGroup = data.getCurrent('itemGroup')
|
|
||||||
itemGroup.id.should.equal 'alpha'
|
|
||||||
itemGroup.modVersion.id.should.equal 1
|
|
||||||
|
|
||||||
describe 'version', ->
|
|
||||||
|
|
||||||
it 'creates a new mod version', ->
|
|
||||||
parser.execute name:'version', argText:'alpha'
|
|
||||||
modVersion = data.getCurrent 'modVersion'
|
|
||||||
modVersion.id.should.equal 'alpha'
|
|
||||||
modVersion.mod.id.should.equal 0
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - multiblock_pe_v1.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
ParserExtension = require '../parser_extension'
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
module.exports = class MultiblockParserExtensionV1 extends ParserExtension
|
|
||||||
|
|
||||||
constructor: (data)->
|
|
||||||
super data, 'multiblock',
|
|
||||||
layer: @_command_layer
|
|
||||||
multiblock: @_command_multiblock
|
|
||||||
|
|
||||||
# Command Methods ##############################################################################
|
|
||||||
|
|
||||||
_command_layer: (command)->
|
|
||||||
return if @missingCurrent command, 'multiblock'
|
|
||||||
return if @missingArgText command
|
|
||||||
|
|
||||||
multiblock = @data.getCurrent 'multiblock'
|
|
||||||
multiblock.layers ?= []
|
|
||||||
multiblock.layers.push command.argText
|
|
||||||
|
|
||||||
_command_multiblock: (command)->
|
|
||||||
return if @missingCurrent command, 'item'
|
|
||||||
|
|
||||||
item = @data.getCurrent 'item'
|
|
||||||
return if @duplicateField command, item, 'multiblock'
|
|
||||||
return if @incompatibleField command, item, 'recipe'
|
|
||||||
return if @incompatibleField command, item, 'gatherable'
|
|
||||||
|
|
||||||
multiblock = @data.create command, 'multiblock'
|
|
||||||
multiblock.item = item
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - multiblock_pe_v1.test.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
MultiblockParserExtensionV1 = require './multiblock_pe_v1'
|
|
||||||
ParserData = require '../parser_data'
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
parser = data = null
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
describe 'multiblock_pe_v1.coffee', ->
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
data = new ParserData
|
|
||||||
parser = new MultiblockParserExtensionV1 data
|
|
||||||
|
|
||||||
data.create {}, 'item', 1
|
|
||||||
|
|
||||||
describe 'layer', ->
|
|
||||||
|
|
||||||
it 'creates a new layer in the current multiblock', ->
|
|
||||||
data.create {}, 'multiblock', 2
|
|
||||||
|
|
||||||
parser.execute name:'layer', argText:'alpha'
|
|
||||||
multiblock = data.getCurrent 'multiblock'
|
|
||||||
multiblock.layers.length.should.equal 1
|
|
||||||
multiblock.layers[0].should.equal 'alpha'
|
|
||||||
|
|
||||||
it 'can create multiple layers', ->
|
|
||||||
data.create {}, 'multiblock', 2
|
|
||||||
|
|
||||||
parser.execute name:'layer', argText:'alpha'
|
|
||||||
parser.execute name:'layer', argText:'bravo'
|
|
||||||
multiblock = data.getCurrent 'multiblock'
|
|
||||||
multiblock.layers.should.eql ['alpha', 'bravo']
|
|
||||||
|
|
||||||
describe 'multiblock', ->
|
|
||||||
|
|
||||||
it 'creates a new multiblock', ->
|
|
||||||
parser.execute name:'multiblock'
|
|
||||||
multiblock = data.getCurrent 'multiblock'
|
|
||||||
multiblock.item.id.should.equal 1
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - recipe_pe_v1.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
ParserExtension = require '../parser_extension'
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
module.exports = class RecipeParserExtensionV1 extends ParserExtension
|
|
||||||
|
|
||||||
constructor: (data)->
|
|
||||||
super data, 'recipe',
|
|
||||||
extras: @_command_extras
|
|
||||||
ignoreDuringCrafting: @_command_ignoreDuringCrafting
|
|
||||||
input: @_command_input
|
|
||||||
onlyIf: @_command_onlyIf
|
|
||||||
pattern: @_command_pattern
|
|
||||||
recipe: @_command_recipe
|
|
||||||
quantity: @_command_quantity
|
|
||||||
tools: @_command_tools
|
|
||||||
|
|
||||||
# Class Methods ################################################################################
|
|
||||||
|
|
||||||
@::PATTERN = /[0-9. ]+/
|
|
||||||
|
|
||||||
@::STACK = /^([0-9]+) +(.+)$/
|
|
||||||
|
|
||||||
# Error Checking Helpers #######################################################################
|
|
||||||
|
|
||||||
invalidPattern: (command)->
|
|
||||||
match = command.argText.match @PATTERN
|
|
||||||
if not match?
|
|
||||||
@data.addError command, "invalid pattern: \"#{command.argText}\""
|
|
||||||
return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
|
|
||||||
# Command Methods ##############################################################################
|
|
||||||
|
|
||||||
_command_extras: (command)->
|
|
||||||
return if @missingCurrent command, 'recipe'
|
|
||||||
return if @missingArgs command
|
|
||||||
|
|
||||||
recipe = @data.getCurrent 'recipe'
|
|
||||||
return if @duplicateField command, 'extras', recipe
|
|
||||||
|
|
||||||
recipe.extras = command.args
|
|
||||||
|
|
||||||
_command_ignoreDuringCrafting: (command)->
|
|
||||||
return if @missingArgText command
|
|
||||||
return if @missingCurrent command, 'recipe'
|
|
||||||
|
|
||||||
recipe = @data.getCurrent 'recipe'
|
|
||||||
return if @duplicateField command, recipe, 'ignoreDuringCrafting'
|
|
||||||
|
|
||||||
ignoreDuringCrafting = @parseBoolean command, command.argText
|
|
||||||
return unless ignoreDuringCrafting?
|
|
||||||
|
|
||||||
recipe.ignoreDuringCrafting = ignoreDuringCrafting
|
|
||||||
|
|
||||||
_command_input: (command)->
|
|
||||||
return if @missingCurrent command, 'recipe'
|
|
||||||
return if @missingArgs command
|
|
||||||
|
|
||||||
recipe = @data.getCurrent 'recipe'
|
|
||||||
multiblock = @data.getCurrent 'multiblock'
|
|
||||||
|
|
||||||
target = if multiblock? then multiblock else recipe
|
|
||||||
|
|
||||||
return if @duplicateField command, 'input', target
|
|
||||||
target.input = (@_parseStack(arg) for arg in command.args)
|
|
||||||
|
|
||||||
_command_onlyIf: (command)->
|
|
||||||
return if @missingCurrent command, 'recipe'
|
|
||||||
return if @missingArgText command
|
|
||||||
|
|
||||||
recipe = @data.getCurrent 'recipe'
|
|
||||||
return if @duplicateField command, recipe, 'condition'
|
|
||||||
|
|
||||||
words = command.argText.split ' '
|
|
||||||
inverted = false
|
|
||||||
if words[0] is 'not'
|
|
||||||
inverted = true
|
|
||||||
words.shift()
|
|
||||||
|
|
||||||
verb = words[0]
|
|
||||||
noun = words[1..].join ' '
|
|
||||||
|
|
||||||
return if @invalidVerb command, verb
|
|
||||||
recipe.condition = verb:verb, noun:noun, inverted:inverted
|
|
||||||
|
|
||||||
_command_pattern: (command)->
|
|
||||||
return if @missingCurrent command, 'recipe'
|
|
||||||
return if @missingArgText command
|
|
||||||
return if @invalidPattern command
|
|
||||||
|
|
||||||
recipe = @data.getCurrent 'recipe'
|
|
||||||
return if @duplicateField command, 'pattern', recipe
|
|
||||||
|
|
||||||
recipe.pattern = command.argText
|
|
||||||
|
|
||||||
_command_quantity: (command)->
|
|
||||||
return if @missingCurrent command, 'recipe'
|
|
||||||
return if @missingArgText command
|
|
||||||
|
|
||||||
value = @parseInt command, command.argText
|
|
||||||
return unless value?
|
|
||||||
|
|
||||||
recipe = @data.getCurrent 'recipe'
|
|
||||||
return if @duplicateField command, 'quantity', recipe
|
|
||||||
|
|
||||||
recipe.quantity = value
|
|
||||||
|
|
||||||
_command_recipe: (command)->
|
|
||||||
return if @missingCurrent command, 'item'
|
|
||||||
|
|
||||||
recipe = @data.create command, 'recipe'
|
|
||||||
recipe.item = @data.getCurrent 'item'
|
|
||||||
|
|
||||||
_command_tools: (command)->
|
|
||||||
return if @missingCurrent command, 'recipe'
|
|
||||||
return if @missingArgs command
|
|
||||||
|
|
||||||
recipe = @data.getCurrent 'recipe'
|
|
||||||
return if @duplicateField command, 'tools', recipe
|
|
||||||
|
|
||||||
recipe.tools = (@_parseStack(arg) for arg in command.args)
|
|
||||||
|
|
||||||
# Custom Parsers ###############################################################################
|
|
||||||
|
|
||||||
_parseStack: (text)->
|
|
||||||
match = text.match @STACK
|
|
||||||
return name:text, quantity:1 unless match?
|
|
||||||
|
|
||||||
quantity = parseFloat match[1]
|
|
||||||
if isNaN quantity then quantity = 1
|
|
||||||
|
|
||||||
name = match[2]
|
|
||||||
|
|
||||||
return name:name, quantity:quantity
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - recipe_pe_v1.test.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
RecipeParserExtensionV1 = require './recipe_pe_v1'
|
|
||||||
ParserData = require '../parser_data'
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
parser = data = null
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
describe 'recipe_pe_v1.coffee', ->
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
data = new ParserData
|
|
||||||
parser = new RecipeParserExtensionV1 data
|
|
||||||
|
|
||||||
data.create {}, 'item', 0
|
|
||||||
|
|
||||||
describe 'extras', ->
|
|
||||||
|
|
||||||
it 'assigns to the current recipe', ->
|
|
||||||
data.create {}, 'recipe'
|
|
||||||
|
|
||||||
parser.execute name:'extras', args:['bravo']
|
|
||||||
recipe = data.getCurrent 'recipe'
|
|
||||||
recipe.extras.should.eql ['bravo']
|
|
||||||
data.errors.should.eql []
|
|
||||||
|
|
||||||
describe 'ignoreDuringCrafting', ->
|
|
||||||
|
|
||||||
it 'assigns to the current recipe', ->
|
|
||||||
data.create {}, 'recipe'
|
|
||||||
|
|
||||||
parser.execute name:'ignoreDuringCrafting', argText:'yes'
|
|
||||||
recipe = data.getCurrent 'recipe'
|
|
||||||
recipe.ignoreDuringCrafting.should.equal true
|
|
||||||
data.errors.should.eql []
|
|
||||||
|
|
||||||
describe 'input', ->
|
|
||||||
|
|
||||||
it 'correctly reads a single item', ->
|
|
||||||
data.create {}, 'recipe'
|
|
||||||
|
|
||||||
parser.execute name:'input', args:['bravo']
|
|
||||||
recipe = data.getCurrent 'recipe'
|
|
||||||
recipe.input.should.eql [name:'bravo', quantity:1]
|
|
||||||
data.errors.should.eql []
|
|
||||||
|
|
||||||
it 'correctly reads multiple items', ->
|
|
||||||
data.create {}, 'recipe'
|
|
||||||
|
|
||||||
parser.execute name:'input', args:['bravo', 'charlie']
|
|
||||||
recipe = data.getCurrent 'recipe'
|
|
||||||
recipe.input.should.eql [{name:'bravo', quantity:1}, {name:'charlie', quantity:1}]
|
|
||||||
data.errors.should.eql []
|
|
||||||
|
|
||||||
it 'correctly reads a stack', ->
|
|
||||||
data.create {}, 'recipe'
|
|
||||||
|
|
||||||
parser.execute name:'input', args:['10 bravo']
|
|
||||||
recipe = data.getCurrent 'recipe'
|
|
||||||
recipe.input.should.eql [name:'bravo', quantity:10]
|
|
||||||
data.errors.should.eql []
|
|
||||||
|
|
||||||
describe 'onlyIf', ->
|
|
||||||
|
|
||||||
it 'assigns to the current recipe', ->
|
|
||||||
data.create {}, 'recipe'
|
|
||||||
|
|
||||||
parser.execute name:'onlyIf', argText:'not mod Alpha'
|
|
||||||
recipe = data.getCurrent 'recipe'
|
|
||||||
recipe.condition.should.eql verb:'mod', noun:'Alpha', inverted:true
|
|
||||||
data.errors.should.eql []
|
|
||||||
|
|
||||||
describe 'pattern', ->
|
|
||||||
|
|
||||||
it 'assigns to the current recipe', ->
|
|
||||||
data.create {}, 'recipe'
|
|
||||||
|
|
||||||
parser.execute name:'pattern', argText:'00. 00. ...'
|
|
||||||
recipe = data.getCurrent 'recipe'
|
|
||||||
recipe.pattern.should.equal '00. 00. ...'
|
|
||||||
data.errors.should.eql []
|
|
||||||
|
|
||||||
it 'rejects an invalid pattern', ->
|
|
||||||
data.create {}, 'recipe'
|
|
||||||
|
|
||||||
parser.execute name:'pattern', argText:'alpha'
|
|
||||||
recipe = data.getCurrent 'recipe'
|
|
||||||
expect(recipe.pattern).to.be.undefined
|
|
||||||
(e.message for e in data.errors).should.eql ['invalid pattern: "alpha"']
|
|
||||||
|
|
||||||
describe 'quantity', ->
|
|
||||||
|
|
||||||
it 'assigns to the current recipe', ->
|
|
||||||
data.create {}, 'recipe'
|
|
||||||
|
|
||||||
parser.execute name:'quantity', argText:'42'
|
|
||||||
recipe = data.getCurrent 'recipe'
|
|
||||||
recipe.quantity.should.equal 42
|
|
||||||
data.errors.should.eql []
|
|
||||||
|
|
||||||
describe 'recipe', ->
|
|
||||||
|
|
||||||
it 'creates a new recipe', ->
|
|
||||||
parser.execute name:'recipe'
|
|
||||||
recipe = data.getCurrent 'recipe'
|
|
||||||
recipe.item.id.should.equal 0
|
|
||||||
data.errors.should.eql []
|
|
||||||
|
|
||||||
describe 'tools', ->
|
|
||||||
|
|
||||||
it 'assigns to the current recipe', ->
|
|
||||||
data.create {}, 'recipe'
|
|
||||||
|
|
||||||
parser.execute name:'tools', args:['bravo']
|
|
||||||
recipe = data.getCurrent 'recipe'
|
|
||||||
recipe.tools.should.eql [name:'bravo', quantity:1]
|
|
||||||
data.errors.should.eql []
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - tutorial_pe_v1.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
ParserExtension = require '../parser_extension'
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
module.exports = class TutorialParserExtensionV1 extends ParserExtension
|
|
||||||
|
|
||||||
constructor: (data)->
|
|
||||||
super data, 'tutorial',
|
|
||||||
content: @_command_content
|
|
||||||
section: @_command_section
|
|
||||||
title: @_command_title
|
|
||||||
tutorial: @_command_tutorial
|
|
||||||
|
|
||||||
# Command Methods ##############################################################################
|
|
||||||
|
|
||||||
_command_content: (command)->
|
|
||||||
return if @missingCurrent command, 'tutorial'
|
|
||||||
return if @missingArgText command
|
|
||||||
|
|
||||||
section = @data.getCurrent 'section'
|
|
||||||
section.content = command.argText
|
|
||||||
|
|
||||||
_command_section: (command)->
|
|
||||||
return if @missingCurrent command, 'tutorial'
|
|
||||||
|
|
||||||
section = @data.create command, 'section'
|
|
||||||
section.tutorial = @data.getCurrent 'tutorial'
|
|
||||||
|
|
||||||
_command_title: (command)->
|
|
||||||
return if @missingCurrent command, 'section'
|
|
||||||
return if @missingArgText command
|
|
||||||
|
|
||||||
section = @data.getCurrent 'section'
|
|
||||||
return if @duplicateField command, section, 'title'
|
|
||||||
|
|
||||||
section.title = command.argText
|
|
||||||
|
|
||||||
_command_tutorial: (command)->
|
|
||||||
return if @missingCurrent command, 'modVersion'
|
|
||||||
return if @missingArgText command
|
|
||||||
|
|
||||||
tutorial = @data.create command, 'tutorial', command.argText
|
|
||||||
tutorial.name = command.argText
|
|
||||||
tutorial.modVersion = @data.getCurrent 'modVersion'
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - tutorial_pe_v1.test.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
TutorialParserExtensionV1 = require './tutorial_pe_v1'
|
|
||||||
ParserData = require '../parser_data'
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
parser = data = null
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
describe 'tutorial_pe_v1.coffee', ->
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
data = new ParserData
|
|
||||||
parser = new TutorialParserExtensionV1 data
|
|
||||||
|
|
||||||
data.create {}, 'modVersion', 1
|
|
||||||
|
|
||||||
describe 'content', ->
|
|
||||||
|
|
||||||
it 'assigns content to the current section', ->
|
|
||||||
data.create {}, 'tutorial', 2
|
|
||||||
data.create {}, 'section', 3
|
|
||||||
|
|
||||||
parser.execute name:'content', argText:'alpha'
|
|
||||||
data.errors.should.eql []
|
|
||||||
section = data.getCurrent 'section'
|
|
||||||
section.content.should.equal 'alpha'
|
|
||||||
|
|
||||||
describe 'section', ->
|
|
||||||
|
|
||||||
it 'creates a section in the current tutorial', ->
|
|
||||||
data.create {}, 'tutorial', 2
|
|
||||||
|
|
||||||
parser.execute name:'section'
|
|
||||||
data.errors.should.eql []
|
|
||||||
section = data.getCurrent 'section'
|
|
||||||
section.tutorial.id.should.equal 2
|
|
||||||
|
|
||||||
describe 'title', ->
|
|
||||||
|
|
||||||
it 'assigns a title to the current tutorial', ->
|
|
||||||
data.create {}, 'tutorial', 2
|
|
||||||
data.create {}, 'section', 3
|
|
||||||
|
|
||||||
parser.execute name:'title', argText:'alpha'
|
|
||||||
data.errors.should.eql []
|
|
||||||
section = data.getCurrent 'section'
|
|
||||||
section.title.should.equal 'alpha'
|
|
||||||
|
|
||||||
describe 'tutorial', ->
|
|
||||||
|
|
||||||
it 'creates a new tutorial', ->
|
|
||||||
parser.execute name:'tutorial', argText:'alpha'
|
|
||||||
data.errors.should.eql []
|
|
||||||
tutorial = data.getCurrent 'tutorial'
|
|
||||||
tutorial.name.should.equal 'alpha'
|
|
||||||
@@ -40,6 +40,7 @@ module.exports = class CraftPage extends BaseModel
|
|||||||
inventory.each (stack)=>
|
inventory.each (stack)=>
|
||||||
item = @modPack.findItem stack.itemSlug, enableAsNeeded:true
|
item = @modPack.findItem stack.itemSlug, enableAsNeeded:true
|
||||||
return unless item? and item.isCraftable
|
return unless item? and item.isCraftable
|
||||||
|
|
||||||
@craftsman.want.add stack.itemSlug, stack.quantity
|
@craftsman.want.add stack.itemSlug, stack.quantity
|
||||||
inventory.remove stack.itemSlug
|
inventory.remove stack.itemSlug
|
||||||
|
|
||||||
|
|||||||
@@ -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'
|
||||||
@@ -47,6 +47,7 @@ module.exports = class ItemPage extends BaseModel
|
|||||||
mod.eachRecipe (recipe)=>
|
mod.eachRecipe (recipe)=>
|
||||||
if isAcceptable recipe
|
if isAcceptable recipe
|
||||||
for outputStack in recipe.output
|
for outputStack in recipe.output
|
||||||
|
continue if recipe.isPassThroughFor outputStack.itemSlug
|
||||||
outputItem = @modPack.findItem outputStack.itemSlug, includeDisabled:true
|
outputItem = @modPack.findItem outputStack.itemSlug, includeDisabled:true
|
||||||
result[outputItem.slug] = outputItem
|
result[outputItem.slug] = outputItem
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
.content.view__browse_page
|
.content.view__browse_page
|
||||||
.left
|
.left
|
||||||
.view__adsense
|
|
||||||
|
|
||||||
.right
|
.right
|
||||||
.tile_container
|
.tile_container
|
||||||
@@ -10,14 +10,32 @@
|
|||||||
|
|
||||||
.right {
|
.right {
|
||||||
.tile_container {
|
.tile_container {
|
||||||
display : flex;
|
display : flex;
|
||||||
flex-wrap : wrap;
|
flex-wrap : wrap;
|
||||||
justify-content : space-between;
|
|
||||||
|
|
||||||
.view__mod_tile {
|
.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;
|
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.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
|
|
||||||
AdsenseController = require '../common/adsense/adsense_controller'
|
|
||||||
ModTileController = require './mod_tile/mod_tile_controller'
|
ModTileController = require './mod_tile/mod_tile_controller'
|
||||||
PageController = require '../page_controller'
|
PageController = require '../page_controller'
|
||||||
|
|
||||||
@@ -32,8 +31,6 @@ module.exports = class BrowsePageController extends PageController
|
|||||||
# BaseController Overrides #####################################################################
|
# BaseController Overrides #####################################################################
|
||||||
|
|
||||||
onDidRender: ->
|
onDidRender: ->
|
||||||
@_adsenseController = @addChild AdsenseController, '.view__adsense', model:'skyscraper'
|
|
||||||
|
|
||||||
@$tileContainer = @$('.tile_container')
|
@$tileContainer = @$('.tile_container')
|
||||||
|
|
||||||
refresh: ->
|
refresh: ->
|
||||||
|
|||||||
@@ -6,16 +6,14 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
.view__mod_tile {
|
.view__mod_tile {
|
||||||
min-width : $size-minecraft-block * 9;
|
min-width : $size-minecraft-block * 9;
|
||||||
|
|
||||||
display : flex;
|
display: flex;
|
||||||
justify-content : stretch;
|
|
||||||
align-items : stretch;
|
|
||||||
|
|
||||||
a {
|
a {
|
||||||
max-width: 100%;
|
|
||||||
|
|
||||||
@include floating-panel;
|
@include floating-panel;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
|
||||||
border : $size-border-medium solid $color-background-panel;
|
border : $size-border-medium solid $color-background-panel;
|
||||||
color : $color-text;
|
color : $color-text;
|
||||||
text-decoration : none;
|
text-decoration : none;
|
||||||
@@ -39,6 +37,7 @@
|
|||||||
overflow : hidden;
|
overflow : hidden;
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
|
max-width: 0;
|
||||||
margin-bottom : $size-margin-medium;
|
margin-bottom : $size-margin-medium;
|
||||||
|
|
||||||
font-family : $font-family-header;
|
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
|
module.exports = class ModTileController extends BaseController
|
||||||
|
|
||||||
constructor: (options={})->
|
constructor: (options={})->
|
||||||
|
options.tagName = 'section'
|
||||||
options.templateName = 'browse_page/mod_tile'
|
options.templateName = 'browse_page/mod_tile'
|
||||||
super options
|
super options
|
||||||
|
|
||||||
|
|||||||
@@ -6,20 +6,64 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
.view__adsense {
|
.view__adsense {
|
||||||
.skyscraper {
|
left : 50%;
|
||||||
height : $size-skyscraper-height;
|
margin : $size-margin-large 0;
|
||||||
width : $size-skyscraper-width;
|
position : relative;
|
||||||
position : relative;
|
transform : translate(-50%);
|
||||||
|
|
||||||
border : 0.1em solid $color-gray-faint;
|
ins {
|
||||||
margin : $size-margin-large 0;
|
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 {
|
&:first-child {
|
||||||
margin-top : 0;
|
margin-top : 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ins {
|
&.placeholder {
|
||||||
position: absolute; top: 0; right: 0; bottom: 0; left: 0;
|
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.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
|
|
||||||
BaseController = require '../../base_controller'
|
|
||||||
|
|
||||||
########################################################################################################################
|
########################################################################################################################
|
||||||
|
|
||||||
module.exports = class AdsenseController extends BaseController
|
module.exports = class AdsenseController
|
||||||
|
|
||||||
constructor: (options={})->
|
|
||||||
options.templateName = 'common/adsense'
|
|
||||||
super options
|
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
@_adsEnabled = global.env in c.productionEnvs
|
@_adsEnabled = global.env in c.productionEnvs
|
||||||
@_adCount = 0
|
@_adsPlaced = 0
|
||||||
@_waiting = false
|
@_waiting = false
|
||||||
|
|
||||||
# Public Methods ###############################################################################
|
# Public Methods ###############################################################################
|
||||||
|
|
||||||
fillAdPositions: ->
|
fillAdPositions: ->
|
||||||
if @_adCount > 0
|
adType = @_computeAdType()
|
||||||
return unless @$sidebar and @$mainBody
|
maxAds = c.adsense[adType].slotIds.length - @_adsPlaced
|
||||||
return unless @_adCount < @_computeMaxAds()
|
return if maxAds is 0
|
||||||
return unless @_adCount < c.adsense.slotIds.length
|
|
||||||
|
|
||||||
$adContainer = $('<div class="skyscraper"></div>')
|
logger.verbose => "Looking to place #{maxAds} more #{adType} ads..."
|
||||||
@$el.append $adContainer
|
|
||||||
|
|
||||||
if @_adsEnabled
|
if adType is 'skyscraper'
|
||||||
$ad = $('<ins class="adsbygoogle"></ins>')
|
placedNewAd = @_createSkyscraperPositions()
|
||||||
$ad.attr 'data-ad-client', c.adsense.clientId
|
else
|
||||||
$ad.attr 'data-ad-slot', c.adsense.slotIds[@_adCount]
|
placedNewAd = @_createBannerPositions adType
|
||||||
$adContainer.append $ad
|
|
||||||
@_loadAds()
|
|
||||||
|
|
||||||
@_adCount += 1
|
if @_adsPlaced < c.adsense[adType].slotIds.length
|
||||||
_.defer => @fillAdPositions()
|
duration = if placedNewAd then 0 else c.adsense.readinessCheckInterval
|
||||||
|
_.delay (=> @fillAdPositions()), duration
|
||||||
|
else
|
||||||
|
logger.verbose => "All #{adType} ad positions filled"
|
||||||
|
|
||||||
# BaseController Overrides #####################################################################
|
reset: ->
|
||||||
|
@_adsPlaced = 0
|
||||||
onDidRender: ->
|
|
||||||
@$mainBody = $('.page > .content > .right')
|
|
||||||
@$sidebar = $('.page > .content > .left')
|
|
||||||
super
|
|
||||||
|
|
||||||
refresh: ->
|
|
||||||
@_waitForPageReadiness()
|
@_waitForPageReadiness()
|
||||||
super
|
|
||||||
|
|
||||||
# Private Methods #############################################################################
|
# Private Methods #############################################################################
|
||||||
|
|
||||||
_computeMaxAds: ->
|
_computeAdType: ->
|
||||||
return null unless @$sidebar
|
return c.adsense.adTypeMap[c.screen.type.compute()]
|
||||||
result = Math.floor @$sidebar.height() / (c.adsense.skyscraper.height + c.adsense.skyscraper.margin)
|
|
||||||
|
_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
|
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
|
return unless @_adsEnabled
|
||||||
|
|
||||||
logger.info "Loading #{@_adCount} Google AdSense ads"
|
logger.info "Loading Google AdSense ads"
|
||||||
try
|
try
|
||||||
global.adsbygoogle ||= []
|
global.adsbygoogle ||= []
|
||||||
global.adsbygoogle.push {}
|
global.adsbygoogle.push {}
|
||||||
@@ -70,11 +139,12 @@ module.exports = class AdsenseController extends BaseController
|
|||||||
|
|
||||||
_waitForPageReadiness: ->
|
_waitForPageReadiness: ->
|
||||||
return if @_waiting
|
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"
|
logger.verbose "Adsense is waiting for room to insert ads"
|
||||||
@_waiting = true
|
@_waiting = true
|
||||||
_.delay (=> @_waiting = false; @_waitForPageReadiness()), c.duration.normal
|
_.delay (=> @_waiting = false; @_waitForPageReadiness()), c.adsense.readinessCheckInterval
|
||||||
else
|
else
|
||||||
logger.verbose "Adsense is ready to fill ads"
|
logger.verbose "Adsense is ready to fill ads"
|
||||||
@fillAdPositions()
|
@fillAdPositions()
|
||||||
|
|||||||
@@ -9,5 +9,5 @@
|
|||||||
.item_container
|
.item_container
|
||||||
.empty_placeholder nothing
|
.empty_placeholder nothing
|
||||||
.buttons
|
.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
|
.button.clear: .bezel: p clear
|
||||||
|
|||||||
@@ -38,12 +38,24 @@
|
|||||||
margin-top: $size-margin-large;
|
margin-top: $size-margin-large;
|
||||||
|
|
||||||
.item-selector {
|
.item-selector {
|
||||||
flex : 85%;
|
flex : 80%;
|
||||||
margin-right : $size-margin-medium;
|
margin-right : $size-margin-medium;
|
||||||
|
|
||||||
|
@include screen-size(mobile) {
|
||||||
|
flex: 50%;
|
||||||
|
|
||||||
|
.full {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.clear {
|
.clear {
|
||||||
flex : 15%;
|
flex : 20%;
|
||||||
|
|
||||||
|
@include screen-size(mobile) {
|
||||||
|
flex: 50%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,8 +73,12 @@
|
|||||||
.quantity {
|
.quantity {
|
||||||
padding-right : $size-margin-medium;
|
padding-right : $size-margin-medium;
|
||||||
input {
|
input {
|
||||||
width: 3em;
|
width : 3em;
|
||||||
font-size : $font-size-xlarge;
|
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;
|
overflow: visible;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
height: $size-minecraft-block;
|
height: $size-minecraft-block;
|
||||||
@@ -22,9 +22,19 @@
|
|||||||
font-family: $font-family-text;
|
font-family: $font-family-text;
|
||||||
font-size: $font-size-medium;
|
font-size: $font-size-medium;
|
||||||
line-height: $size-minecraft-block;
|
line-height: $size-minecraft-block;
|
||||||
overflow-x: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include screen-size(mobile) {
|
||||||
|
.view__item_tile {
|
||||||
|
a {
|
||||||
|
p {
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,7 +48,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
flex : 0 0 auto;
|
|
||||||
background : $color-active-hover;
|
background : $color-active-hover;
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
|
|||||||
@@ -9,6 +9,6 @@
|
|||||||
.view__item_selector_popup
|
.view__item_selector_popup
|
||||||
.search
|
.search
|
||||||
img(src='/images/search.png')
|
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')
|
img.close(src='/images/close.png')
|
||||||
.results
|
.results
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.view__item_selector_popup {
|
.view__item_selector_popup {
|
||||||
|
max-width: $size-minecraft-block * 20;
|
||||||
height : 66%;
|
height : 66%;
|
||||||
|
|
||||||
background : $color-background-panel;
|
background : $color-background-panel;
|
||||||
@@ -35,6 +36,7 @@
|
|||||||
|
|
||||||
input {
|
input {
|
||||||
flex: 1 1 100%;
|
flex: 1 1 100%;
|
||||||
|
min-width: $font-size-large * 10;
|
||||||
|
|
||||||
background: none;
|
background: none;
|
||||||
border: 0;
|
border: 0;
|
||||||
@@ -50,8 +52,15 @@
|
|||||||
|
|
||||||
.results {
|
.results {
|
||||||
flex: 1 1 100%;
|
flex: 1 1 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: scroll;
|
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
|
when c.key.enter
|
||||||
@_chooseSelected()
|
@_chooseSelected()
|
||||||
return false
|
return false
|
||||||
when c.key.down
|
when c.key.downArrow
|
||||||
@_selectNext()
|
@_selectNext()
|
||||||
return false
|
return false
|
||||||
when c.key.up
|
when c.key.upArrow
|
||||||
@_selectPrevious()
|
@_selectPrevious()
|
||||||
return false
|
return false
|
||||||
|
|
||||||
@@ -82,6 +82,7 @@ module.exports = class ItemSelectorController extends BaseController
|
|||||||
@model.hint = @$hintField.val()
|
@model.hint = @$hintField.val()
|
||||||
@tryRefresh()
|
@tryRefresh()
|
||||||
@onResultSelected @_elementControllers[0]
|
@onResultSelected @_elementControllers[0]
|
||||||
|
return false
|
||||||
|
|
||||||
onPopupClicked: (event)->
|
onPopupClicked: (event)->
|
||||||
return false
|
return false
|
||||||
@@ -90,6 +91,7 @@ module.exports = class ItemSelectorController extends BaseController
|
|||||||
@_session.resolve controller.model.slug
|
@_session.resolve controller.model.slug
|
||||||
@_session = null
|
@_session = null
|
||||||
@_close()
|
@_close()
|
||||||
|
return false
|
||||||
|
|
||||||
onResultSelected: (controller)->
|
onResultSelected: (controller)->
|
||||||
for c in @_elementControllers
|
for c in @_elementControllers
|
||||||
@@ -98,6 +100,8 @@ module.exports = class ItemSelectorController extends BaseController
|
|||||||
if controller?
|
if controller?
|
||||||
controller.selected = true
|
controller.selected = true
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
onScreenClicked: (event)->
|
onScreenClicked: (event)->
|
||||||
@_close()
|
@_close()
|
||||||
return false
|
return false
|
||||||
@@ -169,6 +173,8 @@ module.exports = class ItemSelectorController extends BaseController
|
|||||||
@_elementControllers.pop().remove()
|
@_elementControllers.pop().remove()
|
||||||
|
|
||||||
_selectNext: ->
|
_selectNext: ->
|
||||||
|
return unless @_elementControllers.length > 0
|
||||||
|
|
||||||
for i in [0...(@_elementControllers.length - 1)] by 1
|
for i in [0...(@_elementControllers.length - 1)] by 1
|
||||||
controller = @_elementControllers[i]
|
controller = @_elementControllers[i]
|
||||||
nextController = @_elementControllers[i + 1]
|
nextController = @_elementControllers[i + 1]
|
||||||
@@ -179,7 +185,13 @@ module.exports = class ItemSelectorController extends BaseController
|
|||||||
@_showElement nextController.$el
|
@_showElement nextController.$el
|
||||||
return
|
return
|
||||||
|
|
||||||
|
controller = @_elementControllers[0]
|
||||||
|
controller.selected = true
|
||||||
|
@_showElement controller.$el
|
||||||
|
|
||||||
_selectPrevious: ->
|
_selectPrevious: ->
|
||||||
|
return unless @_elementControllers.length > 0
|
||||||
|
|
||||||
for i in [1...@_elementControllers.length] by 1
|
for i in [1...@_elementControllers.length] by 1
|
||||||
previousController = @_elementControllers[i - 1]
|
previousController = @_elementControllers[i - 1]
|
||||||
controller = @_elementControllers[i]
|
controller = @_elementControllers[i]
|
||||||
@@ -190,6 +202,10 @@ module.exports = class ItemSelectorController extends BaseController
|
|||||||
@_showElement previousController.$el
|
@_showElement previousController.$el
|
||||||
return
|
return
|
||||||
|
|
||||||
|
controller = @_elementControllers[@_elementControllers.length - 1]
|
||||||
|
controller.selected = true
|
||||||
|
@_showElement controller.$el
|
||||||
|
|
||||||
_showElement: ($el)->
|
_showElement: ($el)->
|
||||||
top = $el.position().top + @$resultsContainer.scrollTop()
|
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 ################################################################################
|
# Event Methods ################################################################################
|
||||||
|
|
||||||
onCancelClicked: (event)->
|
onCancelClicked: (event)->
|
||||||
event.preventDefault()
|
|
||||||
@model = @_originalModel
|
@model = @_originalModel
|
||||||
@resetToDefaultState()
|
@resetToDefaultState()
|
||||||
|
|
||||||
@_imageListController.reset()
|
@_imageListController.reset()
|
||||||
@_updatePreview()
|
@_updatePreview()
|
||||||
|
return false
|
||||||
|
|
||||||
onEditClicked: (event)->
|
onEditClicked: (event)->
|
||||||
event.preventDefault()
|
return false unless @editable
|
||||||
return unless @editable
|
|
||||||
|
|
||||||
@_originalModel = @model
|
@_originalModel = @model
|
||||||
@state = @State.waiting
|
@state = @State.waiting
|
||||||
@@ -81,22 +80,22 @@ module.exports = class MarkdownSectionController extends BaseController
|
|||||||
@state = @State.appologizing
|
@state = @State.appologizing
|
||||||
w(true).delay(@_confirmDuration).then => @resetToDefaultState()
|
w(true).delay(@_confirmDuration).then => @resetToDefaultState()
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
onQuestionClicked: (event)->
|
onQuestionClicked: (event)->
|
||||||
event.preventDefault()
|
|
||||||
@_enterFeedback ''
|
@_enterFeedback ''
|
||||||
|
return false
|
||||||
|
|
||||||
onPreviewClicked: (event)->
|
onPreviewClicked: (event)->
|
||||||
event.preventDefault()
|
|
||||||
@_updatePreview()
|
@_updatePreview()
|
||||||
@state = @State.previewing
|
@state = @State.previewing
|
||||||
|
return false
|
||||||
|
|
||||||
onReturnClicked: (event)->
|
onReturnClicked: (event)->
|
||||||
event.preventDefault()
|
|
||||||
@state = @State.editing
|
@state = @State.editing
|
||||||
|
return false
|
||||||
|
|
||||||
onSaveClicked: (event)->
|
onSaveClicked: (event)->
|
||||||
event.preventDefault()
|
|
||||||
|
|
||||||
@state = @State.waiting
|
@state = @State.waiting
|
||||||
@_endEditing()
|
@_endEditing()
|
||||||
.then =>
|
.then =>
|
||||||
@@ -109,9 +108,11 @@ module.exports = class MarkdownSectionController extends BaseController
|
|||||||
.then =>
|
.then =>
|
||||||
@state = @State.viewing
|
@state = @State.viewing
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
onTextChanged: (event)->
|
onTextChanged: (event)->
|
||||||
event.preventDefault()
|
|
||||||
@model = @$textarea.val()
|
@model = @$textarea.val()
|
||||||
|
return false
|
||||||
|
|
||||||
# Property Methods #############################################################################
|
# Property Methods #############################################################################
|
||||||
|
|
||||||
|
|||||||
@@ -9,12 +9,16 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
flex: 1 1 50%;
|
flex: 0 0 auto;
|
||||||
|
|
||||||
align-items : center;
|
align-items : center;
|
||||||
display : flex;
|
display : flex;
|
||||||
flex-direction : column;
|
flex-direction : column;
|
||||||
|
|
||||||
|
.view__crafting_grid {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
.tool {
|
.tool {
|
||||||
margin-top : $size-margin-small;
|
margin-top : $size-margin-small;
|
||||||
|
|
||||||
@@ -24,7 +28,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.output {
|
.output {
|
||||||
flex: 1 1 50%;
|
flex: 1 1 100%;
|
||||||
margin-left: $size-margin-medium;
|
margin-left: $size-margin-medium;
|
||||||
|
|
||||||
display : flex;
|
display : flex;
|
||||||
|
|||||||
@@ -6,7 +6,9 @@
|
|||||||
//-
|
//-
|
||||||
|
|
||||||
.view__stack
|
.view__stack
|
||||||
.quantity: input
|
.quantity
|
||||||
|
input
|
||||||
|
.hover
|
||||||
.icon: img(src='')
|
.icon: img(src='')
|
||||||
.name: a
|
.name: a
|
||||||
.action.first(style="display: none")
|
.action.first(style="display: none")
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
.quantity {
|
.quantity {
|
||||||
padding-right : $size-margin-medium;
|
padding-right : $size-margin-medium;
|
||||||
|
position : relative;
|
||||||
text-align : right;
|
text-align : right;
|
||||||
|
|
||||||
input {
|
input {
|
||||||
@@ -32,6 +33,38 @@
|
|||||||
font-size : $font-size-large;
|
font-size : $font-size-large;
|
||||||
text-align : right;
|
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 {
|
.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
|
module.exports = class StackController extends BaseController
|
||||||
|
|
||||||
@::MAX_QUANTITY = 9999
|
@::MAX_QUANTITY = 9999
|
||||||
|
@::STACK_SIZE = 64
|
||||||
|
|
||||||
constructor: (options={})->
|
constructor: (options={})->
|
||||||
if not options.imageLoader? then throw new Error 'options.imageLoader is required'
|
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')
|
@$image = @$('.icon img')
|
||||||
@$nameLink = @$('.name a')
|
@$nameLink = @$('.name a')
|
||||||
@$quantityField = @$('.quantity input')
|
@$quantityField = @$('.quantity input')
|
||||||
|
@$quantityHover = @$('.quantity .hover')
|
||||||
@$secondAction = @$('.action.second')
|
@$secondAction = @$('.action.second')
|
||||||
@$secondButton = @$('.action.second .button')
|
@$secondButton = @$('.action.second .button')
|
||||||
super
|
super
|
||||||
@@ -124,6 +126,7 @@ module.exports = class StackController extends BaseController
|
|||||||
@$quantityField.val quantityText
|
@$quantityField.val quantityText
|
||||||
|
|
||||||
@_refreshButtons()
|
@_refreshButtons()
|
||||||
|
@_refreshHover()
|
||||||
|
|
||||||
if @_editable
|
if @_editable
|
||||||
@$el.addClass 'editable'
|
@$el.addClass 'editable'
|
||||||
@@ -169,6 +172,20 @@ module.exports = class StackController extends BaseController
|
|||||||
when 'remove' then $label.text '-'
|
when 'remove' then $label.text '-'
|
||||||
when 'up' 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)->
|
_updateButtonType: ($button, type)->
|
||||||
for currentType in ['check', 'down', 'remove', 'up']
|
for currentType in ['check', 'down', 'remove', 'up']
|
||||||
$button.removeClass currentType
|
$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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,5 +6,5 @@
|
|||||||
//-
|
//-
|
||||||
|
|
||||||
.view__video
|
.view__video
|
||||||
iframe(width="356", height="267", src="", frameborder="0", allowfullscreen="true")
|
iframe(src="", frameborder="0", allowfullscreen="true")
|
||||||
.caption: p
|
.caption: p
|
||||||
@@ -11,6 +11,10 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.caption {
|
.caption {
|
||||||
margin-top: $size-margin-small;
|
margin-top: $size-margin-small;
|
||||||
|
|
||||||
|
|||||||
@@ -5,16 +5,8 @@
|
|||||||
//- All rights reserved.
|
//- 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
|
.content.view__craft_page
|
||||||
.left
|
.left
|
||||||
.view__adsense
|
|
||||||
|
|
||||||
.right
|
.right
|
||||||
section.instructions
|
section.instructions
|
||||||
@@ -26,19 +18,19 @@
|
|||||||
p.
|
p.
|
||||||
Not sure what you'd like to make? Try one of these:
|
Not sure what you'd like to make? Try one of these:
|
||||||
.items
|
.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")
|
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")
|
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")
|
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")
|
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")
|
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")
|
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")
|
img(src="/data/thermal_expansion/items/tesseract/icon.png")
|
||||||
|
|
||||||
section.want
|
section.want
|
||||||
@@ -51,8 +43,6 @@
|
|||||||
.panel
|
.panel
|
||||||
.view__inventory.large.editable
|
.view__inventory.large.editable
|
||||||
|
|
||||||
section.view__craftsman_working
|
|
||||||
|
|
||||||
section.need
|
section.need
|
||||||
h2 Need to Gather
|
h2 Need to Gather
|
||||||
.panel
|
.panel
|
||||||
@@ -61,3 +51,5 @@
|
|||||||
section.steps
|
section.steps
|
||||||
h2 Steps
|
h2 Steps
|
||||||
.panel
|
.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.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
|
|
||||||
AdsenseController = require '../common/adsense/adsense_controller'
|
|
||||||
BaseController = require '../base_controller'
|
BaseController = require '../base_controller'
|
||||||
CraftPage = require '../../models/site/craft_page'
|
CraftPage = require '../../models/site/craft_page'
|
||||||
Craftsman = require '../../models/crafting/craftsman'
|
Craftsman = require '../../models/crafting/craftsman'
|
||||||
CraftsmanWorkingController = require './craftsman_working/craftsman_working_controller'
|
CraftsmanWorkingController = require './craftsman_working/craftsman_working_controller'
|
||||||
InventoryController = require '../common/inventory/inventory_controller'
|
InventoryController = require '../common/inventory/inventory_controller'
|
||||||
PageController = require '../page_controller'
|
PageController = require '../page_controller'
|
||||||
|
SimpleInventory = require '../../models/crafting/simple_inventory'
|
||||||
StepController = require './step/step_controller'
|
StepController = require './step/step_controller'
|
||||||
|
|
||||||
########################################################################################################################
|
########################################################################################################################
|
||||||
|
|
||||||
module.exports = class CraftPageController extends PageController
|
module.exports = class CraftPageController extends PageController
|
||||||
|
|
||||||
|
@::SCROLL_BUFFER = 8 # px
|
||||||
|
|
||||||
constructor: (options={})->
|
constructor: (options={})->
|
||||||
if not options.imageLoader? then throw new Error 'options.imageLoader is required'
|
if not options.imageLoader? then throw new Error 'options.imageLoader is required'
|
||||||
if not options.modPack? then throw new Error 'options.modPack is required'
|
if not options.modPack? then throw new Error 'options.modPack is required'
|
||||||
@@ -33,10 +35,9 @@ module.exports = class CraftPageController extends PageController
|
|||||||
@_router = options.router
|
@_router = options.router
|
||||||
@_storage = options.storage
|
@_storage = options.storage
|
||||||
|
|
||||||
# c.event Methods ################################################################################
|
# Event Methods ################################################################################
|
||||||
|
|
||||||
onHaveInventoryChanged: ->
|
onHaveInventoryChanged: ->
|
||||||
logger.warning => "storing have: #{@model.craftsman.have.unparse()}"
|
|
||||||
@_storage.store 'crafting-plan:have', @model.craftsman.have.unparse()
|
@_storage.store 'crafting-plan:have', @model.craftsman.have.unparse()
|
||||||
|
|
||||||
onMoveNeedToHave: (itemSlug)->
|
onMoveNeedToHave: (itemSlug)->
|
||||||
@@ -50,27 +51,39 @@ module.exports = class CraftPageController extends PageController
|
|||||||
@model.craftsman.want.remove itemSlug
|
@model.craftsman.want.remove itemSlug
|
||||||
@onWantInventoryChanged()
|
@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: ->
|
onWantInventoryChanged: ->
|
||||||
text = @model.craftsman.want.unparse()
|
text = @model.craftsman.want.unparse()
|
||||||
url = c.url.crafting inventoryText:text
|
url = c.url.crafting inventoryText:text
|
||||||
@router.navigate url
|
@router.navigate url
|
||||||
|
|
||||||
if @model.craftsman.want.isEmpty
|
|
||||||
@model.craftsman.have.clear()
|
|
||||||
|
|
||||||
# PageController Overrides #####################################################################
|
# PageController Overrides #####################################################################
|
||||||
|
|
||||||
getMetaDescription: ->
|
getMetaDescription: ->
|
||||||
return c.text.craftDescription()
|
return c.text.craftDescription()
|
||||||
|
|
||||||
getTitle: ->
|
getTitle: ->
|
||||||
return 'Craft'
|
description = @model.craftsman.want.toDescription()
|
||||||
|
return null unless description?
|
||||||
|
return "Crafting Plan for #{description}"
|
||||||
|
|
||||||
# BaseController Overrides #####################################################################
|
# BaseController Overrides #####################################################################
|
||||||
|
|
||||||
onDidRender: ->
|
onDidRender: ->
|
||||||
@_adsenseController = @addChild AdsenseController, '.view__adsense', model:'skyscraper'
|
|
||||||
|
|
||||||
@_wantInventoryController = @addChild InventoryController, '.want .view__inventory',
|
@_wantInventoryController = @addChild InventoryController, '.want .view__inventory',
|
||||||
firstButtonType: 'remove'
|
firstButtonType: 'remove'
|
||||||
imageLoader: @_imageLoader
|
imageLoader: @_imageLoader
|
||||||
@@ -89,7 +102,6 @@ module.exports = class CraftPageController extends PageController
|
|||||||
router: @_router
|
router: @_router
|
||||||
@_haveInventoryController.on c.event.button.first, (controller, itemSlug)=>
|
@_haveInventoryController.on c.event.button.first, (controller, itemSlug)=>
|
||||||
@onRemoveFromHaveInventory itemSlug
|
@onRemoveFromHaveInventory itemSlug
|
||||||
@_haveInventoryController.on c.event.change, (c)=> @onHaveInventoryChanged()
|
|
||||||
|
|
||||||
@_needInventoryController = @addChild InventoryController, '.need .view__inventory',
|
@_needInventoryController = @addChild InventoryController, '.need .view__inventory',
|
||||||
editable: false
|
editable: false
|
||||||
@@ -102,6 +114,7 @@ module.exports = class CraftPageController extends PageController
|
|||||||
|
|
||||||
@_workingSectionController = @addChild CraftsmanWorkingController, '.view__craftsman_working',
|
@_workingSectionController = @addChild CraftsmanWorkingController, '.view__craftsman_working',
|
||||||
model: @model.craftsman
|
model: @model.craftsman
|
||||||
|
@_workingSectionController.on c.event.click, => @_scrollTo @$workingSection
|
||||||
|
|
||||||
@$haveSection = @$('section.have')
|
@$haveSection = @$('section.have')
|
||||||
@$instructionsSection = @$('section.instructions')
|
@$instructionsSection = @$('section.instructions')
|
||||||
@@ -112,25 +125,37 @@ module.exports = class CraftPageController extends PageController
|
|||||||
@$toolsSection = @$('section.tools')
|
@$toolsSection = @$('section.tools')
|
||||||
@$workingSection = @$('.view__craftsman_working')
|
@$workingSection = @$('.view__craftsman_working')
|
||||||
|
|
||||||
|
if c.screen.type.compute() is c.screen.type.mobile
|
||||||
|
@$('.view__inventory.large').removeClass 'large'
|
||||||
|
|
||||||
super
|
super
|
||||||
|
|
||||||
onWillRender: ->
|
onWillRender: ->
|
||||||
@model.craftsman.have.clear()
|
@model.craftsman.have.clear()
|
||||||
@model.craftsman.have.parse @_storage.load('crafting-plan:have')
|
@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
|
super
|
||||||
|
|
||||||
refresh: ->
|
refresh: ->
|
||||||
@_needInventoryController.model = @model.craftsman.plan?.need
|
@_needInventoryController.model = @model.craftsman.plan?.need
|
||||||
|
@_refreshOutdated()
|
||||||
@_refreshSectionVisibility()
|
@_refreshSectionVisibility()
|
||||||
@_refreshSteps()
|
@_refreshSteps()
|
||||||
@_adsenseController.fillAdPositions()
|
|
||||||
super
|
super
|
||||||
|
|
||||||
# Backbone.View Overrides ########################################################################
|
# Backbone.View Overrides ########################################################################
|
||||||
|
|
||||||
events: ->
|
events: ->
|
||||||
return _.extend super,
|
return _.extend super,
|
||||||
'click .instructions a': 'routeLinkClick'
|
'click .instructions a': 'onSampleClicked'
|
||||||
|
|
||||||
# Private Methods ################################################################################
|
# Private Methods ################################################################################
|
||||||
|
|
||||||
@@ -138,7 +163,7 @@ module.exports = class CraftPageController extends PageController
|
|||||||
controller.model.addToolsTo @model.craftsman.want
|
controller.model.addToolsTo @model.craftsman.want
|
||||||
|
|
||||||
_completeStep: (controller)->
|
_completeStep: (controller)->
|
||||||
controller.model.completeInto @model.craftsman.have
|
controller.markComplete @model.craftsman.have
|
||||||
|
|
||||||
_isAddingToolsPossible: (controller)->
|
_isAddingToolsPossible: (controller)->
|
||||||
tools = controller.model.recipe.tools
|
tools = controller.model.recipe.tools
|
||||||
@@ -160,6 +185,12 @@ module.exports = class CraftPageController extends PageController
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
_refreshOutdated: ->
|
||||||
|
if @model.craftsman.stage is Craftsman::STAGE.OUTDATED
|
||||||
|
@$el.addClass 'outdated'
|
||||||
|
else
|
||||||
|
@$el.removeClass 'outdated'
|
||||||
|
|
||||||
_refreshSectionVisibility: ->
|
_refreshSectionVisibility: ->
|
||||||
return unless @_rendered
|
return unless @_rendered
|
||||||
|
|
||||||
@@ -172,11 +203,13 @@ module.exports = class CraftPageController extends PageController
|
|||||||
if @model.craftsman.want.isEmpty
|
if @model.craftsman.want.isEmpty
|
||||||
visibleSections.push el for el in [@$instructionsSection, @$wantSection]
|
visibleSections.push el for el in [@$instructionsSection, @$wantSection]
|
||||||
else if @model.craftsman.stage is Craftsman::STAGE.INVALID
|
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
|
else if not @model.craftsman.complete
|
||||||
visibleSections.push el for el in [@$wantSection, @$workingSection]
|
visibleSections.push el for el in [@$wantSection, @$haveSection, @$workingSection]
|
||||||
else
|
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
|
@hide $el for $el in allSections
|
||||||
@show $el for $el in visibleSections
|
@show $el for $el in visibleSections
|
||||||
@@ -209,3 +242,28 @@ module.exports = class CraftPageController extends PageController
|
|||||||
|
|
||||||
while @_stepControllers.length > index
|
while @_stepControllers.length > index
|
||||||
@_stepControllers.pop().remove()
|
@_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.
|
//- All rights reserved.
|
||||||
//-
|
//-
|
||||||
|
|
||||||
.view__item_group.section
|
.view__craftsman_working
|
||||||
.content
|
.panel
|
||||||
.waiting
|
.waiting
|
||||||
img(src='/images/wait.gif')
|
img(src='/images/wait.gif')
|
||||||
.message
|
.message
|
||||||
p
|
p
|
||||||
.count
|
.count
|
||||||
p
|
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 {
|
.view__craftsman_working {
|
||||||
.content {
|
.panel {
|
||||||
background: $color-white;
|
|
||||||
box-shadow: none;
|
|
||||||
|
|
||||||
align-items : center;
|
align-items : center;
|
||||||
display : flex;
|
display : flex;
|
||||||
flex-direction : column;
|
flex-direction : column;
|
||||||
padding : $size-margin-xlarge;
|
padding : $size-margin-xlarge;
|
||||||
|
|
||||||
.waiting {
|
.waiting {
|
||||||
margin-bottom: $size-margin-xlarge;
|
margin-bottom : $size-margin-xlarge;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message {
|
.message {
|
||||||
margin-bottom: $size-margin-medium;
|
margin-bottom : $size-margin-medium;
|
||||||
|
|
||||||
p {
|
p {
|
||||||
font-family: $font-family-header;
|
font-family : $font-family-header;
|
||||||
font-size: $font-size-large;
|
font-size : $font-size-large;
|
||||||
|
text-align : center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.count {
|
.count {
|
||||||
p {
|
p {
|
||||||
font-family: $font-family-header;
|
font-family : $font-family-header;
|
||||||
font-size: $font-size-medium;
|
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
|
module.exports = class CraftsmanWorkingController extends BaseController
|
||||||
|
|
||||||
|
@::HIDE_TIMER_DURATION = 2000
|
||||||
|
|
||||||
constructor: (options={})->
|
constructor: (options={})->
|
||||||
if not options.model then throw new Error 'options.model is required'
|
if not options.model then throw new Error 'options.model is required'
|
||||||
options.templateName = 'craft_page/craftsman_working'
|
options.templateName = 'craft_page/craftsman_working'
|
||||||
super options
|
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 #######################################################################
|
# BaseController Methods #######################################################################
|
||||||
|
|
||||||
|
onDidModelChange: ->
|
||||||
|
@refresh()
|
||||||
|
|
||||||
onDidRender: ->
|
onDidRender: ->
|
||||||
@$message = @$('.message p')
|
@$button = @$('.button')
|
||||||
@$count = @$('.count p')
|
@$count = @$('.count p')
|
||||||
@$waiting = @$('.waiting')
|
@$message = @$('.message p')
|
||||||
|
@$outdated = @$('.outdated')
|
||||||
|
@$waiting = @$('.waiting')
|
||||||
|
|
||||||
|
@_controls = [@$button, @$count, @$message, @$outdated, @$waiting]
|
||||||
super
|
super
|
||||||
|
|
||||||
refresh: ->
|
refresh: ->
|
||||||
@_refreshStatusText()
|
|
||||||
super
|
|
||||||
|
|
||||||
# Private Methods ##############################################################################
|
|
||||||
|
|
||||||
_refreshStatusText: ->
|
|
||||||
return unless @$message? and @$count?
|
return unless @$message? and @$count?
|
||||||
|
|
||||||
@show @$waiting
|
button = count = message = outdated = waiting = null
|
||||||
|
|
||||||
switch @model.stage
|
switch @model.stage
|
||||||
when Craftsman::STAGE.WAITING
|
when Craftsman::STAGE.READY
|
||||||
@$message.html 'Preparing crafting calculation...'
|
message = 'Ready to compute crafting plan!'
|
||||||
@$count.html ''
|
count = 'Click "Calculate" to continue.'
|
||||||
|
button = true
|
||||||
when Craftsman::STAGE.GRAPHING
|
when Craftsman::STAGE.GRAPHING
|
||||||
@$message.html 'Researching recipes...'
|
message = 'Researching recipes...'
|
||||||
@$count.html "Found #{@model.stageCount} recipes so far..."
|
count = "Found #{@model.stageCount} recipes so far..."
|
||||||
|
watiing = true
|
||||||
when Craftsman::STAGE.PLANNING
|
when Craftsman::STAGE.PLANNING
|
||||||
@$message.html 'Figuring out possible crafting plans...'
|
message = 'Figuring out possible crafting plans...'
|
||||||
@$count.html "Found #{@model.stageCount} possibilities so far..."
|
count = "Found #{@model.stageCount} possibilities so far..."
|
||||||
|
watiing = true
|
||||||
when Craftsman::STAGE.ANALYZING
|
when Craftsman::STAGE.ANALYZING
|
||||||
@$message.html 'Looking for the best plan...'
|
message = 'Looking for the best plan...'
|
||||||
@$count.html "Finished checking #{@model.stageCount} so far..."
|
count = "Finished checking #{@model.stageCount} so far..."
|
||||||
|
watiing = true
|
||||||
when Craftsman::STAGE.COMPLETE
|
when Craftsman::STAGE.COMPLETE
|
||||||
@$message.html 'All done!'
|
message = 'Crafting plan is complete.'
|
||||||
@$count.html ''
|
|
||||||
when Craftsman::STAGE.INVALID
|
when Craftsman::STAGE.INVALID
|
||||||
@$message.html 'Couldn\'t make a crafting plan'
|
message = 'Couldn\'t make a crafting plan!'
|
||||||
@$count.html ''
|
count = 'Please report this problem using the Feedback box.'
|
||||||
@hide @waiting
|
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'
|
||||||
|
|||||||
@@ -11,5 +11,5 @@
|
|||||||
.view__inventory
|
.view__inventory
|
||||||
.view__recipe
|
.view__recipe
|
||||||
.buttons
|
.buttons
|
||||||
.button.complete: .bezel: p complete step
|
a.button.tool: .bezel: p <span class="full">show plan for </span>tools
|
||||||
.button.tool: .bezel: p make this tool
|
.button.complete: .bezel: p complete<span class="full"> step</span>
|
||||||
|
|||||||
@@ -31,6 +31,10 @@
|
|||||||
.view__inventory {
|
.view__inventory {
|
||||||
flex: 50%;
|
flex: 50%;
|
||||||
margin-left: $size-margin-large;
|
margin-left: $size-margin-large;
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.view__recipe {
|
.view__recipe {
|
||||||
@@ -52,5 +56,51 @@
|
|||||||
margin-left: $size-margin-medium;
|
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'
|
BaseController = require '../../base_controller'
|
||||||
InventoryController = require '../../common/inventory/inventory_controller'
|
InventoryController = require '../../common/inventory/inventory_controller'
|
||||||
RecipeController = require '../../common/recipe/recipe_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
|
@onComplete = options.onComplete or (controller)-> # do nothing
|
||||||
@onAddTools = options.onAddTools 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 ################################################################################
|
# Event Methods ################################################################################
|
||||||
|
|
||||||
onCompleteButtonClicked: (event)->
|
onCompleteButtonClicked: (event)->
|
||||||
return if @$completeButton.hasClass 'disabled'
|
return if @$completeButton.hasClass 'disabled'
|
||||||
@onComplete this
|
@onComplete this
|
||||||
|
|
||||||
onToolButtonClicked: (event)->
|
|
||||||
return if @$toolButton.hasClass 'disabled'
|
|
||||||
@onAddTools this
|
|
||||||
|
|
||||||
# BaseController Overrides #####################################################################
|
# BaseController Overrides #####################################################################
|
||||||
|
|
||||||
onDidRender: ->
|
onDidRender: ->
|
||||||
@@ -63,6 +67,9 @@ module.exports = class StepController extends BaseController
|
|||||||
|
|
||||||
onWillChangeModel: (oldModel, newModel)->
|
onWillChangeModel: (oldModel, newModel)->
|
||||||
if not newModel? then throw new Error 'model cannot be null'
|
if not newModel? then throw new Error 'model cannot be null'
|
||||||
|
if @rendered
|
||||||
|
@$el.removeClass 'complete'
|
||||||
|
@$completeButton.removeClass 'disabled'
|
||||||
return super
|
return super
|
||||||
|
|
||||||
refresh: ->
|
refresh: ->
|
||||||
@@ -83,11 +90,19 @@ module.exports = class StepController extends BaseController
|
|||||||
events: ->
|
events: ->
|
||||||
return _.extend super,
|
return _.extend super,
|
||||||
'click .button.complete': 'onCompleteButtonClicked'
|
'click .button.complete': 'onCompleteButtonClicked'
|
||||||
'click .button.tool': 'onToolButtonClicked'
|
|
||||||
|
|
||||||
# Private Methods ##############################################################################
|
# Private Methods ##############################################################################
|
||||||
|
|
||||||
_refreshToolButton: ->
|
_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
|
if @canAddTools this
|
||||||
@$toolButton.removeClass 'disabled'
|
@$toolButton.removeClass 'disabled'
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -15,6 +15,10 @@
|
|||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
|
@include screen-size(mobile) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.form-content {
|
.form-content {
|
||||||
flex: 1 1 100%;
|
flex: 1 1 100%;
|
||||||
|
|
||||||
@@ -73,13 +77,11 @@
|
|||||||
background: $color-gray-light;
|
background: $color-gray-light;
|
||||||
border: $size-border-medium solid $color-black;
|
border: $size-border-medium solid $color-black;
|
||||||
border-left: 0;
|
border-left: 0;
|
||||||
|
position: relative;
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
p {
|
p {
|
||||||
transform: rotate(-90deg);
|
position: absolute; top: 50%; left: 50%;
|
||||||
|
transform: translateX(-50%) rotate(-90deg) translateX(10%);
|
||||||
|
|
||||||
font-family: $font-family-header;
|
font-family: $font-family-header;
|
||||||
font-size: $label-size;
|
font-size: $label-size;
|
||||||
|
|||||||
@@ -19,12 +19,20 @@
|
|||||||
> .content {
|
> .content {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
|
@include screen-size(mobile) {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
color: $color-text-light;
|
color: $color-text-light;
|
||||||
|
|
||||||
.left, .center, .right {
|
.left, .center, .right {
|
||||||
flex: 1 1 33%;
|
flex: 1 1 33%;
|
||||||
margin: $size-margin-large $size-margin-large $size-margin-large 0;
|
margin: $size-margin-large $size-margin-large $size-margin-large 0;
|
||||||
|
|
||||||
|
@include screen-size(mobile) {
|
||||||
|
margin-left: $size-margin-large;
|
||||||
|
}
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
@@ -38,6 +46,7 @@
|
|||||||
.action {
|
.action {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
|
margin-top: $size-margin-large;
|
||||||
margin-bottom: $size-margin-large;
|
margin-bottom: $size-margin-large;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -55,3 +64,13 @@
|
|||||||
height: $size-minecraft-block;
|
height: $size-minecraft-block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include screen-size(mobile) {
|
||||||
|
.view__footer {
|
||||||
|
> .content {
|
||||||
|
.left, .center, .right {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,4 +21,6 @@
|
|||||||
.button.search: .bezel: p Search
|
.button.search: .bezel: p Search
|
||||||
.button.login: .bezel: p Login
|
.button.login: .bezel: p Login
|
||||||
|
|
||||||
.breadcrumbs
|
.breadcrumb-bar
|
||||||
|
.breadcrumbs
|
||||||
|
.extra-nav
|
||||||
|
|||||||
@@ -23,24 +23,22 @@
|
|||||||
|
|
||||||
img {
|
img {
|
||||||
position : relative;
|
position : relative;
|
||||||
top : -$size-minecraft-block * 0.5;
|
height : $size-minecraft-block * 1.5;
|
||||||
left : -$size-minecraft-block * 0.5;
|
width : $size-minecraft-block * 1.5;
|
||||||
height : $size-minecraft-block * 2.0;
|
|
||||||
width : $size-minecraft-block * 2.0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.addthis_sharing_toolbox {
|
.addthis_sharing_toolbox {
|
||||||
flex : 0 0 auto;
|
flex : 0 0 auto;
|
||||||
min-height : 37px;
|
min-height : 37px; // actual size of addthis component
|
||||||
min-width : 144px;
|
min-width : 144px;
|
||||||
margin-right : $size-margin-small;
|
margin-right : $size-margin-small;
|
||||||
|
|
||||||
|
|
||||||
&.placeholder {
|
&.placeholder {
|
||||||
border : 1px solid orange;
|
border : 1px solid orange;
|
||||||
text-align : center;
|
text-align : center;
|
||||||
@@ -62,36 +60,103 @@
|
|||||||
align-items : center;
|
align-items : center;
|
||||||
display : flex;
|
display : flex;
|
||||||
flex-wrap : wrap;
|
flex-wrap : wrap;
|
||||||
justify-content : space-around;
|
justify-content : center;
|
||||||
padding : $size-margin-medium $size-margin-medium;
|
padding : $size-margin-medium $size-margin-medium;
|
||||||
padding-top : 0;
|
padding-top : 0;
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
flex : 1 1 20%;
|
flex-grow : 1;
|
||||||
min-width : 4 * $size-minecraft-block;
|
flex-shrink : 1;
|
||||||
max-width : 5 * $size-minecraft-block;
|
min-width : 3 * $size-minecraft-block;
|
||||||
margin-top: $size-margin-medium;
|
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;
|
background: $color-screen;
|
||||||
|
padding: 0 ($size-margin-medium + $size-margin-large);
|
||||||
|
|
||||||
font-family: $font-family-control;
|
font-family: $font-family-control;
|
||||||
font-size: $font-size-medium;
|
font-size: $font-size-medium;
|
||||||
|
line-height: $font-size-medium + 2 * $size-margin-small;
|
||||||
|
|
||||||
padding: $size-margin-small $size-margin-medium;
|
display: flex;
|
||||||
|
|
||||||
&:before {
|
.breadcrumbs {
|
||||||
content: "⟩";
|
flex: 1 1 75%;
|
||||||
margin-right: $size-margin-medium;
|
|
||||||
|
text-indent: -$size-margin-large;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: "⟩";
|
||||||
|
margin-right: $size-margin-medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin: 0 $size-margin-medium;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
.extra-nav {
|
||||||
text-decoration: underline;
|
flex: 1 1 25%;
|
||||||
}
|
align-self: flex-end;
|
||||||
|
|
||||||
span {
|
text-align: right;
|
||||||
margin: 0 $size-margin-medium;
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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'
|
BaseController = require '../base_controller'
|
||||||
ItemSelectorController = require '../common/item_selector/item_selector_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
|
@router.navigate '/news', trigger:true
|
||||||
return false
|
return false
|
||||||
|
|
||||||
onSearch: ->
|
onSearch: (event, hint='')->
|
||||||
@_selector.launch()
|
@_selector.launch hint
|
||||||
.then (itemSlug)=>
|
.then (itemSlug)=>
|
||||||
|
return unless itemSlug?
|
||||||
|
|
||||||
itemDisplay = @_modPack.findItemDisplay itemSlug
|
itemDisplay = @_modPack.findItemDisplay itemSlug
|
||||||
@router.navigate itemDisplay.itemUrl, trigger:true
|
@router.navigate itemDisplay.itemUrl, trigger:true
|
||||||
return false
|
return false
|
||||||
@@ -62,8 +65,11 @@ module.exports = class HeaderController extends BaseController
|
|||||||
@$('.addthis_sharing_toolbox').addClass 'placeholder'
|
@$('.addthis_sharing_toolbox').addClass 'placeholder'
|
||||||
|
|
||||||
@$breadcrumbs = @$('.breadcrumbs')
|
@$breadcrumbs = @$('.breadcrumbs')
|
||||||
|
@$extraNav = @$('.extra-nav')
|
||||||
@$loginButtonLabel = @$('.button.login p')
|
@$loginButtonLabel = @$('.button.login p')
|
||||||
@$title = $('title')
|
@$title = $('title')
|
||||||
|
|
||||||
|
@_checkForSearchRequest()
|
||||||
super
|
super
|
||||||
|
|
||||||
onWillChangeModel: (oldModel, newModel)->
|
onWillChangeModel: (oldModel, newModel)->
|
||||||
@@ -75,6 +81,8 @@ module.exports = class HeaderController extends BaseController
|
|||||||
@$loginButtonLabel.text if global.site.user? then "Logout" else "Login"
|
@$loginButtonLabel.text if global.site.user? then "Logout" else "Login"
|
||||||
|
|
||||||
@_refreshBreadcrumbs()
|
@_refreshBreadcrumbs()
|
||||||
|
@_refreshExtraNav()
|
||||||
|
@_refreshSelectedNavButton()
|
||||||
@_refreshTitle()
|
@_refreshTitle()
|
||||||
super
|
super
|
||||||
|
|
||||||
@@ -82,15 +90,21 @@ module.exports = class HeaderController extends BaseController
|
|||||||
|
|
||||||
events: ->
|
events: ->
|
||||||
_.extend super,
|
_.extend super,
|
||||||
'click .craft': 'onCraft'
|
'click .craft': 'onCraft'
|
||||||
'click .browse': 'onBrowse'
|
'click .browse': 'onBrowse'
|
||||||
'click .login': 'onLogin'
|
'click .login': 'onLogin'
|
||||||
'click .news': 'onNews'
|
'click .news': 'onNews'
|
||||||
'click .search': 'onSearch'
|
'click .search': 'onSearch'
|
||||||
'click .breadcrumbs a': 'routeLinkClick'
|
'click .breadcrumb-bar a': 'routeLinkClick'
|
||||||
|
|
||||||
# Private Methods ##############################################################################
|
# Private Methods ##############################################################################
|
||||||
|
|
||||||
|
_checkForSearchRequest: ->
|
||||||
|
params = new UrlParams search:{type:'string'}
|
||||||
|
return unless params.search?
|
||||||
|
|
||||||
|
_.delay (=> @onSearch {}, params.search), c.duration.slow
|
||||||
|
|
||||||
_refreshBreadcrumbs: ->
|
_refreshBreadcrumbs: ->
|
||||||
breadcrumbs = @model?.controller?.getBreadcrumbs()
|
breadcrumbs = @model?.controller?.getBreadcrumbs()
|
||||||
breadcrumbs ?= []
|
breadcrumbs ?= []
|
||||||
@@ -106,6 +120,23 @@ module.exports = class HeaderController extends BaseController
|
|||||||
else
|
else
|
||||||
@hide @$breadcrumbs
|
@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: ->
|
_refreshTitle: ->
|
||||||
title = @model?.controller?.getTitle()
|
title = @model?.controller?.getTitle()
|
||||||
if title
|
if title
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ html
|
|||||||
link(href="/images/favicon.png" rel="icon" type="image/png")
|
link(href="/images/favicon.png" rel="icon" type="image/png")
|
||||||
link(href="/main.css" rel="stylesheet" type="text/css" )
|
link(href="/main.css" rel="stylesheet" type="text/css" )
|
||||||
meta(charset="UTF-8")
|
meta(charset="UTF-8")
|
||||||
meta(name="viewport" content="width=480")
|
meta(name="viewport" content="user-scalable=no, width=device-width")
|
||||||
|
|
||||||
body
|
body
|
||||||
.view__feedback
|
.view__feedback
|
||||||
@@ -21,7 +21,7 @@ html
|
|||||||
.page
|
.page
|
||||||
.view__header
|
.view__header
|
||||||
|
|
||||||
.content(style="display: none")
|
.content.hidden
|
||||||
.content-loading
|
.content-loading
|
||||||
img(src="/images/wait.gif")
|
img(src="/images/wait.gif")
|
||||||
|
|
||||||
@@ -32,4 +32,6 @@ html
|
|||||||
|
|
||||||
include ../includes/_google_adsense.jade
|
include ../includes/_google_adsense.jade
|
||||||
include ../includes/_google_analytics.jade
|
include ../includes/_google_analytics.jade
|
||||||
|
include ../includes/_google_sitelinks.jade
|
||||||
|
include ../includes/_twitter_follow.jade
|
||||||
|
|
||||||
|
|||||||
@@ -36,19 +36,22 @@ html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
& > *:first-child {
|
& > *:first-child {
|
||||||
flex: 0 0 50%;
|
flex: 1 1 100%;
|
||||||
|
|
||||||
box-shadow : $size-margin-small $size-margin-small $size-margin-large $color-shadow;
|
box-shadow : $size-margin-small $size-margin-small $size-margin-large $color-shadow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.page {
|
.page {
|
||||||
margin : $size-margin-large 0;
|
|
||||||
max-width : $size-page-width;
|
max-width : $size-page-width;
|
||||||
width : 100%;
|
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;
|
background : $color-background-page;
|
||||||
box-shadow : $size-margin-small $size-margin-small $size-margin-large $color-shadow;
|
|
||||||
|
|
||||||
display : flex;
|
display : flex;
|
||||||
flex-direction : column;
|
flex-direction : column;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
.content.view__item_page
|
.content.view__item_page
|
||||||
.left
|
.left
|
||||||
.view__adsense
|
|
||||||
|
|
||||||
.right
|
.right
|
||||||
.about
|
.about
|
||||||
@@ -17,7 +16,7 @@
|
|||||||
.title
|
.title
|
||||||
a.sourceMod
|
a.sourceMod
|
||||||
.button-row
|
.button-row
|
||||||
.button.craftingPlan: .bezel: p View Crafting Plan
|
.button.craftingPlan: .bezel: p View <span class="full">Crafting </span>Plan
|
||||||
.right
|
.right
|
||||||
p Official Link:
|
p Official Link:
|
||||||
a.officialLink project page
|
a.officialLink project page
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
|
|
||||||
.button {
|
.button {
|
||||||
flex: 1 1 100%;
|
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.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
|
|
||||||
AdsenseController = require '../common/adsense/adsense_controller'
|
|
||||||
EditableFile = require '../../models/site/editable_file'
|
EditableFile = require '../../models/site/editable_file'
|
||||||
Item = require '../../models/game/item'
|
Item = require '../../models/game/item'
|
||||||
ItemGroupController = require '../common/item_group/item_group_controller'
|
ItemGroupController = require '../common/item_group/item_group_controller'
|
||||||
@@ -42,6 +41,7 @@ module.exports = class ItemPageController extends PageController
|
|||||||
@_itemSlug = options.itemSlug
|
@_itemSlug = options.itemSlug
|
||||||
@_modPack = options.modPack
|
@_modPack = options.modPack
|
||||||
@_router = options.router
|
@_router = options.router
|
||||||
|
@_triggerEditing = options.login
|
||||||
|
|
||||||
@_modPack.on c.event.change, =>
|
@_modPack.on c.event.change, =>
|
||||||
@tryRefresh()
|
@tryRefresh()
|
||||||
@@ -68,6 +68,13 @@ module.exports = class ItemPageController extends PageController
|
|||||||
$("<b>#{display.itemName}</b>")
|
$("<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: ->
|
getMetaDescription: ->
|
||||||
return null unless @_itemSlug?
|
return null unless @_itemSlug?
|
||||||
display = @_modPack.findItemDisplay @_itemSlug
|
display = @_modPack.findItemDisplay @_itemSlug
|
||||||
@@ -83,9 +90,11 @@ module.exports = class ItemPageController extends PageController
|
|||||||
|
|
||||||
# BaseController Overrides #####################################################################
|
# BaseController Overrides #####################################################################
|
||||||
|
|
||||||
onDidRender: ->
|
onDidModelChange: ->
|
||||||
@_adsenseController = @addChild AdsenseController, '.view__adsense', model:'skyscraper', router: @_router
|
@trigger c.event.change
|
||||||
|
super
|
||||||
|
|
||||||
|
onDidRender: ->
|
||||||
options = imageLoader:@_imageLoader, modPack:@_modPack, router:@_router, show:false
|
options = imageLoader:@_imageLoader, modPack:@_modPack, router:@_router, show:false
|
||||||
@_multiblockController = @addChild MultiblockViewerController, '.view__multiblock_viewer', options
|
@_multiblockController = @addChild MultiblockViewerController, '.view__multiblock_viewer', options
|
||||||
@_similarItemsController = @addChild ItemGroupController, '.view__item_group.similar', options
|
@_similarItemsController = @addChild ItemGroupController, '.view__item_group.similar', options
|
||||||
@@ -101,11 +110,12 @@ module.exports = class ItemPageController extends PageController
|
|||||||
endEditing: => @_endEditingDescription()
|
endEditing: => @_endEditingDescription()
|
||||||
enterFeedback: @_enterFeedback
|
enterFeedback: @_enterFeedback
|
||||||
|
|
||||||
@$aboutImage = @$('.about img')
|
@$aboutImage = @$('.about img')
|
||||||
@$name = @$('.about .title')
|
@$craftingPlanButton = @$('.button.craftingPlan')
|
||||||
@$officialLink = @$('.about a.officialLink')
|
@$name = @$('.about .title')
|
||||||
@$sourceModLink = @$('.about a.sourceMod')
|
@$officialLink = @$('.about a.officialLink')
|
||||||
@$aboutLinks = @$('.about .right')
|
@$sourceModLink = @$('.about a.sourceMod')
|
||||||
|
@$aboutLinks = @$('.about .right')
|
||||||
|
|
||||||
@$multiblockSection = @$('section.multiblock')
|
@$multiblockSection = @$('section.multiblock')
|
||||||
@$recipeContainer = @$('section.recipes .panel')
|
@$recipeContainer = @$('section.recipes .panel')
|
||||||
@@ -135,6 +145,15 @@ module.exports = class ItemPageController extends PageController
|
|||||||
else
|
else
|
||||||
@hide @$aboutLinks
|
@hide @$aboutLinks
|
||||||
|
|
||||||
|
if @model.item.isCraftable
|
||||||
|
@show @$craftingPlanButton
|
||||||
|
else
|
||||||
|
@hide @$craftingPlanButton
|
||||||
|
|
||||||
|
if @_triggerEditing
|
||||||
|
@_triggerEditing = false
|
||||||
|
@_descriptionController.onEditClicked {}
|
||||||
|
|
||||||
@show()
|
@show()
|
||||||
else
|
else
|
||||||
@hide()
|
@hide()
|
||||||
@@ -317,7 +336,7 @@ module.exports = class ItemPageController extends PageController
|
|||||||
item = @_modPack.findItem @_itemSlug, includeDisabled:true
|
item = @_modPack.findItem @_itemSlug, includeDisabled:true
|
||||||
if item?
|
if item?
|
||||||
if not ItemSlug.equal item.slug, @_itemSlug
|
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
|
return
|
||||||
|
|
||||||
@model.item = item
|
@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 {
|
.view__recipe_detail {
|
||||||
display : flex;
|
display : flex;
|
||||||
|
|
||||||
.input, .output{
|
.input, .output {
|
||||||
flex : 0 1 33%;
|
flex : 0 1 33%;
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
@@ -20,8 +20,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
order: 10;
|
||||||
|
}
|
||||||
|
|
||||||
.pattern {
|
.pattern {
|
||||||
flex : 0 1 33%;
|
flex : 0 1 33%;
|
||||||
|
order: 20;
|
||||||
|
|
||||||
display : flex;
|
display : flex;
|
||||||
flex-direction : column;
|
flex-direction : column;
|
||||||
@@ -36,9 +41,48 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.output {
|
||||||
|
order: 30;
|
||||||
|
}
|
||||||
|
|
||||||
&:not(:first-child) {
|
&:not(:first-child) {
|
||||||
border-top : 1px solid $color-gray-light;
|
border-top : 1px solid $color-gray-light;
|
||||||
margin-top : $size-margin-medium;
|
margin-top : $size-margin-medium;
|
||||||
padding-top : $size-margin-large;
|
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 ##############################################################################
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
//-
|
//-
|
||||||
//- Crafting Guide - item_page.jade
|
//- Crafting Guide - mod_page.jade
|
||||||
//-
|
//-
|
||||||
//- Copyright © 2014-2016 by Redwood Labs
|
//- Copyright © 2014-2016 by Redwood Labs
|
||||||
//- All rights reserved.
|
//- All rights reserved.
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
.content.view__mod_page
|
.content.view__mod_page
|
||||||
.left
|
.left
|
||||||
.view__adsense
|
|
||||||
|
|
||||||
.right
|
.right
|
||||||
.about
|
.about
|
||||||
@@ -17,8 +16,11 @@
|
|||||||
.title
|
.title
|
||||||
.author
|
.author
|
||||||
.description
|
.description
|
||||||
|
.modpack
|
||||||
|
span.checkbox
|
||||||
|
span.label I have this mod in my modpack
|
||||||
.version
|
.version
|
||||||
span in my mod pack
|
span I'm using version:
|
||||||
select
|
select
|
||||||
.warning.
|
.warning.
|
||||||
<b>PLEASE NOTE:</b> By selecting "no", crafting plans, search, and other features will ignore items
|
<b>PLEASE NOTE:</b> By selecting "no", crafting plans, search, and other features will ignore items
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Crafting Guide - item_page.scss
|
// Crafting Guide - mod_page.scss
|
||||||
//
|
//
|
||||||
// Copyright © 2014-2016 by Redwood Labs
|
// Copyright © 2014-2016 by Redwood Labs
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
@@ -49,8 +49,44 @@
|
|||||||
line-height: $font-size-medium * 1.25;
|
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 {
|
.version {
|
||||||
margin-top: $size-margin-large;
|
margin-top: $size-margin-medium;
|
||||||
|
|
||||||
font-family: $font-family-control;
|
font-family: $font-family-control;
|
||||||
font-size: $font-size-medium;
|
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.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
|
|
||||||
AdsenseController = require '../common/adsense/adsense_controller'
|
|
||||||
BaseController = require '../base_controller'
|
BaseController = require '../base_controller'
|
||||||
Item = require '../../models/game/item'
|
Item = require '../../models/game/item'
|
||||||
ItemGroupController = require '../common/item_group/item_group_controller'
|
ItemGroupController = require '../common/item_group/item_group_controller'
|
||||||
@@ -29,6 +28,14 @@ module.exports = class ModPageController extends BaseController
|
|||||||
|
|
||||||
# Event Methods ################################################################################
|
# Event Methods ################################################################################
|
||||||
|
|
||||||
|
onToggleEnabled: ->
|
||||||
|
if @model.activeVersion is Mod.Version.None
|
||||||
|
@model.activeVersion = Mod.Version.Latest
|
||||||
|
else
|
||||||
|
@model.activeVersion = Mod.Version.None
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
onVersionChanged: ->
|
onVersionChanged: ->
|
||||||
@model.activeVersion = @$versionSelector.val()
|
@model.activeVersion = @$versionSelector.val()
|
||||||
return false
|
return false
|
||||||
@@ -58,8 +65,6 @@ module.exports = class ModPageController extends BaseController
|
|||||||
# BaseController Overrides #####################################################################
|
# BaseController Overrides #####################################################################
|
||||||
|
|
||||||
onDidRender: ->
|
onDidRender: ->
|
||||||
@_adsenseController = @addChild AdsenseController, '.view__adsense', model: 'skyscraper'
|
|
||||||
|
|
||||||
@$author = @$('.about .author')
|
@$author = @$('.about .author')
|
||||||
@$description = @$('.about .description')
|
@$description = @$('.about .description')
|
||||||
@$documentationLink = @$('.about .documentation')
|
@$documentationLink = @$('.about .documentation')
|
||||||
@@ -67,15 +72,18 @@ module.exports = class ModPageController extends BaseController
|
|||||||
@$homePageLink = @$('.about .homePage')
|
@$homePageLink = @$('.about .homePage')
|
||||||
@$itemGroups = @$(".itemGroups")
|
@$itemGroups = @$(".itemGroups")
|
||||||
@$logo = @$('.about img')
|
@$logo = @$('.about img')
|
||||||
|
@$modpackSection = @$('.modpack')
|
||||||
@$title = @$('.about .title')
|
@$title = @$('.about .title')
|
||||||
@$tutorialsContainer = @$('section.tutorials .panel')
|
@$tutorialsContainer = @$('section.tutorials .panel')
|
||||||
@$tutorialsSection = @$('section.tutorials')
|
@$tutorialsSection = @$('section.tutorials')
|
||||||
|
@$versionSection = @$('.version')
|
||||||
@$versionSelector = @$('.version select')
|
@$versionSelector = @$('.version select')
|
||||||
@$warning = @$('.warning')
|
@$warning = @$('.warning')
|
||||||
super
|
super
|
||||||
|
|
||||||
refresh: ->
|
refresh: ->
|
||||||
@_refreshAboutBlock()
|
@_refreshAboutBlock()
|
||||||
|
@_refreshEnabled()
|
||||||
@_refreshItemGroups()
|
@_refreshItemGroups()
|
||||||
@_refreshTutorials()
|
@_refreshTutorials()
|
||||||
@_refreshVersionSelector()
|
@_refreshVersionSelector()
|
||||||
@@ -86,6 +94,7 @@ module.exports = class ModPageController extends BaseController
|
|||||||
events: ->
|
events: ->
|
||||||
return _.extend super,
|
return _.extend super,
|
||||||
'change .version select': 'onVersionChanged'
|
'change .version select': 'onVersionChanged'
|
||||||
|
'click .modpack': 'onToggleEnabled'
|
||||||
|
|
||||||
# Private Methods ##############################################################################
|
# Private Methods ##############################################################################
|
||||||
|
|
||||||
@@ -107,6 +116,19 @@ module.exports = class ModPageController extends BaseController
|
|||||||
@$logo.attr 'src', ''
|
@$logo.attr 'src', ''
|
||||||
@$title.text ''
|
@$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: ->
|
_refreshItemGroups: ->
|
||||||
@_groupControllers ?= []
|
@_groupControllers ?= []
|
||||||
groupIndex = 0
|
groupIndex = 0
|
||||||
@@ -124,9 +146,10 @@ module.exports = class ModPageController extends BaseController
|
|||||||
router: @_router
|
router: @_router
|
||||||
title: if group is Item.Group.Other then 'Items' else group
|
title: if group is Item.Group.Other then 'Items' else group
|
||||||
|
|
||||||
@_groupControllers.push controller
|
_.defer =>
|
||||||
@$itemGroups.append controller.$el
|
@_groupControllers.push controller
|
||||||
controller.render()
|
@$itemGroups.append controller.$el
|
||||||
|
controller.render()
|
||||||
else
|
else
|
||||||
controller.modVersion = modVersion
|
controller.modVersion = modVersion
|
||||||
controller.model = items
|
controller.model = items
|
||||||
@@ -163,19 +186,16 @@ module.exports = class ModPageController extends BaseController
|
|||||||
|
|
||||||
_refreshVersionSelector: ->
|
_refreshVersionSelector: ->
|
||||||
modVersions = @model.modVersions
|
modVersions = @model.modVersions
|
||||||
|
|
||||||
|
if (@model.activeVersion is Mod.Version.None) or modVersions.length < 2
|
||||||
|
@hide @$versionSection
|
||||||
|
else
|
||||||
|
@show @$versionSection
|
||||||
|
|
||||||
selectedModVersion = @effectiveModVersion
|
selectedModVersion = @effectiveModVersion
|
||||||
|
|
||||||
@$versionSelector.empty()
|
@$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
|
for modVersion in @model.modVersions
|
||||||
$option = $("<option value=\"#{modVersion.version}\">#{modVersion.version}</option>")
|
$option = $("<option value=\"#{modVersion.version}\">#{modVersion.version}</option>")
|
||||||
if modVersion is selectedModVersion
|
if modVersion is selectedModVersion
|
||||||
|
|||||||
@@ -7,9 +7,86 @@
|
|||||||
|
|
||||||
.content.view__news_page
|
.content.view__news_page
|
||||||
.left
|
.left
|
||||||
.view__adsense
|
|
||||||
|
|
||||||
.right
|
.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
|
section
|
||||||
h3 2016-04-05
|
h3 2016-04-05
|
||||||
.panel
|
.panel
|
||||||
@@ -79,54 +156,3 @@
|
|||||||
p.
|
p.
|
||||||
With many thanks to <a href="https://github.com/pkmnfrk">Mike Caron</a>, I'm pleased to announce
|
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>!
|
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.
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user