1 | fs = require 'fs'
|
2 | _ = require 'underscore'
|
3 | async = require 'async'
|
4 |
|
5 | Watcher = require './watcher'
|
6 | Finder = require './finder'
|
7 | Server = require './server'
|
8 |
|
9 | class Site
|
10 | constructor: ( @root=process.cwd() ) ->
|
11 | @config = Config
|
12 | @info = _.inject( Site.KINDS, (( h, k ) -> h[k] = {}; h ), {} )
|
13 | Logger.debug "SITE #{@}"
|
14 | determineIndex: () ->
|
15 | if @config.index?
|
16 | if (item = @info.pages[@config.index])?
|
17 | item.index = true
|
18 | Logger.debug "As index: #{item.kind}/#{item.permalink}"
|
19 | else
|
20 |
|
21 | newestThing = _.reject( @posts(), (p) -> p.draft )[0]
|
22 | newestThing.index = true
|
23 | Logger.debug "As index: #{newestThing.kind}/#{newestThing.permalink}"
|
24 | populateInfo: ( kind, items ) ->
|
25 | items.forEach ( item ) => @info[kind][item.permalink] = item
|
26 | renderAll: ( kind, cb ) ->
|
27 | renderTasks = []
|
28 | for permalink, item of @info[kind]
|
29 | renderTasks.push( { item: item, fn: ( item ) -> ( cb ) -> item.render( cb ) } )
|
30 |
|
31 | renderFuncs = _.map( renderTasks, ( task ) -> task.fn(task.item) )
|
32 | async.parallel( renderFuncs, cb )
|
33 | watchContent: () ->
|
34 | again = @watchContent
|
35 | Site.WATCH_KINDS.forEach ( kind ) =>
|
36 | for permalink, item of @info[kind]
|
37 | toWatch = "_#{item.kind}s/#{item.srcPath}"
|
38 | Watcher.onChange toWatch, "#{@root}/#{toWatch}", (( itemToProcess ) ->
|
39 | () ->
|
40 | itemToProcess.process ( err, processed ) ->
|
41 | if err
|
42 | Logger.error "Could not re-process watched #{itemToProcess.kind}, #{err}"
|
43 | return
|
44 |
|
45 | itemToProcess.render ( err ) =>
|
46 | if err
|
47 | Logger.error "Clould not re-render watched #{itemToProcess.kind}, #{err}"
|
48 | return
|
49 | )(item)
|
50 | processContent: ( kind, cb ) ->
|
51 | cb ?= ( err ) -> Logger.error( "Could not reload content! #{err}" ) if err
|
52 | new Finder @, kind, ( err, items ) =>
|
53 | @populateInfo( kind, items )
|
54 | @determineIndex()
|
55 | cb( err )
|
56 | processStyles: ( cb ) ->
|
57 | new Finder @, 'styles', ( err, styles ) =>
|
58 | @populateInfo( 'styles', styles )
|
59 | @renderAll( 'styles', cb )
|
60 |
|
61 | compileScripts: ( cb ) ->
|
62 | new Finder @, 'scripts', ( err, scripts ) =>
|
63 | @populateInfo( 'scripts', scripts )
|
64 | @renderAll( 'scripts', cb )
|
65 | copyStatics: ( cb ) ->
|
66 | new Finder @, 'statics', ( err, statics ) =>
|
67 | @populateInfo( 'statics', statics )
|
68 | @renderAll( 'statics', cb )
|
69 | posts: () ->
|
70 | _(@info.posts).chain()
|
71 | .values()
|
72 | .sortBy( (v) -> return v.timestamp )
|
73 | .reverse()
|
74 | .value()
|
75 | pages: () ->
|
76 | _(@info.pages).values()
|
77 | build: ( cb ) ->
|
78 | cb ?= ( err ) ->
|
79 | if err
|
80 | Logger.error "Site build failed! #{e}"
|
81 | return
|
82 | else
|
83 | Logger.info "Build complete."
|
84 | s = @
|
85 | async.parallel(
|
86 | [
|
87 | ( cb ) ->
|
88 | s.processContent 'posts', ( err ) ->
|
89 | cb( err, 'posts' )
|
90 | ( cb ) ->
|
91 | s.processContent 'pages', ( err ) ->
|
92 | cb( err, 'pages' )
|
93 | ( cb ) ->
|
94 | s.processStyles ( err ) ->
|
95 | cb( err, 'styles' )
|
96 | ( cb ) ->
|
97 | s.compileScripts ( err ) ->
|
98 | cb( err, 'scripts' )
|
99 | ( cb ) ->
|
100 | s.copyStatics ( err ) ->
|
101 | cb( err, 'statics' )
|
102 | ],
|
103 | ( err, loaded ) ->
|
104 | async.parallel(
|
105 | [
|
106 | ( cb ) -> s.renderAll( 'posts', cb )
|
107 | ( cb ) -> s.renderAll( 'pages', cb )
|
108 | ],
|
109 | cb
|
110 | )
|
111 | )
|
112 | developmentMode: () ->
|
113 | @build ( err ) =>
|
114 | site = @
|
115 | if err
|
116 | Logger.error err
|
117 | return
|
118 | else
|
119 | Logger.info "Initial build complete!"
|
120 | @watchContent()
|
121 |
|
122 |
|
123 | fs.readdir @root, ( err, items ) ->
|
124 | items.forEach ( item ) ->
|
125 | return unless item.match( /^_/ )
|
126 | Watcher.onChange item, () ->
|
127 | site.build( () ->
|
128 | site.watchContent()
|
129 | )
|
130 |
|
131 | Watcher.onChange 'config.coffee', () ->
|
132 | site.config._reload()
|
133 | site.build()
|
134 | Watcher.onChange '_inc/layout.jade', () ->
|
135 | site.build()
|
136 |
|
137 | Site.WATCH_KINDS = [ 'pages', 'posts', 'styles', 'scripts' ]
|
138 | Site.KINDS = _.clone( Site.WATCH_KINDS ).concat( ['statics'] )
|
139 |
|
140 | module.exports = Site
|