--------------------------------------------------------------------------------
-- | Provides an easy way to combine several items in a list. The applications
-- are obvious:
--
-- * A post list on a blog
--
-- * An image list in a gallery
--
-- * A sitemap
{-# LANGUAGE CPP           #-}
{-# LANGUAGE TupleSections #-}
module Hakyll.Web.Template.List
    ( applyTemplateList
    , applyJoinTemplateList
    , chronological
    , recentFirst
    , sortChronological
    , sortRecentFirst
    ) where


--------------------------------------------------------------------------------
import           Control.Monad               (liftM)
#if !MIN_VERSION_base(4,13,0)
import           Control.Monad.Fail          (MonadFail)
#endif
import           Data.List                   (intersperse, sortBy)
import           Data.Ord                    (comparing)
import           Data.Time.Locale.Compat     (defaultTimeLocale)


--------------------------------------------------------------------------------
import           Hakyll.Core.Compiler
import           Hakyll.Core.Identifier
import           Hakyll.Core.Item
import           Hakyll.Core.Metadata
import           Hakyll.Web.Template
import           Hakyll.Web.Template.Context


--------------------------------------------------------------------------------
-- | Generate a string of a listing of pages, after applying a template to each
-- page.
applyTemplateList :: Template
                  -> Context a
                  -> [Item a]
                  -> Compiler String
applyTemplateList :: forall a. Template -> Context a -> [Item a] -> Compiler String
applyTemplateList = forall a.
String -> Template -> Context a -> [Item a] -> Compiler String
applyJoinTemplateList String
""


--------------------------------------------------------------------------------
-- | Join a listing of pages with a string in between, after applying a template
-- to each page.
applyJoinTemplateList :: String
                      -> Template
                      -> Context a
                      -> [Item a]
                      -> Compiler String
applyJoinTemplateList :: forall a.
String -> Template -> Context a -> [Item a] -> Compiler String
applyJoinTemplateList String
delimiter Template
tpl Context a
context [Item a]
items = do
    [Item String]
items' <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (forall a. Template -> Context a -> Item a -> Compiler (Item String)
applyTemplate Template
tpl Context a
context) [Item a]
items
    forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat forall a b. (a -> b) -> a -> b
$ forall a. a -> [a] -> [a]
intersperse String
delimiter forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map forall a. Item a -> a
itemBody [Item String]
items'


--------------------------------------------------------------------------------
-- | Sort pages chronologically. Uses the same method as 'dateField' for
-- extracting the date.
chronological :: (MonadMetadata m, MonadFail m) => [Item a] -> m [Item a]
chronological :: forall (m :: * -> *) a.
(MonadMetadata m, MonadFail m) =>
[Item a] -> m [Item a]
chronological =
    forall (m :: * -> *) k a.
(Monad m, Ord k) =>
(a -> m k) -> [a] -> m [a]
sortByM forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *).
(MonadMetadata m, MonadFail m) =>
TimeLocale -> Identifier -> m UTCTime
getItemUTC TimeLocale
defaultTimeLocale forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Item a -> Identifier
itemIdentifier
  where
    sortByM :: (Monad m, Ord k) => (a -> m k) -> [a] -> m [a]
    sortByM :: forall (m :: * -> *) k a.
(Monad m, Ord k) =>
(a -> m k) -> [a] -> m [a]
sortByM a -> m k
f [a]
xs = forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> a
fst forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing forall a b. (a, b) -> b
snd)) forall a b. (a -> b) -> a -> b
$
                   forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (\a
x -> forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (a
x,) (a -> m k
f a
x)) [a]
xs


--------------------------------------------------------------------------------
-- | The reverse of 'chronological'
recentFirst :: (MonadMetadata m, MonadFail m) => [Item a] -> m [Item a]
recentFirst :: forall (m :: * -> *) a.
(MonadMetadata m, MonadFail m) =>
[Item a] -> m [Item a]
recentFirst = forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM forall a. [a] -> [a]
reverse forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a.
(MonadMetadata m, MonadFail m) =>
[Item a] -> m [Item a]
chronological


--------------------------------------------------------------------------------
-- | Version of 'chronological' which doesn't need the actual items.
sortChronological
    :: (MonadMetadata m, MonadFail m) => [Identifier] -> m [Identifier]
sortChronological :: forall (m :: * -> *).
(MonadMetadata m, MonadFail m) =>
[Identifier] -> m [Identifier]
sortChronological [Identifier]
ids =
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (forall a b. (a -> b) -> [a] -> [b]
map forall a. Item a -> Identifier
itemIdentifier) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a.
(MonadMetadata m, MonadFail m) =>
[Item a] -> m [Item a]
chronological [forall a. Identifier -> a -> Item a
Item Identifier
i () | Identifier
i <- [Identifier]
ids]


--------------------------------------------------------------------------------
-- | Version of 'recentFirst' which doesn't need the actual items.
sortRecentFirst
    :: (MonadMetadata m, MonadFail m) => [Identifier] -> m [Identifier]
sortRecentFirst :: forall (m :: * -> *).
(MonadMetadata m, MonadFail m) =>
[Identifier] -> m [Identifier]
sortRecentFirst [Identifier]
ids =
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (forall a b. (a -> b) -> [a] -> [b]
map forall a. Item a -> Identifier
itemIdentifier) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a.
(MonadMetadata m, MonadFail m) =>
[Item a] -> m [Item a]
recentFirst [forall a. Identifier -> a -> Item a
Item Identifier
i () | Identifier
i <- [Identifier]
ids]