-- | -- Module: Yesod.TableView -- Copyright: (c) 2010 Ertugrul Soeylemez -- License: BSD3 -- Maintainer: Ertugrul Soeylemez -- Stability: experimental -- -- Table-like view for tabular data. {-# LANGUAGE FlexibleContexts, ScopedTypeVariables, TemplateHaskell #-} module Yesod.TableView ( -- Table view TableView(..), defTableView, tableView, -- * Reexports module Yesod.TableView.Widget ) where import Control.Monad import Text.Cassius import Text.Hamlet import Yesod import Yesod.TableView.NumEntriesForm import Yesod.TableView.Widget -- | Table view settings. Defaults are given in parentheses. data TableView s val = TableView { -- Filter to use (@[]@). tableFilter :: [Filter val], -- ^ Table filter. tableId :: String, -- ^ HTML table id. tableOrder :: [Order val], -- ^ Table sorting order. tableRoute :: Int -> Int -> Route s, -- ^ Table route. tableShowHead :: Bool, -- ^ Show table header? tableStyled :: Bool, -- ^ Add CSS styles? -- Limits. tableCurrentLimit :: Int, -- ^ Current pager limit. tableCurrentOffset :: Int, -- ^ Current offset. tableLimitPrompt :: String, -- ^ Prompt in limit form. tableLimits :: [Int], -- ^ Selectable limits (@[10, 20, 50, 100]@). tableMinLimit :: Maybe Int, -- ^ Minimum pager limit (@Just 10@). tableMaxLimit :: Maybe Int -- ^ Maximum pager limit (@Just 100@). } -- | Default values for most fields. The following fields will be left -- undefined: 'tableId', 'tableRoute', 'tableCurrentLimit' and -- 'tableCurrentOffset'. defTableView :: TableView s val defTableView = TableView { tableFilter = [], tableId = undefined, 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 } clamp :: Ord a => Maybe a -> Maybe a -> a -> a clamp mMin mMax = maybe id max mMin . maybe id min mMax tableView :: forall s sub val. ( PersistBackend (YesodDB s (GGHandler sub s IO)), PersistEntity val, TableViewWidget val, YesodPersist s) => TableView s val -> GHandler sub s (GWidget sub s ()) tableView cfg'@(TableView { tableFilter = filters, 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 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)) -> GWidget sub s () 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")