about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/Blog.hs501
1 files changed, 263 insertions, 238 deletions
diff --git a/src/Blog.hs b/src/Blog.hs
index d7a53e1f4225..538dd9212441 100644
--- a/src/Blog.hs
+++ b/src/Blog.hs
@@ -1,25 +1,20 @@
-{-# LANGUAGE OverloadedStrings, ScopedTypeVariables, DeriveDataTypeable, RecordWildCards #-}
+{-# LANGUAGE OverloadedStrings, ScopedTypeVariables, DeriveDataTypeable, QuasiQuotes, RecordWildCards #-}
 
 module Blog where
 
-import           Control.Monad (when, unless)
-import           Data.Data (Data, Typeable)
-import           Data.List (intersperse)
-import           Data.Monoid (mempty)
-import           Data.Text (Text)
-import qualified Data.Text as T
-import           Data.Time
-import           Network.Captcha.ReCaptcha
-import           System.Locale (defaultTimeLocale)
-import           Text.Blaze (toValue, preEscapedText, preEscapedString)
-import           Text.Blaze.Html5 (Html, (!), a, form, input, p, toHtml, label)
-import           Text.Blaze.Html5.Attributes (action, enctype, href, name, size, type_, value)
-import qualified Text.Blaze.Html5 as H
-import qualified Text.Blaze.Html5.Attributes as A
-import           Text.XHtml.Strict (showHtmlFragment)
+import Control.Monad (when, unless)
+import Data.Data (Data, Typeable)
+import Data.List (intersperse)
+import Data.Monoid (mempty)
+import Data.Text (Text, append, pack, empty)
+import Data.Time
+import Network.Captcha.ReCaptcha
+import System.Locale (defaultTimeLocale)
+import Text.Hamlet
+import Locales
+import BlogDB
 
-import           Locales
-import           BlogDB
+import qualified Data.Text as T
 
 -- custom list functions
 intersperse' :: a -> [a] -> [a]
@@ -28,21 +23,12 @@ intersperse' sep l = sep : intersperse sep l
 replace :: Eq a => a -> a -> [a] -> [a]
 replace x y = map (\z -> if z == x then y else z)
 
--- javascript and others
-
-captcha :: Html
-captcha = H.div ! A.class_ "cCaptcha" $
-          do H.script ! A.src "http://api.recaptcha.net/challenge?k=6LfQXccSAAAAAIjKm26XlFnBMAgvaKlOAjVWEEnM" ! A.type_ "text/javascript" $ ""
-             H.noscript $ H.iframe ! A.src "http://api.recaptcha.net/noscript?k=6LfQXccSAAAAAIjKm26XlFnBMAgvaKlOAjVWEEnM" ! A.height "300" !
-                               A.width "500" ! A.seamless "" $ do
-                                    H.br
-                                    H.textarea ! A.name "recaptcha_challenge_field" ! A.rows "3" ! A.cols "40" $ ""
-                                    H.input ! A.type_ "hidden" ! A.name "recaptcha_response_field" ! A.value "manual_challenge"
+show' :: Show a => a -> Text
+show' = pack . show
 
-captchaOptions :: BlogLang ->  Html
-captchaOptions lang = H.script ! A.type_ "text/javascript" $ toHtml $ 
-                        T.concat ["var RecaptchaOptions = { theme: 'clean', lang: '", showLangText lang, "'};"]
+data BlogURL = BlogURL
 
+-- javascript and others
 analytics :: Text
 analytics = T.pack $ unlines ["<script type=\"text/javascript\">"
                              ,"  var _gaq = _gaq || [];"
@@ -56,240 +42,279 @@ analytics = T.pack $ unlines ["<script type=\"text/javascript\">"
                              ,"</script>"]
 
 -- blog HTML
-
 blogTemplate :: BlogLang -> Text -> Html -> Html
-blogTemplate lang t_append body = H.docTypeHtml $ do --add body
-    H.head $ do
-        H.title $ (toHtml $ blogTitle lang t_append)
-        H.link ! A.rel "alternate" ! A.type_ "application/rss+xml" ! A.title "RSS-Feed" ! A.href (toValue feedURL)
-        H.link ! A.rel "stylesheet" ! A.type_ "text/css" ! A.href "/static/blogv33.css" ! A.media "all"
-        --H.link ! A.rel "stylesheet" ! A.type_ "text/css" ! A.href "/res/blogstyle.css" ! A.media "all"
-        H.meta ! A.httpEquiv "content-type" ! A.content "text/html;charset=UTF-8"
-        --H.style ! A.type_ "text/css" ! A.title "iOS iMessage" ! A.media "screen and (max-device-width: 1024px)" $ "#cosx{display:none;}"
-        preEscapedText analytics
-    H.body $ do
-        H.div ! A.class_ "header" $ do
-            H.a ! A.class_ "btitle" ! A.href (toValue $ "/" ++ show lang) $ 
-                toHtml $ blogTitle lang ""
-            H.p ! A.style "clear: both;" $ do
-                H.span ! A.class_ "contacts" ! A.id "cosx" $ contactInfo iMessage
-                -- H.span ! A.id "cios" ! A.style "display:none;" $ H.b $ contactInfo "sms:tazjin@me.com"
-                H.span ! A.class_ "righttext" $ preEscapedText $ rightText lang
-        H.div ! A.class_ "middle" $ do
-            body
-            H.div ! A.class_ "footer" $ do
-                showFooter lang $ T.pack version
-                H.div ! A.class_ "centerbox" $
-                    H.span ! A.style "font-size: 17px; font-family: Helvetica;" $ "ಠ_ಠ"
-                    --H.img ! A.src "http://cl.ly/F9m4/idiots.png" ! A.alt ""
-    where
-        contactInfo (imu :: Text) = do
-            toHtml $ contactText lang
-            H.a ! A.class_ "link" ! A.href (toValue mailTo) $ "Mail"
-            ", "
-            H.a ! A.class_ "link" ! A.href (toValue twitter) ! A.target "_blank" $ "Twitter"
-            toHtml $ orText lang
-            H.a ! A.class_ "link" ! A.href (toValue imu) ! A.target "_blank" $ "iMessage"
-            "."
-        feedURL = "/" ++ show lang ++ "/rss.xml"
+blogTemplate lang t_append body = [shamlet|
+$doctype 5
+ <head>
+  <title>#{blogTitle lang t_append}
+  <link rel="stylesheet" type="text/css" href="/static/blogv33.css" media="all">
+  <link rel="alternate" type="application/rss+xml" title="RSS-Feed" href=#{rssUrl}>
+  <meta http-equiv="content-type" content="text/html;charset=UTF-8">
+  #{analytics}
+ <body>
+  <div class="header">
+  <a class="btitle" href=#{append "/" (show' lang)}>#{blogTitle lang empty}
+  <p style="clear: both;">
+   <span class="contacts" id="cosx">#{contactInfo iMessage}
+   <span class="righttext">#{rightText lang}
+  <div class="middle">
+   #{body}
+   <div class="footer">
+    #{showFooter lang $ pack version}
+    <div class="centerbox">
+     <span style="font-size:17px;font-family:Helvetica;">ಠ_ಠ
+|]
+ where
+  rssUrl = T.concat ["/", show' lang, "/rss.xml"]
+  contactInfo imu = [shamlet|
+#{contactText lang}
+<a class="link" href=#{mailTo}>Mail
+, #
+<a class="link" href=#{twitter} target="_blank">Twitter
+#{orText lang}
+<a class="link" href=#{imu} target="_blank">iMessage
+.
+|]
 
-renderEntries :: Bool -> [Entry] -> Text -> Maybe Html -> Html
-renderEntries showAll entries topText footerLinks = do
-    H.span ! A.class_ "innerTitle" $ toHtml topText
-    H.div ! A.class_ "innerContainer" $ do
-        H.ul ! A.style "max-width: 57em;" $ if' showAll
-            (mapM_ showEntry entries)
-            (mapM_ showEntry $ take 6 entries)
-        getFooterLinks footerLinks
-    where
-        showEntry :: Entry -> Html
-        showEntry e = H.li $ do 
-            entryLink e $ T.pack $ show(length $ comments e)
-            preEscapedText $ T.append " " $ btext e
-            when ( mtext e /= T.empty ) $
-                H.p $ entryLink e $ readMore $ lang e
-            unless ( mtext e /= T.empty ) $
-                preEscapedText "<br>&nbsp;"
-        entryLink :: Entry -> Text -> Html
-        entryLink e s = H.a ! A.href (toValue $ concat $ intersperse' "/" $ linkElems e) $
-                        toHtml (T.concat ["[", s, "]"])
-        linkElems e = [show(lang e), show $ entryId e]
-        getFooterLinks (Just h) = h
-        getFooterLinks Nothing = mempty
+showFooter :: BlogLang -> Text -> Html
+showFooter l v = [shamlet|
+<div class="rightbox" style="text-align:right;">
+ Proudly made with #
+ <a class="link" href="http://haskell.org">Haskell
+ , #
+ <a class="link" href="http://hackage.haskell.org/package/acid-state-0.6.3">Acid-State
+ / and without PHP, Java, Perl, MySQL and Python.
+ <p>
+  <a class="link" href=#{repoURL}>#{append "Version " v}
+  &nbsp;
+  <a class="link" href="/notice">#{noticeText l}
+|]
 
-renderEntry :: Entry -> Html
-renderEntry (Entry{..}) = do
-    H.span ! A.class_ "innerTitle" $ toHtml $ title
-    H.span ! A.class_ "righttext" $ H.i $ toHtml $ woText
-    H.div ! A.class_ "innerContainer" $ do
-        H.article $ H.ul ! A.style "max-width: 57em;" $ H.li $ do
-            preEscapedText $ btext
-            H.p $ preEscapedText $ mtext
-        H.div ! A.class_ "innerBoxComments" $ do
-            H.div ! A.class_ "cHead" $ toHtml $ cHead lang -- ! A.style "font-size:large;font-weight:bold;"
-            H.ul ! A.style "max-width: 57em;" $ renderComments comments lang
-            renderCommentBox lang entryId
+renderEntries :: Bool -> [Entry] -> Text -> Maybe Html -> Html
+renderEntries showAll entries topText footerLinks = [shamlet|
+<span class="innerTitle">#{topText}
+<div class="innerContainer">
+ <ul style="max-width:57em;">
+  $forall entry <- elist
+   <li>
+    <a href=#{linkElems entry}>#{linkText $ length $ comments entry}
+    #{append " " $ btext entry}
+    $if ((/=) (mtext entry) empty)
+     <p><a href=#{linkElems entry}>#{readMore $ lang entry}
+    $else
+     <br>&nbsp;
+ $maybe links <- footerLinks
+  #{links}
+|]
   where
-    woText = flip T.append author $ T.pack $ (formatTime defaultTimeLocale (eTimeFormat lang) edate) 
+   elist = if' showAll entries (take 6 entries)
+   linkElems Entry{..} = concat $ intersperse' "/" [show lang, show entryId]
+   linkText n = T.concat ["[", show' n, "]"]
 
-renderCommentBox :: BlogLang -> EntryId -> Html
-renderCommentBox cLang cId = do
-    H.div ! A.class_ "cHead" $ toHtml $ cwHead cLang
-    captchaOptions cLang
-    H.form ! A.method "POST" ! A.action (toValue $ "/" ++ (show cLang) ++  "/postcomment/" ++ show cId) $ do
-        H.p $ H.input ! A.name "cname" ! A.placeholder "Name" ! A.class_ "cInput"
-        H.p $ H.label $ H.textarea ! A.name "ctext" ! A.cols "50" ! A.rows "13" ! A.class_ "cInput" !
-                        A.placeholder (toValue $ cTextPlaceholder cLang) $ mempty
-        -- H.p $ H.label $ captcha
-        H.p $ H.input ! A.class_ "cInput" ! A.style "width: 120px;" ! A.type_ "submit" ! A.value (toValue $ cSend cLang)
+showLinks :: Maybe Int -> BlogLang -> Html
+showLinks (Just i) lang = [shamlet|
+ $if ((>) i 1)
+  <div class="centerbox">
+   <a href=#{nLink $ succ i}>#{backText lang}
+   / -- #
+   <a href=#{nLink $ pred i}>#{nextText lang}
+ $elseif ((<=) i 1)
+  #{showLinks Nothing lang}
+|]
+  where
+   nLink page = T.concat ["/", show' lang, "/?page=", show' page]
+showLinks Nothing lang = [shamlet|
+<div class="centerbox">
+ <a href=#{nLink}>#{backText lang}
+|]
+  where
+   nLink = T.concat ["/", show' lang, "/?page=2"]
 
-renderComments :: [Comment] -> BlogLang -> Html
-renderComments [] lang = H.li $ toHtml $ noComments lang
-renderComments comments lang = mapM_ showComment comments
-    where
-        showComment :: Comment -> Html
-        showComment (Comment{..}) = H.li $ do
-            H.i $ toHtml $ T.append cauthor ": "
-            preEscapedText ctext
-            H.p ! A.class_ "tt" $ toHtml $ timeString cdate
-        timeString t = formatTime defaultTimeLocale (cTimeFormat lang) t
+renderEntry :: Entry -> Html
+renderEntry Entry{..} = [shamlet|
+<span class="innerTitle">#{title}
+<span class="righttext"><i>#{woText}
+<div class="innerContainer">
+ <article>
+  <ul style="max-width:57em;">
+   <li>
+    #{btext}
+    <p>#{mtext}
+ <div class="innerBoxComments">
+  <div class="cHead">#{cHead lang}
+  <ul style="max-width:57em;">#{renderComments comments lang}
+  #{renderCommentBox lang entryId}
+|]
+  where
+   woText = flip T.append author $ T.pack $ (formatTime defaultTimeLocale (eTimeFormat lang) edate)
 
-showLinks :: Maybe Int -> BlogLang -> Html
-showLinks (Just i) lang
-    | ( i > 1) = H.div ! A.class_ "centerbox" $ do
-        H.a ! A.href (toValue $ "/" ++ show lang ++ "/?page=" ++ show (i+1)) $ 
-                                toHtml $ backText lang
-        toHtml (" -- " :: Text)
-        H.a ! A.href (toValue $ "/" ++ show lang ++ "/?page=" ++ show (i-1)) $
-                                toHtml $ nextText lang
-    | ( i <= 1 ) = showLinks Nothing lang 
-showLinks Nothing lang = H.div ! A.class_ "centerbox" $
-    H.a ! A.href (toValue $ "/" ++ show lang ++ "/?page=2") $ 
-                                toHtml $  backText lang
+renderComments :: [Comment] -> BlogLang -> Html
+renderComments [] lang = [shamlet|<li>#{noComments lang}|]
+renderComments comments lang = [shamlet|
+$forall comment <- comments
+ <li>
+  <i>#{append (cauthor comment) ": "}
+  #{ctext comment}
+  <p class="tt">#{timeString $ cdate comment}
+|]
+  where
+   timeString = formatTime defaultTimeLocale (cTimeFormat lang)
 
-showFooter :: BlogLang -> Text -> Html
-showFooter l v = H.div ! A.class_ "rightbox" ! A.style "text-align:right;" $ do
-    toHtml ("Proudly made with " :: Text)
-    H.a ! A.class_ "link" ! A.href "http://haskell.org" $ "Haskell"
-    toHtml (", " :: Text)
-    H.a ! A.class_ "link" ! A.href "http://hackage.haskell.org/package/acid-state-0.6.3" $ "Acid-State"
-    toHtml (" and without PHP, Java, Perl, MySQL and Python." :: Text)
-    H.br
-    H.a ! A.class_ "link" ! A.href (toValue repoURL) $ toHtml $ T.append "Version " v
-    preEscapedText "&nbsp;"
-    H.a ! A.class_ "link" ! A.href "/notice" $ toHtml $ noticeText l
+
+renderCommentBox :: BlogLang -> EntryId -> Html
+renderCommentBox cLang cId = [shamlet|
+<div class="cHead">#{cwHead cLang}
+<form method="POST" action=#{aLink}>
+ <p><input name="cname" placeholder="Name" class="cInput">
+ <p>
+  <label>
+   <textarea name="ctext" cols="50" rows="13" class="cInput" placeholder=#{cTextPlaceholder cLang}>
+ <p><input class="cInput" style="width:120px;" type="submit" value=#{cSend cLang}>
+|]
+  where
+   aLink = T.concat ["/", show' cLang, "/postcomment", show' cId]
 
 showSiteNotice :: Html
-showSiteNotice = H.docTypeHtml $ do
-    H.title $ "Impressum"
-    H.h2 $ preEscapedText "Impressum und <a alt=\"Verantwortlich im Sinne des Presserechtes\">ViSdP</a>"
-    H.i $ "[German law demands this]"
-    H.br
-    H.p $ do
-        toHtml ("Vincent Ambo" :: Text)
-        H.br
-        toHtml ("Benfleetstr. 8" :: Text)
-        H.br 
-        toHtml ("50858 Köln" :: Text)
-        H.p $ H.a ! A.href "/" ! A.style "color:black" $ "Back"
+showSiteNotice = [shamlet|
+$doctype 5
+<head>
+ <title>Impressum
+<body>
+ <h2>
+  Impressum und #
+  <a alt="Verantwortlich im Sinne des Presserechtes">ViSdP
+ <i>[German law demands this]
+ <br>
+ <p>
+  Vincent Ambo
+  <br>
+  Benfleetstr. 8
+  <br>
+  50858 Köln
+  <p><a href="/" style="color:black;">Back
+|]
 
 {- Administration pages -}
 
 adminTemplate :: Text -> Html -> Html
-adminTemplate title body = H.docTypeHtml $ do
-    H.head $ do
-        H.link ! A.rel "stylesheet" ! A.type_ "text/css" ! A.href "/static/admin.css" ! A.media "all"
-        H.meta ! A.httpEquiv "content-type" ! A.content "text/html;charset=UTF-8"
-        H.title $ toHtml $ T.append "TazBlog Admin: " title
-    H.body
-        body
+adminTemplate title body = [shamlet|
+$doctype 5
+<head>
+ <link rel="stylesheet" type="text/css" href="/static/admin.css" media="all">
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8">
+ <title>#{append "TazBlog Admin: " title}
+<body>
+ #{body}
+|]
 
 adminLogin :: Html
-adminLogin = adminTemplate "Login" $
-  H.div ! A.class_ "loginBox" $ do
-    H.div ! A.class_ "loginBoxTop" $ "TazBlog Admin: Login"
-    H.div ! A.class_ "loginBoxMiddle" $ H.form ! A.action "/dologin" ! A.method "post" $ do
-        H.p $ "Account ID"
-        H.p $ H.input ! A.type_ "text" ! A.style "font-size: 2;" 
-            ! A.name "account" -- ! A.value "tazjin" ! A.readonly "1"
-        H.p $ "Passwort"
-        H.p $ H.input ! A.type_ "password" ! A.style "font-size: 2;" ! A.name "password"
-        H.p $ H.input ! A.alt "Anmelden" ! A.type_ "image" ! A.src "/static/signin.gif"
+adminLogin = adminTemplate "Login" $ [shamlet|
+<div class="loginBox">
+ <div class="loginBoxTop">TazBlog Admin: Login
+ <div class="loginBoxMiddle">
+  <form action="/dologin" method="POST">
+   <p>Account ID
+   <p><input type="text" style="font-size:2;" name="account" value="tazjin" readonly="1">
+   <p>Passwort
+   <p><input type="password" style="font-size:2;" name="password">
+   <p><input alt="Anmelden" type="image" src="/static/signin.gif">
+|]
 
 adminIndex :: Text -> Html
-adminIndex sUser = adminTemplate "Index" $
-  H.div ! A.style "float: center;" $
-    H.form ! A.action "/admin/postentry" ! A.method "POST" $ do
-      H.table $ do
-        H.tr $ do H.td $ "Titel:"
-                  H.td $ H.input ! A.type_ "text" ! A.name "title"
-        H.tr $ do H.td $ "Sprache:"
-                  H.td $ H.select ! A.name "lang" $ do
-                    H.option ! A.value "de" $ "Deutsch"
-                    H.option ! A.value "en" $ "Englisch"
-        H.tr $ do H.td ! A.style "vertical-align: top;" $ "Text:"
-                  H.td $ H.textarea ! A.name "btext" ! A.cols "100" ! A.rows "15" $ mempty
-        H.tr $ do H.td ! A.style "vertical-align: top;" $ "Mehr Text:"
-                  H.td $ H.textarea ! A.name "mtext" ! A.cols "100" ! A.rows "15" $ mempty
-      H.input ! A.type_ "hidden" ! A.name "author" ! A.value (toValue sUser)
-      H.input ! A.style "margin-left: 20px" ! A.type_ "submit" ! A.value "Absenden"
-      adminFooter
+adminIndex sUser = adminTemplate "Index" $ [shamlet|
+<div style="float:center;">
+ <form action="/admin/postentry" method="POST">
+  <table>
+   <tr>
+    <thead><td>Titel:
+    <td><input type="text" name="title">
+   <tr>
+    <thead><td>Sprache:
+    <td><select name="lang">
+     <option value="de">Deutsch
+     <option value="en">Englisch
+   <tr>
+    <thead><td>Text:
+    <td><textarea name="btext" cols="100" rows="15">
+   <tr>
+    <thead><td style="vertical-align:top;">Mehr Text:
+    <td><textarea name="mtext" cols="100" rows="15">
+  <input type="hidden" name="author" value=#{sUser}>
+  <input style="margin-left:20px;" type="submit" value="Absenden">
+ #{adminFooter}
+|]
 
 adminFooter :: Html
-adminFooter =  H.p $ do 
-    preEscapedText "<a href=/>Startseite</a> -- Entrylist: <a href=/admin/entrylist/de>DE</a>"
-    preEscapedText " & <a href=/admin/entrylist/en>EN</a> -- <a href=#>Backup</a> (NYI)"
+adminFooter = [shamlet|
+<a href="/">Startseite
+/ -- Entrylist: #
+<a href="/admin/entrylist/de">DE
+/ & #
+<a href="/admin/entrylist/en">EN
+/ -- #
+<a href="#">Backup
+/ (NYI)
+|]
 
 adminEntryList :: [Entry] -> Html
-adminEntryList entries = adminTemplate "Entrylist" $
-  H.div ! A.style "float: center;" $ do
-    H.table $ do
-        mapM_ showEntryItem entries
-    adminFooter
-  where
-    showEntryItem :: Entry -> Html
-    showEntryItem (Entry{..}) = H.tr $ do
-        H.td $ H.a ! A.href (toValue $ "/admin/edit/" ++ show entryId) $ toHtml title
-        H.td $ toHtml $ formatTime defaultTimeLocale "[On %D at %H:%M]" edate
-
+adminEntryList entries = adminTemplate "EntryList" $ [shamlet|
+<div style="float: center;">
+ <table>
+  $forall entry <- entries
+   <tr>
+    <td><a href=#{append "/admin/edit" (show' $ entryId entry)}>#{title entry}
+    <td>#{formatPostDate $ edate entry}
+|]
+ where
+  formatPostDate = formatTime defaultTimeLocale "[On %D at %H:%M]"
 
 editPage :: Entry -> Html
-editPage (Entry{..}) = adminTemplate "Index" $
-  H.div ! A.style "float: center;" $
-    H.form ! A.action "/admin/updateentry" ! A.method "POST" $ do
-      H.table $ do
-        H.tr $ do H.td $ "Titel:"
-                  H.td $ H.input ! A.type_ "text" ! A.name "title" ! A.value (toValue title)
-        H.tr $ do H.td ! A.style "vertical-align: top;" $ "Text:"
-                  H.td $ H.textarea ! A.name "btext" ! A.cols "100" ! A.rows "15" $ toHtml btext
-        H.tr $ do H.td ! A.style "vertical-align: top;" $ "Mehr Text:"
-                  H.td $ H.textarea ! A.name "mtext" ! A.cols "100" ! A.rows "15" $ toHtml mtext
-      H.input ! A.type_ "hidden" ! A.name "eid" ! A.value (toValue $ unEntryId entryId)
-      H.input ! A.style "margin-left: 20px" ! A.type_ "submit" ! A.value "Absenden"
-      H.div ! A.class_ "editComments" $ editComments comments entryId
-      H.p $ do preEscapedText "<a href=/>Startseite</a> -- Entrylist: <a href=/admin/entrylist/de>DE</a>"
-               preEscapedText " & <a href=/admin/entrylist/en>EN</a> -- <a href=#>Backup</a> (NYI)"
+editPage (Entry{..}) = adminTemplate "Index" $ [shamlet|
+<div style="float:center;">
+ <form action="/admin/updateentry" method="POST">
+  <table>
+   <tr>
+    <td>Titel:
+    <td><input type="text" name="title" value=#{title}>
+   <tr>
+    <td style="vertical-align:top;">Text:
+    <td><textarea name="btext" cols="100" rows="15">#{btext}
+   <tr>
+    <td style="vertical-align:top;">Mehr Text:
+    <td><textarea name="mtext" cols="100" rows="15">#{mtext}
+  <input type="hidden" name="eid" value=#{unEntryId entryId}>
+  <input type="submit" style="margin-left:20px;" value="Absenden">
+  <div class="editComments">#{editComments comments entryId}
+  <p>#{adminFooter}
+|]
 
 editComments :: [Comment] -> EntryId -> Html
-editComments clist eId = H.table $ mapM_ editComment clist
-    where
-        editComment (Comment{..}) = H.tr $ do H.td $ toHtml cauthor
-                                              H.td $ toHtml $ formatTime defaultTimeLocale "%c" cdate
-                                              H.td $ cDeleteLink cdate
-        cDeleteLink cdate = H.a ! A.href (toValue $ "/admin/cdelete/" ++ show eId 
-                                         ++ formatTime defaultTimeLocale "/%s%Q" cdate) $ "Löschen"
+editComments comments eId = [shamlet|
+<table>
+ $forall c <- comments
+  <tr>
+   <td>#{cauthor c}
+   <td>#{cPostTime $ cdate c}
+  <tr>
+   <td><a href=#{cDeleteLink $ cdate c}>Löschen
+|]
+ where
+  cPostTime = formatTime defaultTimeLocale "%c"
+  cDeleteLink cd = concat ["/admin/cdelete", show eId, formatTime defaultTimeLocale "/%s%Q" cd]
 
 commentDeleted :: EntryId -> Html
-commentDeleted eId = adminTemplate "Kommentar gelöscht" $ do
-    H.div $ "Der Kommentar wurde gelöscht."
-    H.br
-    H.a ! A.href (toValue $ "/de/" ++ show eId) $ "Eintrag ansehen | "
-    H.a ! A.href (toValue $ "/admin/edit/" ++ show eId) $ "Eintrag bearbeiten"
+commentDeleted eId = adminTemplate "Kommentar gelöscht" $ [shamlet|
+<div>Der Kommentar wurde gelöscht.
+<br>
+<a href=#{append "/de/" $ show' eId}>Eintrag ansehen | #
+<a href=#{append "/admin/edit/" $ show' eId}>Eintrag bearbeiten
+|]
 
--- Error pages
 showError :: BlogError -> BlogLang -> Html
-showError NotFound l = blogTemplate l (T.append ": " $ notFoundTitle l) $ do
-  H.span ! A.class_ "innerTitle" $ toHtml $ notFoundTitle l
-  H.div ! A.class_ "innerContainer" $ do
-    H.p ! A.class_ "notFoundFace" $ toHtml (":'(" :: Text)
-    H.p ! A.class_ "notFoundText" $ toHtml $ notFoundText l
+showError NotFound l = blogTemplate l (T.append ": " $ notFoundTitle l) $ [shamlet|
+<span class="innerTitle">#{notFoundTitle l}
+<div class="innerTitle">
+ <p class="notFoundFace">:(
+ <p class="notFoundText">#{notFoundText l}
+|]
+