92 lines
3.2 KiB
CoffeeScript
92 lines
3.2 KiB
CoffeeScript
|
|
||
|
module.exports = (env, callback) ->
|
||
|
### Paginator plugin. Defaults can be overridden in config.json
|
||
|
e.g. "paginator": {"perPage": 10} ###
|
||
|
|
||
|
defaults =
|
||
|
template: 'index.jade' # template that renders pages
|
||
|
articles: 'articles' # directory containing contents to paginate
|
||
|
first: 'index.html' # filename/url for first page
|
||
|
filename: 'page/%d/index.html' # filename for rest of pages
|
||
|
perPage: 2 # number of articles per page
|
||
|
|
||
|
# assign defaults any option not set in the config file
|
||
|
options = env.config.paginator or {}
|
||
|
for key, value of defaults
|
||
|
options[key] ?= defaults[key]
|
||
|
|
||
|
getArticles = (contents) ->
|
||
|
# helper that returns a list of articles found in *contents*
|
||
|
# note that each article is assumed to have its own directory in the articles directory
|
||
|
articles = contents[options.articles]._.directories.map (item) -> item.index
|
||
|
# skip articles that does not have a template associated
|
||
|
articles = articles.filter (item) -> item.template isnt 'none'
|
||
|
# sort article by date
|
||
|
articles.sort (a, b) -> b.date - a.date
|
||
|
return articles
|
||
|
|
||
|
class PaginatorPage extends env.plugins.Page
|
||
|
### A page has a number and a list of articles ###
|
||
|
|
||
|
constructor: (@pageNum, @articles) ->
|
||
|
|
||
|
getFilename: ->
|
||
|
if @pageNum is 1
|
||
|
options.first
|
||
|
else
|
||
|
options.filename.replace '%d', @pageNum
|
||
|
|
||
|
getView: -> (env, locals, contents, templates, callback) ->
|
||
|
# simple view to pass articles and pagenum to the paginator template
|
||
|
# note that this function returns a funciton
|
||
|
|
||
|
# get the pagination template
|
||
|
template = templates[options.template]
|
||
|
if not template?
|
||
|
return callback new Error "unknown paginator template '#{ options.template }'"
|
||
|
|
||
|
# setup the template context
|
||
|
ctx = {@articles, @pageNum, @prevPage, @nextPage}
|
||
|
|
||
|
# extend the template context with the enviroment locals
|
||
|
env.utils.extend ctx, locals
|
||
|
|
||
|
# finally render the template
|
||
|
template.render ctx, callback
|
||
|
|
||
|
# register a generator, 'paginator' here is the content group generated content will belong to
|
||
|
# i.e. contents._.paginator
|
||
|
env.registerGenerator 'paginator', (contents, callback) ->
|
||
|
|
||
|
# find all articles
|
||
|
articles = getArticles contents
|
||
|
|
||
|
# populate pages
|
||
|
numPages = Math.ceil articles.length / options.perPage
|
||
|
pages = []
|
||
|
for i in [0...numPages]
|
||
|
pageArticles = articles.slice i * options.perPage, (i + 1) * options.perPage
|
||
|
pages.push new PaginatorPage i + 1, pageArticles
|
||
|
|
||
|
# add references to prev/next to each page
|
||
|
for page, i in pages
|
||
|
page.prevPage = pages[i - 1]
|
||
|
page.nextPage = pages[i + 1]
|
||
|
|
||
|
# create the object that will be merged with the content tree (contents)
|
||
|
# do _not_ modify the tree directly inside a generator, consider it read-only
|
||
|
rv = {pages:{}}
|
||
|
for page in pages
|
||
|
rv.pages["#{ page.pageNum }.page"] = page # file extension is arbitrary
|
||
|
rv['index.page'] = pages[0] # alias for first page
|
||
|
rv['last.page'] = pages[(numPages-1)] # alias for last page
|
||
|
|
||
|
# callback with the generated contents
|
||
|
callback null, rv
|
||
|
|
||
|
# add the article helper to the environment so we can use it later
|
||
|
env.helpers.getArticles = getArticles
|
||
|
|
||
|
# tell the plugin manager we are done
|
||
|
callback()
|