{-# LANGUAGE QuasiQuotes, TemplateHaskell, CPP, TypeFamilies, FlexibleInstances, MultiParamTypeClasses, FlexibleContexts #-}
-- | Provides a pagination subsite for Yesod.
--
-- Route layout:
--
-- > / PaginateHomeR GET
-- > /#Int PaginateStartR GET
-- > /#Int/#Int PaginateR GET
--
-- If no numbers are given, display the items starting from the beginning with the default count. If one number is given,
-- display the items starting from that index with the default count. If two numbers are given, the first one is the count
-- and the second is the starting index. (This is so the user can modify the end of the URL to move forward in the pagination.)
module Yesod.Paginate
( Paginate (..)
, PaginateRoute (..)
, defaultPaginate
, prevLink
, nextLink
)
where
import Yesod
import Control.Applicative
import Language.Haskell.TH.Syntax
data Paginate master rep a = Paginate
{ pgnDefaultCount :: Int -- ^ How many items to show per page by default
, pgnGetItems :: Int -> Int -> GHandler (Paginate master rep a) master [a] -- ^ Get a certain count of items at a certain offset
, pgnItemCount :: GHandler (Paginate master rep a) master Int -- ^ How many items there are in all
, pgnDisplayItems :: Int -> Int -> [a] -> GHandler (Paginate master rep a) master rep -- ^ Render the items on a page given the count and offset
}
mkYesodSub
"Paginate master rep a"
[ ClassP ''Yesod [VarT $ mkName "master"]
, ClassP ''HasReps [VarT $ mkName "rep"]
]
#if GHC7
[parseRoutes|
#else
[$parseRoutes|
#endif
/ PaginateHomeR GET
/#Int PaginateStartR GET
/#Int/#Int PaginateR GET
|]
getPaginateHomeR :: GHandler (Paginate master rep a) master rep
getPaginateHomeR = do
pgn <- getYesodSub
toMaster <- getRouteToMaster
redirect RedirectSeeOther (toMaster (PaginateR (pgnDefaultCount pgn) 0))
getPaginateStartR :: Int -> GHandler (Paginate master rep a) master rep
getPaginateStartR start = do
pgn <- getYesodSub
toMaster <- getRouteToMaster
redirect RedirectSeeOther (toMaster (PaginateR (pgnDefaultCount pgn) start))
getPaginateR :: Int -> Int -> GHandler (Paginate master rep a) master rep
getPaginateR howmany start = do
pgn <- getYesodSub
xs <- pgnGetItems pgn howmany start
pgnDisplayItems pgn howmany start xs
defaultPaginate
:: (YesodPersist master, PersistBackend (YesodDB master (GHandler (Paginate master rep a) master)), PersistEntity a)
=> Int -- ^ Default number of items to show
-> [Filter a] -- ^ Filters to apply
-> [Order a] -- ^ Ordering to apply
-> (Int -> Int -> [a] -> GHandler (Paginate master rep a) master rep) -- ^ Display function
-> Paginate master rep a
defaultPaginate x fs os d = Paginate
{ pgnDefaultCount = x
, pgnGetItems = \y z -> map snd <$> runDB (selectList fs os y z)
, pgnItemCount = runDB (count fs)
, pgnDisplayItems = d
}
-- | Link to the previous page.
prevLink :: Paginate master rep a -> Int -> Int -> Maybe (Route (Paginate master rep a))
prevLink p howmany start
| start > 0 = Just (PaginateR howmany (max 0 (start-howmany)))
| otherwise = Nothing
-- | Link to the next page.
nextLink :: Paginate master rep a -> Int -> Int -> GHandler (Paginate master rep a) master (Maybe (Route (Paginate master rep a)))
nextLink p howmany start = go <$> pgnItemCount p where
go l | start < l-howmany-1 = Just (PaginateR howmany (start+howmany))
| otherwise = Nothing