Basic implementation of template groups
This commit is contained in:
parent
3cbcac8c41
commit
911934bff0
@ -186,7 +186,7 @@ instance ToSElem HtmlObject where
|
|||||||
#if TEST
|
#if TEST
|
||||||
caseHtmlToText :: Assertion
|
caseHtmlToText :: Assertion
|
||||||
caseHtmlToText = do
|
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>"
|
[ Html $ cs "<br>Some HTML<br>"
|
||||||
, Text $ cs "<'this should be escaped'>"
|
, Text $ cs "<'this should be escaped'>"
|
||||||
, EmptyTag "img" [("src", "baz&")]
|
, EmptyTag "img" [("src", "baz&")]
|
||||||
|
|||||||
4
TODO
4
TODO
@ -1,6 +1,4 @@
|
|||||||
Cleanup Data.Object.Translate
|
Some form of i18n.
|
||||||
Cleanup Parameter stuff. Own module? Interface with formlets?
|
Cleanup Parameter stuff. Own module? Interface with formlets?
|
||||||
Authentication via e-mail address built in. (eaut.org)
|
Authentication via e-mail address built in. (eaut.org)
|
||||||
OpenID 2 stuff (for direct Google login).
|
OpenID 2 stuff (for direct Google login).
|
||||||
Native support for HStringTemplate groups.
|
|
||||||
Use Text for HStringTemplate throughout
|
|
||||||
|
|||||||
4
Yesod.hs
4
Yesod.hs
@ -21,7 +21,7 @@ module Yesod
|
|||||||
, module Yesod.Resource
|
, module Yesod.Resource
|
||||||
, module Data.Object.Html
|
, module Data.Object.Html
|
||||||
, module Yesod.Rep
|
, module Yesod.Rep
|
||||||
, module Yesod.Templates
|
, module Yesod.Template
|
||||||
, module Data.Convertible.Text
|
, module Data.Convertible.Text
|
||||||
, Application
|
, Application
|
||||||
) where
|
) where
|
||||||
@ -34,6 +34,6 @@ import Yesod.Handler
|
|||||||
import Yesod.Resource
|
import Yesod.Resource
|
||||||
import Hack (Application)
|
import Hack (Application)
|
||||||
import Yesod.Rep
|
import Yesod.Rep
|
||||||
import Yesod.Templates
|
import Yesod.Template
|
||||||
import Data.Object.Html
|
import Data.Object.Html
|
||||||
import Data.Convertible.Text
|
import Data.Convertible.Text
|
||||||
|
|||||||
@ -38,6 +38,7 @@ module Yesod.Handler
|
|||||||
import Yesod.Request
|
import Yesod.Request
|
||||||
import Yesod.Response
|
import Yesod.Response
|
||||||
import Yesod.Rep
|
import Yesod.Rep
|
||||||
|
import Yesod.Template
|
||||||
|
|
||||||
import Control.Exception hiding (Handler)
|
import Control.Exception hiding (Handler)
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
@ -49,11 +50,10 @@ import Control.Monad (liftM, ap)
|
|||||||
import System.IO
|
import System.IO
|
||||||
import Data.Object.Html
|
import Data.Object.Html
|
||||||
|
|
||||||
--import Data.Typeable
|
|
||||||
|
|
||||||
------ Handler monad
|
------ Handler monad
|
||||||
newtype Handler yesod a = Handler {
|
newtype Handler yesod a = Handler {
|
||||||
unHandler :: (RawRequest, yesod) -> IO ([Header], HandlerContents a)
|
unHandler :: (RawRequest, yesod, TemplateGroup)
|
||||||
|
-> IO ([Header], HandlerContents a)
|
||||||
}
|
}
|
||||||
data HandlerContents a =
|
data HandlerContents a =
|
||||||
forall e. Exception e => HCError e
|
forall e. Exception e => HCError e
|
||||||
@ -81,22 +81,26 @@ instance MonadIO (Handler yesod) where
|
|||||||
instance Exception e => Failure e (Handler yesod) where
|
instance Exception e => Failure e (Handler yesod) where
|
||||||
failure e = Handler $ \_ -> return ([], HCError e)
|
failure e = Handler $ \_ -> return ([], HCError e)
|
||||||
instance MonadRequestReader (Handler yesod) where
|
instance MonadRequestReader (Handler yesod) where
|
||||||
askRawRequest = Handler $ \(rr, _) -> return ([], HCContent rr)
|
askRawRequest = Handler $ \(rr, _, _) -> return ([], HCContent rr)
|
||||||
invalidParam _pt pn pe = invalidArgs [(pn, pe)]
|
invalidParam _pt pn pe = invalidArgs [(pn, pe)]
|
||||||
authRequired = permissionDenied
|
authRequired = permissionDenied
|
||||||
|
|
||||||
getYesod :: Handler yesod yesod
|
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
|
runHandler :: Handler yesod RepChooser
|
||||||
-> (ErrorResult -> Handler yesod RepChooser)
|
-> (ErrorResult -> Handler yesod RepChooser)
|
||||||
-> RawRequest
|
-> RawRequest
|
||||||
-> yesod
|
-> yesod
|
||||||
|
-> TemplateGroup
|
||||||
-> [ContentType]
|
-> [ContentType]
|
||||||
-> IO Response
|
-> IO Response
|
||||||
runHandler (Handler handler) eh rr y cts = do
|
runHandler (Handler handler) eh rr y tg cts = do
|
||||||
(headers, contents) <- Control.Exception.catch
|
(headers, contents) <- Control.Exception.catch
|
||||||
(handler (rr, y))
|
(handler (rr, y, tg))
|
||||||
(\e -> return ([], HCError (e :: Control.Exception.SomeException)))
|
(\e -> return ([], HCError (e :: Control.Exception.SomeException)))
|
||||||
let contents' =
|
let contents' =
|
||||||
case contents of
|
case contents of
|
||||||
@ -105,7 +109,7 @@ runHandler (Handler handler) eh rr y cts = do
|
|||||||
HCContent a -> Right a
|
HCContent a -> Right a
|
||||||
case contents' of
|
case contents' of
|
||||||
Left e -> do
|
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
|
let hs' = headers ++ hs ++ getHeaders e
|
||||||
return $ Response (getStatus e) hs' ct c
|
return $ Response (getStatus e) hs' ct c
|
||||||
Right a -> do
|
Right a -> do
|
||||||
|
|||||||
20
Yesod/Rep.hs
20
Yesod/Rep.hs
@ -47,7 +47,6 @@ module Yesod.Rep
|
|||||||
import Data.ByteString.Lazy (ByteString)
|
import Data.ByteString.Lazy (ByteString)
|
||||||
import qualified Data.ByteString.Lazy as BL
|
import qualified Data.ByteString.Lazy as BL
|
||||||
import Data.Text.Lazy (Text)
|
import Data.Text.Lazy (Text)
|
||||||
import qualified Data.Text.Lazy as TL
|
|
||||||
import Data.Maybe (mapMaybe)
|
import Data.Maybe (mapMaybe)
|
||||||
import Data.Function (on)
|
import Data.Function (on)
|
||||||
|
|
||||||
@ -162,15 +161,24 @@ instance HasReps Plain where
|
|||||||
plain :: ConvertSuccess x Text => x -> Plain
|
plain :: ConvertSuccess x Text => x -> Plain
|
||||||
plain = Plain . cs
|
plain = Plain . cs
|
||||||
|
|
||||||
data Template = Template (StringTemplate Text) HtmlObject
|
data Template = Template (StringTemplate Text)
|
||||||
|
String
|
||||||
|
HtmlObject
|
||||||
|
(IO [(String, HtmlObject)])
|
||||||
instance HasReps Template where
|
instance HasReps Template where
|
||||||
reps = [ (TypeHtml,
|
reps = [ (TypeHtml,
|
||||||
\(Template t h) ->
|
\(Template t name ho attrsIO) -> do
|
||||||
return $ cs $ render $ setAttribute "o" h t)
|
attrs <- attrsIO
|
||||||
, (TypeJson, \(Template _ ho) ->
|
return
|
||||||
|
$ cs
|
||||||
|
$ render
|
||||||
|
$ setAttribute name ho
|
||||||
|
$ setManyAttrib attrs t)
|
||||||
|
, (TypeJson, \(Template _ _ ho _) ->
|
||||||
return $ cs $ unJsonDoc $ cs ho)
|
return $ cs $ unJsonDoc $ cs ho)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
-- FIXME
|
||||||
data TemplateFile = TemplateFile FilePath HtmlObject
|
data TemplateFile = TemplateFile FilePath HtmlObject
|
||||||
instance HasReps TemplateFile where
|
instance HasReps TemplateFile where
|
||||||
reps = [ (TypeHtml,
|
reps = [ (TypeHtml,
|
||||||
@ -231,7 +239,7 @@ caseChooseRepTemplate = do
|
|||||||
ho = toHtmlObject [ ("foo", toHtmlObject "<fooval>")
|
ho = toHtmlObject [ ("foo", toHtmlObject "<fooval>")
|
||||||
, ("bar", toHtmlObject ["bar1", "bar2"])
|
, ("bar", toHtmlObject ["bar1", "bar2"])
|
||||||
]
|
]
|
||||||
hasreps = Template temp ho
|
hasreps = Template temp "o" ho $ return []
|
||||||
res1 = cs "foo:<fooval>, bar:bar1bar2"
|
res1 = cs "foo:<fooval>, bar:bar1bar2"
|
||||||
res2 = cs $ "{\"bar\":[\"bar1\",\"bar2\"]," ++
|
res2 = cs $ "{\"bar\":[\"bar1\",\"bar2\"]," ++
|
||||||
"\"foo\":\"<fooval>\"}"
|
"\"foo\":\"<fooval>\"}"
|
||||||
|
|||||||
@ -43,7 +43,7 @@ import Language.Haskell.TH.Ppr
|
|||||||
import System.IO
|
import System.IO
|
||||||
-}
|
-}
|
||||||
|
|
||||||
import Data.Typeable (Typeable)
|
import Data.Typeable
|
||||||
import Control.Exception (Exception)
|
import Control.Exception (Exception)
|
||||||
import Data.Attempt -- for failure stuff
|
import Data.Attempt -- for failure stuff
|
||||||
import Data.Object.Text
|
import Data.Object.Text
|
||||||
@ -62,7 +62,6 @@ import Test.Framework.Providers.QuickCheck (testProperty)
|
|||||||
import Test.HUnit hiding (Test)
|
import Test.HUnit hiding (Test)
|
||||||
import Test.QuickCheck
|
import Test.QuickCheck
|
||||||
import Control.Monad (when)
|
import Control.Monad (when)
|
||||||
import Data.Typeable
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
resources :: QuasiQuoter
|
resources :: QuasiQuoter
|
||||||
|
|||||||
38
Yesod/Template.hs
Normal file
38
Yesod/Template.hs
Normal 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
|
||||||
@ -16,6 +16,7 @@ import Yesod.Utils
|
|||||||
|
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (fromMaybe)
|
||||||
import Data.Convertible.Text
|
import Data.Convertible.Text
|
||||||
|
import Text.StringTemplate
|
||||||
|
|
||||||
import qualified Hack
|
import qualified Hack
|
||||||
import Hack.Middleware.CleanPath
|
import Hack.Middleware.CleanPath
|
||||||
@ -41,6 +42,10 @@ class Yesod a where
|
|||||||
errorHandler :: ErrorResult -> Handler a RepChooser
|
errorHandler :: ErrorResult -> Handler a RepChooser
|
||||||
errorHandler = defaultErrorHandler
|
errorHandler = defaultErrorHandler
|
||||||
|
|
||||||
|
-- | The template directory. Blank means no templates.
|
||||||
|
templateDir :: a -> FilePath
|
||||||
|
templateDir _ = ""
|
||||||
|
|
||||||
class Yesod a => YesodApproot a where
|
class Yesod a => YesodApproot a where
|
||||||
-- | An absolute URL to the root of the application.
|
-- | An absolute URL to the root of the application.
|
||||||
approot :: a -> Approot
|
approot :: a -> Approot
|
||||||
@ -80,7 +85,12 @@ toHackApp' y env = do
|
|||||||
verb = cs $ Hack.requestMethod env
|
verb = cs $ Hack.requestMethod env
|
||||||
handler = handlers resource verb
|
handler = handlers resource verb
|
||||||
rr = cs env
|
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
|
let langs = ["en"] -- FIXME
|
||||||
responseToHackResponse langs res
|
responseToHackResponse langs res
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
import Yesod
|
import Yesod
|
||||||
import Hack.Handler.SimpleServer
|
import Hack.Handler.SimpleServer
|
||||||
|
|
||||||
data HelloWorld = HelloWorld TemplateGroup
|
data HelloWorld = HelloWorld
|
||||||
instance Yesod HelloWorld where
|
instance Yesod HelloWorld where
|
||||||
handlers = [$resources|
|
handlers = [$resources|
|
||||||
/:
|
/:
|
||||||
@ -12,9 +12,7 @@ instance Yesod HelloWorld where
|
|||||||
/groups:
|
/groups:
|
||||||
Get: helloGroup
|
Get: helloGroup
|
||||||
|]
|
|]
|
||||||
|
templateDir _ = "examples"
|
||||||
instance YesodTemplates HelloWorld where
|
|
||||||
templates (HelloWorld g) = g
|
|
||||||
|
|
||||||
helloWorld :: Handler HelloWorld TemplateFile
|
helloWorld :: Handler HelloWorld TemplateFile
|
||||||
helloWorld = return $ TemplateFile "examples/template.html" $ cs
|
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>!")
|
, ("content", "Hey look!! I'm <auto escaped>!")
|
||||||
]
|
]
|
||||||
|
|
||||||
helloGroup = template "real-template" $ cs "foo"
|
helloGroup = template "real-template" "foo" (cs "bar") $ return []
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
putStrLn "Running..."
|
putStrLn "Running..."
|
||||||
stg <- loadTemplates "examples"
|
run 3000 $ toHackApp HelloWorld
|
||||||
run 3000 (toHackApp $ HelloWorld stg)
|
|
||||||
\end{code}
|
\end{code}
|
||||||
|
|||||||
@ -1 +1,2 @@
|
|||||||
This is a more realistic template.
|
This is a more realistic template.
|
||||||
|
foo: $foo$
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
{-# LANGUAGE QuasiQuotes #-}
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
|
|
||||||
import Yesod
|
import Yesod
|
||||||
|
import Text.StringTemplate (nullGroup)
|
||||||
|
|
||||||
data MyYesod = MyYesod
|
data MyYesod = MyYesod
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ ph h = do
|
|||||||
rr = error "No raw request"
|
rr = error "No raw request"
|
||||||
y = MyYesod
|
y = MyYesod
|
||||||
cts = [TypeHtml]
|
cts = [TypeHtml]
|
||||||
res <- runHandler h eh rr y cts
|
res <- runHandler h eh rr y nullGroup cts
|
||||||
print res
|
print res
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
|
|||||||
@ -51,7 +51,8 @@ library
|
|||||||
HStringTemplate >= 0.6.2 && < 0.7,
|
HStringTemplate >= 0.6.2 && < 0.7,
|
||||||
data-object-json >= 0.0.0 && < 0.1,
|
data-object-json >= 0.0.0 && < 0.1,
|
||||||
attempt >= 0.2.1 && < 0.3,
|
attempt >= 0.2.1 && < 0.3,
|
||||||
template-haskell
|
template-haskell,
|
||||||
|
failure >= 0.0.0 && < 0.1
|
||||||
exposed-modules: Yesod
|
exposed-modules: Yesod
|
||||||
Yesod.Constants
|
Yesod.Constants
|
||||||
Yesod.Rep
|
Yesod.Rep
|
||||||
@ -62,7 +63,7 @@ library
|
|||||||
Yesod.Handler
|
Yesod.Handler
|
||||||
Yesod.Resource
|
Yesod.Resource
|
||||||
Yesod.Yesod
|
Yesod.Yesod
|
||||||
Yesod.Templates
|
Yesod.Template
|
||||||
Data.Object.Html
|
Data.Object.Html
|
||||||
Hack.Middleware.MethodOverride
|
Hack.Middleware.MethodOverride
|
||||||
Hack.Middleware.ClientSession
|
Hack.Middleware.ClientSession
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user