packages feed

yesod-paginator 0.2.1 → 0.2.2.1

raw patch · 3 files changed

+151/−128 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Yesod.Paginator.Widget: getCurrentPage :: GHandler s m Int
+ Yesod.Paginator.Widget: paginationWidget :: Int -> Int -> Int -> GWidget s m ()

Files

Yesod/Paginator.hs view
@@ -11,13 +11,41 @@ -- But uses an entirely different approach. -- -- There are two pagination functions. One for arbitrary items where you--- provide the list of things to be paginated, and one for paginating--- directly out of the database, you provide the same filters as you--- would to @selectList@.+-- provide the list of things to be paginated: --+-- > getSomeRoute = do+-- >     things' <- getAllThings+-- >+-- >     (things, widget) <- paginate 10 things'+-- >+-- >     defaultLayout $ do+-- >         [whamlet|+-- >             $forall thing <- things+-- >                 ^{showThing thing}+-- >+-- >             <div .pagination>+-- >                  ^{widget}+-- >             |]+--+-- And another for paginating directly out of the database, you provide+-- the same filters as you would to @selectList@.+--+-- > getSomeRoute something = do+-- >     -- note: things is [Entity val] just like selectList returns+-- >     (things, widget) <- runDB $ selectPaginated 10 [SomeThing ==. something] []+-- >+-- >     defaultLayout $ do+-- >         [whamlet|+-- >             $forall thing <- things+-- >                 ^{showThing $ entityVal thing}+-- >+-- >             <div .pagination>+-- >                  ^{widget}+-- >             |]+-- -- Both functions return a tuple: the first element being the list of--- items to display on this page and the second being a widget showing--- the pagination navagation links.+-- items (or Entities) to display on this page and the second being a+-- widget showing the pagination navagation links. -- ------------------------------------------------------------------------------- module Yesod.Paginator@@ -26,32 +54,11 @@     , paginationWidget     ) where -import Yesod -- TODO: minimal deps-import Control.Monad (when)+import Yesod+import Yesod.Paginator.Widget import Control.Monad.Trans.Class (MonadTrans)-import Data.Text     (Text)-import Data.Maybe    (fromMaybe)-import qualified Data.Text as T --- | Paginate an existing list of items.------   > getSomeRoute = do---   >     things' <- getAllThings---   >---   >     (things, widget) <- paginate 10 things'---   >---   >     defaultLayout $ do---   >         [whamlet|---   >             $forall thing <- things---   >                 ^{showThing thing}---   >---   >             <div .pagination>---   >                  ^{widget}---   >             |]----paginate :: Int -- ^ items per page-         -> [a] -- ^ complete list of items-         -> GHandler s m ([a], GWidget s m ())+paginate :: Int -> [a] -> GHandler s m ([a], GWidget s m ()) paginate per items = do     p <- getCurrentPage @@ -60,25 +67,10 @@      return (xs, paginationWidget p per tot) --- | Paginate directly out of the database.------   > getSomeRoute something = do---   >     -- note: things is [Entity val] just like selectList returns---   >     (things, widget) <- runDB $ selectPaginated 10 [SomeThing ==. something] []---   >---   >     defaultLayout $ do---   >         [whamlet|---   >             $forall thing <- things---   >                 ^{showThing $ entityVal thing}---   >---   >             <div .pagination>---   >                  ^{widget}---   >             |]--- selectPaginated :: ( MonadTrans (PersistEntityBackend v)                    , PersistEntity v                    , PersistQuery (PersistEntityBackend v) (GHandler s m))-                => Int-> [Filter v] -> [SelectOpt v]+                => Int -> [Filter v] -> [SelectOpt v]                 -> PersistEntityBackend v (GHandler s m) ([Entity v], GWidget s1 m1 ()) selectPaginated per filters selectOpts = do     p   <- lift getCurrentPage@@ -86,85 +78,3 @@     xs  <- selectList filters (selectOpts ++ [OffsetBy ((p-1)*per), LimitTo per])      return (xs, paginationWidget p per tot)---- | A widget showing pagination links. Follows bootstrap principles.---   Utilizes a \"p\" GET param but leaves all other GET params intact.-paginationWidget :: Int -- ^ current page-                 -> Int -- ^ items per page-                 -> Int -- ^ total number of items-                 -> GWidget s m ()-paginationWidget page per tot = do-    -- total / per + 1 for any remainder-    let pages = (\(n, r) -> n + (min r 1)) $ tot `divMod` per--    when (pages > 1) $ do-        let prev = [1       ..(page-1)]-        let next = [(page+1)..pages   ]--        let lim = 9 -- don't show more than nine links on either side-        let prev' = if length prev > lim then drop ((length prev) - lim) prev else prev-        let next' = if length next > lim then take lim next else next--        curParams <- lift $ fmap reqGetParams getRequest--        [whamlet|-            <ul>-                ^{linkToDisabled (null prev) curParams (page - 1) "← Previous"}--                $if (/=) prev prev'-                    <li>^{linkTo curParams 1 "1"}-                    <li>-                        <a>...--                $forall p <- prev'-                    <li>^{linkTo curParams p (show p)}--                <li .active>-                    <a>#{show page}--                $forall n <- next'-                    <li>^{linkTo curParams n (show n)}--                $if (/=) next next'-                    <li>-                        <a>...-                    <li>^{linkTo curParams pages (show pages)}--                ^{linkToDisabled (null next) curParams (page + 1) "Next →"}-            |]---- | looks up the \"p\" GET param and converts it to an Int. returns a---   default of 1 when conversion fails.-getCurrentPage :: GHandler s m Int-getCurrentPage = fmap (fromMaybe 1 . go) $ lookupGetParam "p"--    where-        go :: Maybe Text -> Maybe Int-        go mp = readIntegral . T.unpack =<< mp--updateGetParam :: [(Text,Text)] -> (Text,Text) -> Text-updateGetParam getParams (p, n) = (T.cons '?') . T.intercalate "&"-                                . map (\(k,v) -> k `T.append` "=" `T.append` v)-                                . (++ [(p, n)]) . filter ((/= p) . fst) $ getParams--linkTo :: [(Text,Text)] -> Int -> String -> GWidget s m ()-linkTo params pg txt = do-    let param = ("p", T.pack $ show pg)--    [whamlet|-        <a href="#{updateGetParam params param}">#{txt}-        |]---- | Similiar, but used for Previous/Next so that there's no href when---   disabled-linkToDisabled :: Bool -- ^ disabled?-               -> [(Text,Text)] -> Int -> String -> GWidget s m ()-linkToDisabled True _ _ txt = [whamlet|-    <li .prev .disabled>-        <a>#{txt}-    |]--linkToDisabled _ params pg txt = [whamlet|-    <li .prev>-        ^{linkTo params pg txt}-    |]
+ Yesod/Paginator/Widget.hs view
@@ -0,0 +1,112 @@+{-# LANGUAGE QuasiQuotes       #-}+{-# LANGUAGE OverloadedStrings #-}+module Yesod.Paginator.Widget+ ( getCurrentPage  + , paginationWidget+ ) where++import Yesod++import Control.Monad (when)+import Data.Maybe    (fromMaybe)+import Data.Text     (Text)+import qualified Data.Text as T++-- | Individual links to pages need to follow strict (but sane) markup+--   to be styled correctly by bootstrap. This type allows construction+--   of such links in both enabled and disabled states.+data PageLink = Enabled Int String String -- ^ page, content, class+              | Disabled    String String -- ^ content, class++-- | Correctly show one of the constructed links+showLink :: [(Text, Text)] -> PageLink -> GWidget s m ()+showLink params (Enabled pg cnt cls) = do+    let param = ("p", T.pack . show $ pg)++    [whamlet|+        <li .#{cls}>+            <a href="#{updateGetParam params param}">#{cnt}+        |]++    where+        updateGetParam :: [(Text,Text)] -> (Text,Text) -> Text+        updateGetParam getParams (p, n) = (T.cons '?') . T.intercalate "&"+                                        . map (\(k,v) -> k `T.append` "=" `T.append` v)+                                        . (++ [(p, n)]) . filter ((/= p) . fst) $ getParams++showLink _ (Disabled cnt cls) =+    [whamlet|+        <li .#{cls} .disabled>+            <a>#{cnt}+        |]++-- | A widget showing pagination links. Follows bootstrap principles.+--   Utilizes a \"p\" GET param but leaves all other GET params intact.+paginationWidget :: Int -- ^ current page+                 -> Int -- ^ items per page+                 -> Int -- ^ total number of items+                 -> GWidget s m ()+paginationWidget page per tot = do+    -- total / per + 1 for any remainder+    let pages = (\(n, r) -> n + (min r 1)) $ tot `divMod` per++    when (pages > 1) $ do+        curParams <- lift $ fmap reqGetParams getRequest++        [whamlet|+            <ul>+                $forall link <- buildLinks page pages+                    ^{showLink curParams link}+            |]++    where+        -- | Build up each component of the overall list of links. We'll+        --   use empty lists to denote ommissions along the way then+        --   concatenate.+        buildLinks :: Int -> Int -> [PageLink]+        buildLinks pg pgs =+            let prev = [1      .. pg - 1]+                next = [pg + 1 .. pgs   ]++                -- these always appear+                prevLink = [(if null prev then Disabled else Enabled (pg - 1)) "«" "prev"]+                nextLink = [(if null next then Disabled else Enabled (pg + 1)) "»" "next"]++                -- show first/last unless we're on it+                firstLink = [ Enabled 1   "1"        "prev" | pg > 1   ]+                lastLink  = [ Enabled pgs (show pgs) "next" | pg < pgs ]++                lim = 9++                -- we'll show ellipsis if there are enough links that some will+                -- be ommitted from the list+                prevEllipsis = [ Disabled "..." "prev" | length prev > lim + 1 ]+                nextEllipsis = [ Disabled "..." "next" | length next > lim + 1 ]++                -- the middle lists, strip the first/last pages and+                -- correctly take up to limit away from current+                prevLinks = reverse . take lim . reverse . drop 1 $ map (\p -> Enabled p (show p) "prev") prev+                nextLinks = take lim . reverse . drop 1 . reverse $ map (\p -> Enabled p (show p) "next") next++                -- finally, this page itself+                curLink = [Disabled (show pg) "active"]++            in concat [ prevLink+                      , firstLink+                      , prevEllipsis+                      , prevLinks+                      , curLink+                      , nextLinks+                      , nextEllipsis+                      , lastLink+                      , nextLink+                      ]++-- | looks up the \"p\" GET param and converts it to an Int. returns a+--   default of 1 when conversion fails.+getCurrentPage :: GHandler s m Int+getCurrentPage = fmap (fromMaybe 1 . go) $ lookupGetParam "p"++    where+        go :: Maybe Text -> Maybe Int+        go mp = readIntegral . T.unpack =<< mp
yesod-paginator.cabal view
@@ -1,5 +1,5 @@ name:                yesod-paginator-version:             0.2.1+version:             0.2.2.1 synopsis:            A pagination approach for yesod description:         Paginate a list showing a per-item widget and links to other pages homepage:            http://github.com/pbrisbin/yesod-paginator@@ -13,6 +13,7 @@  library   exposed-modules: Yesod.Paginator+                   Yesod.Paginator.Widget    build-depends: base       >= 4    && < 5                , text       >= 0.11 && < 0.12