module Yesod.TableView
(
TableView(..),
defTableView,
makeTableView,
tableView,
module Yesod.TableView.Widget
)
where
import Control.Monad
import Text.Cassius
import Text.Hamlet
import Yesod
import Yesod.TableView.NumEntriesForm
import Yesod.TableView.Widget
data TableView val =
TableView {
tableFilter :: [Filter val],
tableId :: Maybe String,
tableOrder :: [Order val],
tableRoute :: Int -> Int ->
Route (TableSite val),
tableShowHead :: Bool,
tableStyled :: Bool,
tableCurrentLimit :: Int,
tableCurrentOffset :: Int,
tableLimitPrompt :: String,
tableLimits :: [Int],
tableMinLimit :: Maybe Int,
tableMaxLimit :: Maybe Int
}
clamp :: Ord a => Maybe a -> Maybe a -> a -> a
clamp mMin mMax = maybe id max mMin . maybe id min mMax
defTableView :: TableView val
defTableView =
TableView { tableFilter = [],
tableId = Nothing,
tableOrder = [],
tableRoute = undefined,
tableShowHead = True,
tableStyled = True,
tableCurrentLimit = undefined,
tableCurrentOffset = undefined,
tableLimitPrompt = "Number of entries per page:",
tableLimits = [10, 20, 50, 100],
tableMinLimit = Just 10,
tableMaxLimit = Just 100 }
makeTableView :: [Filter val] -> [Order val] -> Int -> Int ->
(Int -> Int -> Route (TableSite val)) ->
TableView val
makeTableView filters orders limit offset route =
defTableView { tableFilter = filters,
tableOrder = orders,
tableRoute = route,
tableCurrentLimit = limit,
tableCurrentOffset = offset }
tableView :: forall val.
( PersistBackend (YesodDB (TableSite val) (GTableHandler val IO)),
PersistEntity val,
TableViewWidget val,
YesodPersist (TableSite val)) =>
TableView val -> TableHandler val (TableWidget val ())
tableView cfg'@(TableView {
tableFilter = filters,
tableId = mTableId,
tableOrder = orders,
tableLimitPrompt = limitPrompt,
tableLimits = limitOpts,
tableRoute = thisRoute,
tableShowHead = showHead,
tableStyled = styled,
tableCurrentLimit = limit',
tableCurrentOffset = offset',
tableMinLimit = minLimit,
tableMaxLimit = maxLimit
}) = do
let minOffset = Just 0
maxOffset = Nothing
let limit = clamp minLimit maxLimit limit'
offset = clamp minOffset maxOffset offset'
prevOffset = clamp minOffset maxOffset (offset limit)
nextOffset = clamp minOffset maxOffset (offset + limit)
(entries, numEntries) <-
runDB $ liftM2 (,) (selectList filters orders limit offset) (count filters)
numEntriesWidget <- runNumEntriesForm
styled limitPrompt limitOpts limit (`thisRoute` offset)
let lastOffset = (numEntries 1) `div` limit * limit
tableId <- maybe newIdent return mTableId
return $ do
let entryRows = mapM_ row (zip [0..] entries)
firstRoute = guard (offset > 0) >> Just (thisRoute limit 0)
lastRoute = guard (offset < lastOffset) >>
Just (thisRoute limit lastOffset)
forwardRoute = guard (nextOffset < numEntries) >>
Just (thisRoute limit nextOffset)
backRoute = guard (offset > 0) >>
Just (thisRoute limit prevOffset)
mHeader = guard showHead >> Just (tableHeader (undefined :: val))
when styled $ addCassius $(cassiusFile "templates/tableview.cassius")
addWidget $(hamletFile "templates/tableview.hamlet")
where
row :: (Int, (Key val, val)) -> TableWidget val ()
row (ix, (entryId, entry)) =
let rowClass = if even ix then "even-row" else "odd-row"
entryWidget = tableRecord ix entryId entry
in addWidget $(hamletFile "templates/tableview-row.hamlet")