Basic implementation of template groups

This commit is contained in:
Michael Snoyman 2009-12-29 23:07:38 +02:00
parent 3cbcac8c41
commit 911934bff0
12 changed files with 90 additions and 33 deletions

View File

@ -186,7 +186,7 @@ instance ToSElem HtmlObject where
#if TEST
caseHtmlToText :: Assertion
caseHtmlToText = do
let actual = Tag "div" [("id", "foo"), ("class", "bar")]
let actual = Tag "div" [("id", "foo"), ("class", "bar")] $ HtmlList
[ Html $ cs "<br>Some HTML<br>"
, Text $ cs "<'this should be escaped'>"
, EmptyTag "img" [("src", "baz&")]

4
TODO
View File

@ -1,6 +1,4 @@
Cleanup Data.Object.Translate
Some form of i18n.
Cleanup Parameter stuff. Own module? Interface with formlets?
Authentication via e-mail address built in. (eaut.org)
OpenID 2 stuff (for direct Google login).
Native support for HStringTemplate groups.
Use Text for HStringTemplate throughout

View File

@ -21,7 +21,7 @@ module Yesod
, module Yesod.Resource
, module Data.Object.Html
, module Yesod.Rep
, module Yesod.Templates
, module Yesod.Template
, module Data.Convertible.Text
, Application
) where
@ -34,6 +34,6 @@ import Yesod.Handler
import Yesod.Resource
import Hack (Application)
import Yesod.Rep
import Yesod.Templates
import Yesod.Template
import Data.Object.Html
import Data.Convertible.Text

View File

@ -38,6 +38,7 @@ module Yesod.Handler
import Yesod.Request
import Yesod.Response
import Yesod.Rep
import Yesod.Template
import Control.Exception hiding (Handler)
import Control.Applicative
@ -49,11 +50,10 @@ import Control.Monad (liftM, ap)
import System.IO
import Data.Object.Html
--import Data.Typeable
------ Handler monad
newtype Handler yesod a = Handler {
unHandler :: (RawRequest, yesod) -> IO ([Header], HandlerContents a)
unHandler :: (RawRequest, yesod, TemplateGroup)
-> IO ([Header], HandlerContents a)
}
data HandlerContents a =
forall e. Exception e => HCError e
@ -81,22 +81,26 @@ instance MonadIO (Handler yesod) where
instance Exception e => Failure e (Handler yesod) where
failure e = Handler $ \_ -> return ([], HCError e)
instance MonadRequestReader (Handler yesod) where
askRawRequest = Handler $ \(rr, _) -> return ([], HCContent rr)
askRawRequest = Handler $ \(rr, _, _) -> return ([], HCContent rr)
invalidParam _pt pn pe = invalidArgs [(pn, pe)]
authRequired = permissionDenied
getYesod :: Handler yesod yesod
getYesod = Handler $ \(_, yesod) -> return ([], HCContent yesod)
getYesod = Handler $ \(_, yesod, _) -> return ([], HCContent yesod)
instance HasTemplateGroup (Handler yesod) where
getTemplateGroup = Handler $ \(_, _, tg) -> return ([], HCContent tg)
runHandler :: Handler yesod RepChooser
-> (ErrorResult -> Handler yesod RepChooser)
-> RawRequest
-> yesod
-> TemplateGroup
-> [ContentType]
-> IO Response
runHandler (Handler handler) eh rr y cts = do
runHandler (Handler handler) eh rr y tg cts = do
(headers, contents) <- Control.Exception.catch
(handler (rr, y))
(handler (rr, y, tg))
(\e -> return ([], HCError (e :: Control.Exception.SomeException)))
let contents' =
case contents of
@ -105,7 +109,7 @@ runHandler (Handler handler) eh rr y cts = do
HCContent a -> Right a
case contents' of
Left e -> do
Response _ hs ct c <- runHandler (eh e) specialEh rr y cts
Response _ hs ct c <- runHandler (eh e) specialEh rr y tg cts
let hs' = headers ++ hs ++ getHeaders e
return $ Response (getStatus e) hs' ct c
Right a -> do

View File

@ -47,7 +47,6 @@ module Yesod.Rep
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as BL
import Data.Text.Lazy (Text)
import qualified Data.Text.Lazy as TL
import Data.Maybe (mapMaybe)
import Data.Function (on)
@ -162,15 +161,24 @@ instance HasReps Plain where
plain :: ConvertSuccess x Text => x -> Plain
plain = Plain . cs
data Template = Template (StringTemplate Text) HtmlObject
data Template = Template (StringTemplate Text)
String
HtmlObject
(IO [(String, HtmlObject)])
instance HasReps Template where
reps = [ (TypeHtml,
\(Template t h) ->
return $ cs $ render $ setAttribute "o" h t)
, (TypeJson, \(Template _ ho) ->
\(Template t name ho attrsIO) -> do
attrs <- attrsIO
return
$ cs
$ render
$ setAttribute name ho
$ setManyAttrib attrs t)
, (TypeJson, \(Template _ _ ho _) ->
return $ cs $ unJsonDoc $ cs ho)
]
-- FIXME
data TemplateFile = TemplateFile FilePath HtmlObject
instance HasReps TemplateFile where
reps = [ (TypeHtml,
@ -231,7 +239,7 @@ caseChooseRepTemplate = do
ho = toHtmlObject [ ("foo", toHtmlObject "<fooval>")
, ("bar", toHtmlObject ["bar1", "bar2"])
]
hasreps = Template temp ho
hasreps = Template temp "o" ho $ return []
res1 = cs "foo:&lt;fooval&gt;, bar:bar1bar2"
res2 = cs $ "{\"bar\":[\"bar1\",\"bar2\"]," ++
"\"foo\":\"&lt;fooval&gt;\"}"

View File

@ -43,7 +43,7 @@ import Language.Haskell.TH.Ppr
import System.IO
-}
import Data.Typeable (Typeable)
import Data.Typeable
import Control.Exception (Exception)
import Data.Attempt -- for failure stuff
import Data.Object.Text
@ -62,7 +62,6 @@ import Test.Framework.Providers.QuickCheck (testProperty)
import Test.HUnit hiding (Test)
import Test.QuickCheck
import Control.Monad (when)
import Data.Typeable
#endif
resources :: QuasiQuoter

38
Yesod/Template.hs Normal file
View File

@ -0,0 +1,38 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts #-}
module Yesod.Template
( HasTemplateGroup (..)
, template
, NoSuchTemplate
, TemplateGroup
) where
import Data.Object.Html
import Data.Typeable (Typeable)
import Control.Exception (Exception)
import Control.Failure
import Yesod.Rep
import Data.Object.Text (Text)
import Text.StringTemplate
type TemplateGroup = STGroup Text
class HasTemplateGroup a where
getTemplateGroup :: a TemplateGroup
-- FIXME better home
template :: (MonadFailure NoSuchTemplate t, HasTemplateGroup t)
=> String -- ^ template name
-> String -- ^ object name
-> HtmlObject -- ^ object
-> IO [(String, HtmlObject)] -- ^ template attributes
-> t Template
template tn on o attrs = do
tg <- getTemplateGroup
t <- case getStringTemplate tn tg of
Nothing -> failure $ NoSuchTemplate tn
Just x -> return x
return $ Template t on o attrs
newtype NoSuchTemplate = NoSuchTemplate String
deriving (Show, Typeable)
instance Exception NoSuchTemplate

View File

@ -16,6 +16,7 @@ import Yesod.Utils
import Data.Maybe (fromMaybe)
import Data.Convertible.Text
import Text.StringTemplate
import qualified Hack
import Hack.Middleware.CleanPath
@ -41,6 +42,10 @@ class Yesod a where
errorHandler :: ErrorResult -> Handler a RepChooser
errorHandler = defaultErrorHandler
-- | The template directory. Blank means no templates.
templateDir :: a -> FilePath
templateDir _ = ""
class Yesod a => YesodApproot a where
-- | An absolute URL to the root of the application.
approot :: a -> Approot
@ -80,7 +85,12 @@ toHackApp' y env = do
verb = cs $ Hack.requestMethod env
handler = handlers resource verb
rr = cs env
res <- runHandler handler errorHandler rr y types
-- FIXME don't do the templateDir thing for each request
let td = templateDir y
tg <- if null td
then return nullGroup
else directoryGroupRecursiveLazy td
res <- runHandler handler errorHandler rr y tg types
let langs = ["en"] -- FIXME
responseToHackResponse langs res

View File

@ -4,7 +4,7 @@
import Yesod
import Hack.Handler.SimpleServer
data HelloWorld = HelloWorld TemplateGroup
data HelloWorld = HelloWorld
instance Yesod HelloWorld where
handlers = [$resources|
/:
@ -12,9 +12,7 @@ instance Yesod HelloWorld where
/groups:
Get: helloGroup
|]
instance YesodTemplates HelloWorld where
templates (HelloWorld g) = g
templateDir _ = "examples"
helloWorld :: Handler HelloWorld TemplateFile
helloWorld = return $ TemplateFile "examples/template.html" $ cs
@ -22,11 +20,10 @@ helloWorld = return $ TemplateFile "examples/template.html" $ cs
, ("content", "Hey look!! I'm <auto escaped>!")
]
helloGroup = template "real-template" $ cs "foo"
helloGroup = template "real-template" "foo" (cs "bar") $ return []
main :: IO ()
main = do
putStrLn "Running..."
stg <- loadTemplates "examples"
run 3000 (toHackApp $ HelloWorld stg)
run 3000 $ toHackApp HelloWorld
\end{code}

View File

@ -1 +1,2 @@
This is a more realistic template.
foo: $foo$

View File

@ -2,6 +2,7 @@
{-# LANGUAGE QuasiQuotes #-}
import Yesod
import Text.StringTemplate (nullGroup)
data MyYesod = MyYesod
@ -54,7 +55,7 @@ ph h = do
rr = error "No raw request"
y = MyYesod
cts = [TypeHtml]
res <- runHandler h eh rr y cts
res <- runHandler h eh rr y nullGroup cts
print res
main :: IO ()

View File

@ -51,7 +51,8 @@ library
HStringTemplate >= 0.6.2 && < 0.7,
data-object-json >= 0.0.0 && < 0.1,
attempt >= 0.2.1 && < 0.3,
template-haskell
template-haskell,
failure >= 0.0.0 && < 0.1
exposed-modules: Yesod
Yesod.Constants
Yesod.Rep
@ -62,7 +63,7 @@ library
Yesod.Handler
Yesod.Resource
Yesod.Yesod
Yesod.Templates
Yesod.Template
Data.Object.Html
Hack.Middleware.MethodOverride
Hack.Middleware.ClientSession