forked from yesodweb/yesodweb.com
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial Import.Content, no Markdown support yet
- Loading branch information
Showing
6 changed files
with
102 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "content"] | ||
path = content | ||
url = https://github.com/yesodweb/yesodweb.com-content.git |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
{-# LANGUAGE RankNTypes #-} | ||
{-# LANGUAGE OverloadedStrings #-} | ||
-- | Load page contents from the content folder. | ||
module Import.Content | ||
( ContentFormat (..) | ||
, htmlFormat | ||
, unsafeHtmlFormat | ||
, loadContent | ||
, returnContent | ||
) where | ||
|
||
import Prelude ((.), ($), IO, Maybe (..), return, (==), maybe) | ||
import Data.Text (Text) | ||
import qualified Data.Conduit as C | ||
import qualified Data.Conduit.List as CL | ||
import qualified Data.Conduit.Text as CT | ||
import qualified Data.Conduit.Filesystem as CB | ||
import Text.Blaze (Html, preEscapedText, preEscapedLazyText, toHtml) | ||
import qualified Data.ByteString as S | ||
import Control.Applicative ((<$>)) | ||
import Text.HTML.SanitizeXSS (sanitizeBalance) | ||
import Filesystem.Path.CurrentOS ((</>), fromText, (<.>)) | ||
import Filesystem (isFile) | ||
import Data.List (foldl') | ||
import qualified Data.Text.Lazy as TL | ||
import Control.Arrow (second) | ||
import Yesod | ||
( liftIO, GHandler, Yesod, RepHtml, notFound, defaultLayout | ||
, setTitle, toWidget | ||
) | ||
|
||
data ContentFormat = ContentFormat | ||
{ cfExtension :: Text | ||
, cfLoad :: C.Sink S.ByteString IO (Maybe Html, Html) | ||
} | ||
|
||
-- | Turn a stream of 'S.ByteString's into an optional title line and the rest | ||
-- of the text. Assumes UTF8 encoding. | ||
sinkText :: C.Sink S.ByteString IO (Maybe Html, TL.Text) | ||
sinkText = | ||
go . TL.fromChunks <$> (CT.decode CT.utf8 C.=$ CL.consume) | ||
where | ||
go t = | ||
case TL.stripPrefix "title: " x of | ||
Just title -> (Just $ toHtml title, TL.drop 1 y) | ||
Nothing -> (Nothing, t) | ||
where | ||
(x, y) = TL.break (== '\n') t | ||
|
||
-- | HTML content with XSS protection. | ||
htmlFormat :: ContentFormat | ||
htmlFormat = ContentFormat "html" $ | ||
second (preEscapedText . sanitizeBalance . TL.toStrict) <$> sinkText | ||
|
||
-- | HTML content without XSS protection. | ||
unsafeHtmlFormat :: ContentFormat | ||
unsafeHtmlFormat = ContentFormat "html" $ | ||
second preEscapedLazyText <$> sinkText | ||
|
||
-- | Try to load 'Html' from the given path. | ||
loadContent :: [ContentFormat] | ||
-> [Text] | ||
-> IO (Maybe (Maybe Html, Html)) | ||
loadContent [] _ = return Nothing | ||
loadContent (cf:cfs) pieces = do | ||
e <- isFile path | ||
if e | ||
-- FIXME caching | ||
then Just <$> (C.runResourceT $ CB.sourceFile path C.$$ cfLoad cf) | ||
else loadContent cfs pieces | ||
where | ||
path = foldl' go "content" pieces <.> cfExtension cf | ||
go x y = x </> fromText y | ||
|
||
-- | Return some content as a 'Handler'. | ||
returnContent :: Yesod master | ||
=> [ContentFormat] | ||
-> [Text] | ||
-> GHandler sub master RepHtml | ||
returnContent cfs pieces = do | ||
mc <- liftIO $ loadContent cfs pieces | ||
case mc of | ||
Nothing -> notFound | ||
Just (mtitle, body) -> defaultLayout $ do | ||
maybe (return ()) setTitle mtitle | ||
toWidget body |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters