@@ -0,0 +1,110 @@
1+-- | Provides various functions to manipulate the metadata fields of a page
3+module Hakyll.Web.Page.Metadata
10+ , renderDateFieldWith
13+import Data.List (intercalate)
14+import Data.Maybe (fromMaybe)
15+import Data.Time.Clock (UTCTime)
16+import Data.Time.Format (parseTime, formatTime)
17+import qualified Data.Map as M
18+import System.FilePath (takeFileName)
19+import System.Locale (TimeLocale, defaultTimeLocale)
21+import Hakyll.Web.Page.Internal
22+import Hakyll.Web.Util.String
24+-- | Get a metadata field. If the field does not exist, the empty string is
27+getField :: String -- ^ Key
30+getField key = fromMaybe "" . M.lookup key . pageMetadata
32+-- | Add a metadata field. If the field already exists, it is not overwritten.
34+setField :: String -- ^ Key
36+ -> Page a -- ^ Page to add it to
37+ -> Page a -- ^ Resulting page
38+setField k v (Page m b) = Page (M.insertWith (flip const) k v m) b
40+-- | Do something with a metadata value, but keep the old value as well. If the
41+-- key given is not present in the metadata, nothing will happen. If the source
42+-- and destination keys are the same, the value will be changed (but you should
43+-- use 'changeField' for this purpose).
45+renderField :: String -- ^ Key of which the value should be copied
46+ -> String -- ^ Key the value should be copied to
47+ -> (String -> String) -- ^ Function to apply on the value
48+ -> Page a -- ^ Page on which this should be applied
49+ -> Page a -- ^ Resulting page
50+renderField src dst f page = case M.lookup src (pageMetadata page) of
52+ (Just value) -> setField dst (f value) page
54+-- | Change a metadata value.
56+-- > import Data.Char (toUpper)
57+-- > changeField "title" (map toUpper)
59+-- Will put the title in UPPERCASE.
61+changeField :: String -- ^ Key to change.
62+ -> (String -> String) -- ^ Function to apply on the value.
63+ -> Page a -- ^ Page to change
64+ -> Page a -- ^ Resulting page
65+changeField key = renderField key key
67+-- | Make a copy of a metadata field (put the value belonging to a certain key
68+-- under some other key as well)
70+copyField :: String -- ^ Key to copy
71+ -> String -- ^ Destination to copy to
72+ -> Page a -- ^ Page on which this should be applied
73+ -> Page a -- ^ Resulting page
74+copyField src dst = renderField src dst id
76+-- | When the metadata has a field called @path@ in a
77+-- @folder/yyyy-mm-dd-title.extension@ format (the convention for pages),
78+-- this function can render the date.
80+-- > renderDate "date" "%B %e, %Y" "Date unknown"
82+-- Will render something like @January 32, 2010@.
84+renderDateField :: String -- ^ Key in which the rendered date should be placed
85+ -> String -- ^ Format to use on the date
86+ -> String -- ^ Default value, in case the date cannot be parsed
87+ -> Page a -- ^ Page on which this should be applied
88+ -> Page a -- ^ Resulting page
89+renderDateField = renderDateFieldWith defaultTimeLocale
91+-- | This is an extended version of 'renderDateField' that allows you to
92+-- specify a time locale that is used for outputting the date. For more
93+-- details, see 'renderDateField'.
95+renderDateFieldWith :: TimeLocale -- ^ Output time locale
96+ -> String -- ^ Destination key
97+ -> String -- ^ Format to use on the date
98+ -> String -- ^ Default value
99+ -> Page a -- ^ Target page
100+ -> Page a -- ^ Resulting page
101+renderDateFieldWith locale key format defaultValue =
102+ renderField "path" key renderDate'
104+ renderDate' filePath = fromMaybe defaultValue $ do
105+ let dateString = intercalate "-" $ take 3
106+ $ splitAll "-" $ takeFileName filePath
107+ time <- parseTime defaultTimeLocale
109+ dateString :: Maybe UTCTime
110+ return $ formatTime locale format time