1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
--------------------------------------------------------------------------------
{-# LANGUAGE OverloadedStrings #-}
module Hakyll.Web.Paginate
( PageNumber
, Paginate (..)
, buildPaginateWith
, paginateEvery
, paginateRules
, paginateContext
) where
--------------------------------------------------------------------------------
import Control.Monad (forM_)
import qualified Data.Map as M
import Data.Monoid (mconcat)
import qualified Data.Set as S
--------------------------------------------------------------------------------
import Hakyll.Core.Compiler
import Hakyll.Core.Identifier
import Hakyll.Core.Identifier.Pattern
import Hakyll.Core.Item
import Hakyll.Core.Metadata
import Hakyll.Core.Rules
import Hakyll.Web.Html
import Hakyll.Web.Template.Context
--------------------------------------------------------------------------------
type PageNumber = Int
--------------------------------------------------------------------------------
-- | Data about paginators
data Paginate = Paginate
{ paginateMap :: M.Map PageNumber [Identifier]
, paginateMakeId :: PageNumber -> Identifier
, paginateDependency :: Dependency
} deriving (Show)
--------------------------------------------------------------------------------
paginateNumPages :: Paginate -> Int
paginateNumPages = M.size . paginateMap
--------------------------------------------------------------------------------
paginateEvery :: Int -> [a] -> [[a]]
paginateEvery n = go
where
go [] = []
go xs = let (y, ys) = splitAt n xs in y : go ys
--------------------------------------------------------------------------------
buildPaginateWith
:: MonadMetadata m
=> ([Identifier] -> m [[Identifier]]) -- ^ Group items into pages
-> Pattern -- ^ Select items to paginate
-> (PageNumber -> Identifier) -- ^ Identifiers for the pages
-> m Paginate
buildPaginateWith grouper pattern makeId = do
ids <- getMatches pattern
idGroups <- grouper ids
let idsSet = S.fromList ids
return Paginate
{ paginateMap = M.fromList (zip [1 ..] idGroups)
, paginateMakeId = makeId
, paginateDependency = PatternDependency pattern idsSet
}
--------------------------------------------------------------------------------
paginateRules :: Paginate -> (PageNumber -> Pattern -> Rules ()) -> Rules ()
paginateRules paginator rules =
forM_ (M.toList $ paginateMap paginator) $ \(idx, identifiers) ->
rulesExtraDependencies [paginateDependency paginator] $
create [paginateMakeId paginator idx] $
rules idx $ fromList identifiers
--------------------------------------------------------------------------------
-- | Get the identifier for a certain page by passing in the page number.
paginatePage :: Paginate -> PageNumber -> Maybe Identifier
paginatePage pag pageNumber
| pageNumber < 1 = Nothing
| pageNumber > (paginateNumPages pag) = Nothing
| otherwise = Just $ paginateMakeId pag pageNumber
--------------------------------------------------------------------------------
-- | A default paginate context which provides the following keys:
--
--
paginateContext :: Paginate -> PageNumber -> Context a
paginateContext pag currentPage = mconcat
[ field "firstPageNum" $ \_ -> otherPage 1 >>= num
, field "firstPageUrl" $ \_ -> otherPage 1 >>= url
, field "previousPageNum" $ \_ -> otherPage (currentPage - 1) >>= num
, field "previousPageUrl" $ \_ -> otherPage (currentPage - 1) >>= url
, field "nextPageNum" $ \_ -> otherPage (currentPage + 1) >>= num
, field "nextPageUrl" $ \_ -> otherPage (currentPage + 1) >>= url
, field "lastPageNum" $ \_ -> otherPage lastPage >>= num
, field "lastPageUrl" $ \_ -> otherPage lastPage >>= url
, field "currentPageNum" $ \i -> thisPage i >>= num
, field "currentPageUrl" $ \i -> thisPage i >>= url
, constField "numPages" $ show $ paginateNumPages pag
]
where
lastPage = paginateNumPages pag
thisPage i = return (currentPage, itemIdentifier i)
otherPage n
| n == currentPage = fail $ "This is the current page: " ++ show n
| otherwise = case paginatePage pag n of
Nothing -> fail $ "No such page: " ++ show n
Just i -> return (n, i)
num :: (Int, Identifier) -> Compiler String
num = return . show . fst
url :: (Int, Identifier) -> Compiler String
url (n, i) = getRoute i >>= \mbR -> case mbR of
Just r -> return $ toUrl r
Nothing -> fail $ "No URL for page: " ++ show n
|