2012-11-10 12:26:39 +00:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
module Hakyll.Web.Template.Context
|
2012-11-13 18:03:58 +00:00
|
|
|
( Context (..)
|
|
|
|
, mapContext
|
2012-11-10 12:26:39 +00:00
|
|
|
, field
|
2012-11-10 15:30:38 +00:00
|
|
|
|
|
|
|
, defaultContext
|
|
|
|
, bodyField
|
|
|
|
, urlField
|
|
|
|
, pathField
|
|
|
|
, categoryField
|
|
|
|
, titleField
|
2012-11-18 10:22:13 +00:00
|
|
|
, dateField
|
|
|
|
, dateFieldWith
|
|
|
|
, modificationTimeField
|
|
|
|
, modificationTimeFieldWith
|
2012-11-10 12:26:39 +00:00
|
|
|
) where
|
|
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
2012-11-18 10:22:13 +00:00
|
|
|
import Control.Applicative (Alternative (..), (<$>))
|
|
|
|
import Control.Monad (msum)
|
|
|
|
import Data.List (intercalate)
|
|
|
|
import qualified Data.Map as M
|
|
|
|
import Data.Monoid (Monoid (..))
|
|
|
|
import Data.Time.Clock (UTCTime (..))
|
|
|
|
import Data.Time.Format (formatTime, parseTime)
|
|
|
|
import System.FilePath (takeBaseName, takeDirectory,
|
|
|
|
takeFileName)
|
|
|
|
import System.Locale (TimeLocale, defaultTimeLocale)
|
2012-11-10 15:30:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
2012-11-10 12:26:39 +00:00
|
|
|
import Hakyll.Core.Compiler
|
2012-11-18 10:22:13 +00:00
|
|
|
import Hakyll.Core.Compiler.Internal
|
2012-11-10 15:30:38 +00:00
|
|
|
import Hakyll.Core.Identifier
|
2012-11-18 10:22:13 +00:00
|
|
|
import Hakyll.Core.ResourceProvider
|
|
|
|
import Hakyll.Core.Util.String (splitAll)
|
2012-11-10 17:11:46 +00:00
|
|
|
import Hakyll.Web.Page.Internal
|
2012-11-10 15:30:38 +00:00
|
|
|
import Hakyll.Web.Urls
|
2012-11-10 12:26:39 +00:00
|
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
2012-11-13 18:03:58 +00:00
|
|
|
newtype Context a = Context
|
|
|
|
{ unContext :: String -> Identifier -> a -> Compiler String
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
instance Monoid (Context a) where
|
|
|
|
mempty = Context $ \_ _ _ -> empty
|
|
|
|
mappend (Context f) (Context g) = Context $ \k i x -> f k i x <|> g k i x
|
|
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
mapContext :: (String -> String) -> Context a -> Context a
|
|
|
|
mapContext f (Context g) = Context $ \k i x -> f <$> g k i x
|
2012-11-10 12:26:39 +00:00
|
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
2012-11-13 16:31:03 +00:00
|
|
|
field :: String -> (Identifier -> a -> Compiler String) -> Context a
|
2012-11-13 18:03:58 +00:00
|
|
|
field key value = Context $ \k i x -> if k == key then value i x else empty
|
2012-11-10 15:30:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
2012-11-10 17:11:46 +00:00
|
|
|
defaultContext :: Context Page
|
2012-11-10 15:30:38 +00:00
|
|
|
defaultContext =
|
2012-11-13 18:03:58 +00:00
|
|
|
bodyField "body" `mappend`
|
|
|
|
urlField "url" `mappend`
|
|
|
|
pathField "path" `mappend`
|
|
|
|
categoryField "category" `mappend`
|
|
|
|
titleField "title" `mappend`
|
2012-11-10 17:11:46 +00:00
|
|
|
missingField
|
2012-11-10 15:30:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
2012-11-10 17:11:46 +00:00
|
|
|
bodyField :: String -> Context Page
|
2012-11-13 16:31:03 +00:00
|
|
|
bodyField key = field key $ \_ x -> return x
|
2012-11-10 15:30:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
2012-11-10 17:11:46 +00:00
|
|
|
urlField :: String -> Context a
|
2012-11-13 18:03:58 +00:00
|
|
|
urlField key = field key $ \i _ -> maybe empty toUrl <$> getRouteFor i
|
2012-11-10 15:30:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
2012-11-10 17:11:46 +00:00
|
|
|
pathField :: String -> Context a
|
2012-11-13 18:03:58 +00:00
|
|
|
pathField key = field key $ \i _ -> return $ toFilePath i
|
2012-11-10 15:30:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
2012-11-10 17:11:46 +00:00
|
|
|
categoryField :: String -> Context a
|
2012-11-13 18:03:58 +00:00
|
|
|
categoryField key = mapContext (takeBaseName . takeDirectory) $ pathField key
|
2012-11-10 15:30:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
2012-11-10 17:11:46 +00:00
|
|
|
titleField :: String -> Context a
|
2012-11-13 18:03:58 +00:00
|
|
|
titleField key = mapContext takeBaseName $ pathField key
|
2012-11-10 17:11:46 +00:00
|
|
|
|
|
|
|
|
2012-11-18 10:22:13 +00:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- | When the metadata has a field called @published@ in one of the
|
|
|
|
-- following formats then this function can render the date.
|
|
|
|
--
|
|
|
|
-- * @Sun, 01 Feb 2000 13:00:00 UT@ (RSS date format)
|
|
|
|
--
|
|
|
|
-- * @2000-02-01T13:00:00Z@ (Atom date format)
|
|
|
|
--
|
|
|
|
-- * @February 1, 2000 1:00 PM@ (PM is usually uppercase)
|
|
|
|
--
|
|
|
|
-- * @February 1, 2000@ (assumes 12:00 AM for the time)
|
|
|
|
--
|
|
|
|
-- Alternatively, when the metadata has a field called @path@ in a
|
|
|
|
-- @folder/yyyy-mm-dd-title.extension@ format (the convention for pages)
|
|
|
|
-- and no @published@ metadata field set, this function can render
|
|
|
|
-- the date.
|
|
|
|
--
|
|
|
|
-- > renderDateField "date" "%B %e, %Y" "Date unknown"
|
|
|
|
--
|
|
|
|
-- Will render something like @January 32, 2010@.
|
|
|
|
--
|
|
|
|
dateField :: String -- ^ Key in which the rendered date should be placed
|
|
|
|
-> String -- ^ Format to use on the date
|
|
|
|
-> Context a -- ^ Resulting context
|
|
|
|
dateField = dateFieldWith defaultTimeLocale
|
|
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- | This is an extended version of 'dateField' that allows you to
|
|
|
|
-- specify a time locale that is used for outputting the date. For more
|
|
|
|
-- details, see 'dateField'.
|
|
|
|
dateFieldWith :: TimeLocale -- ^ Output time locale
|
|
|
|
-> String -- ^ Destination key
|
|
|
|
-> String -- ^ Format to use on the date
|
|
|
|
-> Context a -- ^ Resulting context
|
|
|
|
dateFieldWith locale key format = field key $ \id' _ -> do
|
|
|
|
time <- getUTC locale id'
|
|
|
|
return $ formatTime locale format time
|
|
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- | Parser to try to extract and parse the time from the @published@
|
|
|
|
-- field or from the filename. See 'renderDateField' for more information.
|
|
|
|
getUTC :: TimeLocale -- ^ Output time locale
|
|
|
|
-> Identifier -- ^ Input page
|
|
|
|
-> Compiler UTCTime -- ^ Parsed UTCTime
|
|
|
|
getUTC locale id' = do
|
|
|
|
metadata <- getMetadataFor id'
|
|
|
|
let tryField k fmt = M.lookup k metadata >>= parseTime' fmt
|
|
|
|
fn = takeFileName $ toFilePath id'
|
|
|
|
|
|
|
|
maybe empty return $ msum $
|
|
|
|
[tryField "published" fmt | fmt <- formats] ++
|
|
|
|
[tryField "date" fmt | fmt <- formats] ++
|
|
|
|
[parseTime' "%Y-%m-%d" $ intercalate "-" $ take 3 $ splitAll "-" fn]
|
|
|
|
where
|
|
|
|
parseTime' = parseTime locale
|
|
|
|
formats =
|
|
|
|
[ "%a, %d %b %Y %H:%M:%S UT"
|
|
|
|
, "%Y-%m-%dT%H:%M:%SZ"
|
|
|
|
, "%Y-%m-%d %H:%M:%S"
|
|
|
|
, "%Y-%m-%d"
|
|
|
|
, "%B %e, %Y %l:%M %p"
|
|
|
|
, "%B %e, %Y"
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
modificationTimeField :: String -- ^ Key
|
|
|
|
-> String -- ^ Format
|
|
|
|
-> Context a -- ^ Resuting context
|
|
|
|
modificationTimeField = modificationTimeFieldWith defaultTimeLocale
|
|
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
modificationTimeFieldWith :: TimeLocale -- ^ Time output locale
|
|
|
|
-> String -- ^ Key
|
|
|
|
-> String -- ^ Format
|
|
|
|
-> Context a -- ^ Resulting context
|
|
|
|
modificationTimeFieldWith locale key fmt = field key $ \id' _ -> do
|
|
|
|
mtime <- compilerUnsafeIO $ resourceModificationTime id'
|
|
|
|
return $ formatTime locale fmt mtime
|
|
|
|
|
|
|
|
|
2012-11-10 17:11:46 +00:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
missingField :: Context a
|
2012-11-13 18:03:58 +00:00
|
|
|
missingField = Context $ \k _ _ -> return $ "$" ++ k ++ "$"
|