@@ -3,6 +3,9 @@ module Text.Hakyll.Renderables
33 , createCustomPage
44 , PagePath
55 , createPagePath
6+ , CombinedRenderable
7+ , combine
8+ , combineWithURL
69 ) where
710
811import qualified Data.Map as M
@@ -14,9 +17,9 @@ import Text.Hakyll.File
1417
1518-- | A custom page.
1619data CustomPage = CustomPage
17− { url :: String,
18− dependencies :: [FilePath],
19− mapping :: [(String, Either String (Hakyll String))]
20+ { customPageURL :: String,
21+ customPageDependencies :: [FilePath],
22+ customPageContext :: [(String, Either String (Hakyll String))]
2023 }
2124
2225-- | Create a custom page.
@@ -33,12 +36,12 @@ createCustomPage :: String -- ^ Destination of the page, relative to _site.
3336createCustomPage = CustomPage
3437
3538instance Renderable CustomPage where
36− getDependencies = dependencies
37− getURL = url
39+ getDependencies = customPageDependencies
40+ getURL = customPageURL
3841 toContext page = do
39− values <- mapM (either (return) (>>= return) . snd) (mapping page)
40− return $ M.fromList $ [ ("url", url page)
41− ] ++ zip (map fst $ mapping page) values
42+ values <- mapM (either return id . snd) (customPageContext page)
43+ return $ M.fromList $ [ ("url", customPageURL page)
44+ ] ++ zip (map fst $ customPageContext page) values
4245
4346-- | PagePath is a class that wraps a FilePath. This is used to render Pages
4447-- without reading them first through use of caching.
@@ -53,3 +56,44 @@ instance Renderable PagePath where
5356 getDependencies (PagePath path) = return path
5457 getURL (PagePath path) = toURL path
5558 toContext (PagePath path) = readPage path >>= toContext
59+
60+-- | A combination of two other renderables.
61+data CombinedRenderable a b = CombinedRenderable a b
62+ | CombinedRenderableWithURL FilePath a b
63+
64+-- | Combine two renderables. The url will always be taken from the first
65+-- "Renderable". Also, if a `$key` is present in both renderables, the
66+-- value from the first "Renderable" will be taken as well.
67+combine :: (Renderable a, Renderable b) => a -> b -> CombinedRenderable a b
68+combine = CombinedRenderable
69+
70+-- | Combine two renderables and set a custom URL.
71+combineWithURL :: (Renderable a, Renderable b)
72+ => FilePath
73+ -> a
74+ -> b
75+ -> CombinedRenderable a b
76+combineWithURL = CombinedRenderableWithURL
77+
78+-- | Render combinations.
79+instance (Renderable a, Renderable b)
80+ => Renderable (CombinedRenderable a b) where
81+
82+ -- Add the dependencies.
83+ getDependencies (CombinedRenderable a b) =
84+ getDependencies a ++ getDependencies b
85+ getDependencies (CombinedRenderableWithURL _ a b) =
86+ getDependencies a ++ getDependencies b
87+
88+ -- Take the url from the first renderable, or the specified URL.
89+ getURL (CombinedRenderable a _) = getURL a
90+ getURL (CombinedRenderableWithURL url _ _) = url
91+
92+ -- Take a union of the contexts.
93+ toContext (CombinedRenderable a b) = do
94+ c1 <- toContext a
95+ c2 <- toContext b
96+ return $ c1 `M.union` c2
97+ toContext (CombinedRenderableWithURL url a b) = do
98+ c <- toContext (CombinedRenderable a b)
99+ return $ (M.singleton "url" url) `M.union` c