Simplified GHandler/GWidget
This commit is contained in:
parent
fc6551c650
commit
4bdd01ef58
@ -49,7 +49,7 @@ module Yesod.Core
|
||||
, BottomOfHeadAsync
|
||||
-- * Subsites
|
||||
, defaultLayoutT
|
||||
, MonadHandlerBase (..)
|
||||
, MonadHandler (..)
|
||||
-- * Misc
|
||||
, yesodVersion
|
||||
, yesodRender
|
||||
@ -92,8 +92,8 @@ import Data.Version (showVersion)
|
||||
import Yesod.Routes.Class (RenderRoute (..))
|
||||
|
||||
-- | Return an 'Unauthorized' value, with the given i18n message.
|
||||
unauthorizedI :: RenderMessage master msg => msg -> GHandler sub master AuthResult
|
||||
unauthorizedI msg =do
|
||||
unauthorizedI :: RenderMessage site msg => msg -> GHandler site AuthResult
|
||||
unauthorizedI msg = do
|
||||
mr <- getMessageRender
|
||||
return $ Unauthorized $ mr msg
|
||||
|
||||
@ -104,37 +104,19 @@ yesodVersion = showVersion Paths_yesod_core.version
|
||||
--
|
||||
-- Built on top of 'isAuthorized'. This is useful for building page that only
|
||||
-- contain links to pages the user is allowed to see.
|
||||
maybeAuthorized :: Yesod a
|
||||
=> Route a
|
||||
maybeAuthorized :: Yesod site
|
||||
=> Route site
|
||||
-> Bool -- ^ is this a write request?
|
||||
-> GHandler s a (Maybe (Route a))
|
||||
-> GHandler site (Maybe (Route site))
|
||||
maybeAuthorized r isWrite = do
|
||||
x <- isAuthorized r isWrite
|
||||
return $ if x == Authorized then Just r else Nothing
|
||||
|
||||
class (MonadResource m, HandlerState m, Yesod (HandlerBase m)) => MonadHandlerBase m where
|
||||
type HandlerBase m
|
||||
type HandlerSite m
|
||||
liftHandler :: GHandler (HandlerBase m) (HandlerBase m) a -> m a
|
||||
askHandlerData :: m (HandlerData (HandlerSite m) (HandlerSite m))
|
||||
instance Yesod master => MonadHandlerBase (GHandler master master) where
|
||||
type HandlerBase (GHandler master master) = master
|
||||
type HandlerSite (GHandler master master) = master
|
||||
liftHandler = id
|
||||
askHandlerData = GHandler return
|
||||
instance MonadHandlerBase m => MonadHandlerBase (HandlerT sub m) where
|
||||
type HandlerBase (HandlerT sub m) = HandlerBase m
|
||||
type HandlerSite (HandlerT sub m) = sub
|
||||
liftHandler = lift . liftHandler
|
||||
askHandlerData = HandlerT return
|
||||
|
||||
defaultLayoutT :: ( HandlerState m
|
||||
, HandlerSite m ~ sub
|
||||
, Yesod (HandlerBase m)
|
||||
, MonadHandlerBase m
|
||||
, MonadResource m
|
||||
defaultLayoutT :: ( HandlerSite m ~ sub
|
||||
, Yesod (HandlerMaster m)
|
||||
, MonadHandler m
|
||||
)
|
||||
=> GWidget sub sub ()
|
||||
=> GWidget sub ()
|
||||
-> m RepHtml
|
||||
defaultLayoutT (GWidget (GHandler f)) = do
|
||||
hd <- askHandlerData
|
||||
|
||||
@ -8,14 +8,14 @@ import Data.Text (Text)
|
||||
-- | A type-safe, concise method of creating breadcrumbs for pages. For each
|
||||
-- resource, you declare the title of the page and the parent resource (if
|
||||
-- present).
|
||||
class YesodBreadcrumbs y where
|
||||
class YesodBreadcrumbs site where
|
||||
-- | Returns the title and the parent resource, if available. If you return
|
||||
-- a 'Nothing', then this is considered a top-level page.
|
||||
breadcrumb :: Route y -> GHandler sub y (Text , Maybe (Route y))
|
||||
breadcrumb :: Route site -> GHandler site (Text , Maybe (Route site))
|
||||
|
||||
-- | Gets the title of the current page and the hierarchy of parent pages,
|
||||
-- along with their respective titles.
|
||||
breadcrumbs :: YesodBreadcrumbs y => GHandler sub y (Text, [(Route y, Text)])
|
||||
breadcrumbs :: YesodBreadcrumbs site => GHandler site (Text, [(Route site, Text)])
|
||||
breadcrumbs = do
|
||||
x <- getCurrentRoute
|
||||
case x of
|
||||
|
||||
@ -18,56 +18,36 @@ import Control.Monad.Trans.Control (MonadBaseControl)
|
||||
|
||||
-- | This class is automatically instantiated when you use the template haskell
|
||||
-- mkYesod function. You should never need to deal with it directly.
|
||||
class YesodDispatch sub master where
|
||||
yesodDispatch
|
||||
:: Yesod master
|
||||
=> YesodRunnerEnv sub master
|
||||
-> W.Application
|
||||
|
||||
instance YesodDispatch WaiSubsite master where
|
||||
yesodDispatch YesodRunnerEnv { yreSub = WaiSubsite app } req =
|
||||
app req
|
||||
class Yesod site => YesodDispatch site where
|
||||
yesodDispatch :: YesodRunnerEnv site -> W.Application
|
||||
|
||||
class YesodSubDispatch sub m where
|
||||
yesodSubDispatch
|
||||
:: (HandlerError m, HandlerState m, master ~ HandlerMaster m, Yesod master, MonadBaseControl IO m)
|
||||
:: (MonadHandler m, master ~ HandlerMaster m, Yesod master)
|
||||
=> (m TypedContent
|
||||
-> YesodRunnerEnv master master
|
||||
-> YesodRunnerEnv master
|
||||
-> Maybe (Route master)
|
||||
-> W.Application)
|
||||
-> (master -> sub)
|
||||
-> (Route sub -> Route master)
|
||||
-> YesodRunnerEnv master master
|
||||
-> YesodRunnerEnv master
|
||||
-> W.Application
|
||||
|
||||
instance YesodSubDispatch WaiSubsite master where
|
||||
yesodSubDispatch _ toSub _ YesodRunnerEnv { yreMaster = master } req =
|
||||
yesodSubDispatch _ toSub _ YesodRunnerEnv { yreSite = site } req =
|
||||
app req
|
||||
where
|
||||
WaiSubsite app = toSub master
|
||||
WaiSubsite app = toSub site
|
||||
|
||||
{-
|
||||
subHelper :: Yesod master => (YesodRunnerEnv sub master -> W.Application)
|
||||
-> (forall res. ToTypedContent res
|
||||
=> m res
|
||||
-> YesodRunnerEnv master master
|
||||
-> Maybe (Route master)
|
||||
-> W.Application)
|
||||
-> (master -> sub)
|
||||
-> (Route sub -> Route master)
|
||||
-> W.Application
|
||||
subHelper runBase getSub toMaster = error "subHelper"
|
||||
-}
|
||||
|
||||
subHelper :: (HandlerMaster m ~ master, HandlerState m, MonadBaseControl IO m)
|
||||
subHelper :: (HandlerSite m ~ master, MonadHandler m)
|
||||
=> (m TypedContent
|
||||
-> YesodRunnerEnv master master
|
||||
-> YesodRunnerEnv master
|
||||
-> Maybe (Route master)
|
||||
-> W.Application)
|
||||
-> (master -> sub)
|
||||
-> (Route sub -> Route master)
|
||||
-> HandlerT sub m TypedContent
|
||||
-> YesodRunnerEnv master master
|
||||
-> YesodRunnerEnv master
|
||||
-> Maybe (Route sub)
|
||||
-> W.Application
|
||||
subHelper parentRunner getSub toMaster handlert env route =
|
||||
|
||||
@ -5,35 +5,38 @@
|
||||
module Yesod.Core.Class.Handler where
|
||||
|
||||
import Yesod.Core.Types
|
||||
import Yesod.Core.Types.Orphan ()
|
||||
import Yesod.Core.Class.MonadLift (lift)
|
||||
import Control.Monad.Trans.Class (MonadTrans)
|
||||
import Control.Monad.Trans.Resource
|
||||
import Control.Monad.Trans.Control
|
||||
import Data.IORef.Lifted (atomicModifyIORef)
|
||||
import Control.Exception.Lifted (throwIO)
|
||||
|
||||
class Monad m => HandlerReader m where
|
||||
type HandlerSub m
|
||||
type HandlerSite m
|
||||
type HandlerMaster m
|
||||
|
||||
askYesodRequest :: m YesodRequest
|
||||
askHandlerEnv :: m (RunHandlerEnv (HandlerSub m) (HandlerMaster m))
|
||||
askHandlerEnv :: m (RunHandlerEnv (HandlerSite m))
|
||||
|
||||
instance HandlerReader (GHandler sub master) where
|
||||
type HandlerSub (GHandler sub master) = sub
|
||||
type HandlerMaster (GHandler sub master) = master
|
||||
instance HandlerReader (GHandler site) where
|
||||
type HandlerSite (GHandler site) = site
|
||||
type HandlerMaster (GHandler site) = site
|
||||
|
||||
askYesodRequest = GHandler $ return . handlerRequest
|
||||
askHandlerEnv = GHandler $ return . handlerEnv
|
||||
|
||||
instance HandlerReader (GWidget sub master) where
|
||||
type HandlerSub (GWidget sub master) = sub
|
||||
type HandlerMaster (GWidget sub master) = master
|
||||
instance HandlerReader m => HandlerReader (HandlerT site m) where
|
||||
type HandlerSite (HandlerT site m) = site
|
||||
type HandlerMaster (HandlerT site m) = HandlerMaster m
|
||||
|
||||
askYesodRequest = lift askYesodRequest
|
||||
askHandlerEnv = lift askHandlerEnv
|
||||
askYesodRequest = HandlerT $ return . handlerRequest
|
||||
askHandlerEnv = HandlerT $ return . handlerEnv
|
||||
|
||||
instance (MonadTrans t, HandlerReader m, Monad (t m)) => HandlerReader (t m) where
|
||||
type HandlerSub (t m) = HandlerSub m
|
||||
type HandlerMaster (t m) = HandlerMaster m
|
||||
instance HandlerReader (GWidget site) where
|
||||
type HandlerSite (GWidget site) = site
|
||||
type HandlerMaster (GWidget site) = site
|
||||
|
||||
askYesodRequest = lift askYesodRequest
|
||||
askHandlerEnv = lift askHandlerEnv
|
||||
@ -47,26 +50,26 @@ class HandlerReader m => HandlerState m where
|
||||
putGHState :: GHState -> m ()
|
||||
putGHState s = stateGHState $ const ((), s)
|
||||
|
||||
instance HandlerState (GHandler sub master) where
|
||||
instance HandlerState (GHandler site) where
|
||||
stateGHState f =
|
||||
GHandler $ flip atomicModifyIORef f' . handlerState
|
||||
where
|
||||
f' z = let (x, y) = f z in (y, x)
|
||||
|
||||
instance HandlerState (GWidget sub master) where
|
||||
instance HandlerState (GWidget site) where
|
||||
stateGHState = lift . stateGHState
|
||||
|
||||
instance (MonadTrans t, HandlerState m, Monad (t m)) => HandlerState (t m) where
|
||||
instance HandlerState m => HandlerState (HandlerT site m) where
|
||||
stateGHState = lift . stateGHState
|
||||
|
||||
class HandlerReader m => HandlerError m where
|
||||
handlerError :: HandlerContents -> m a
|
||||
|
||||
instance HandlerError (GHandler sub master) where
|
||||
instance HandlerError (GHandler site) where
|
||||
handlerError = throwIO
|
||||
|
||||
instance HandlerError (GWidget sub master) where
|
||||
instance HandlerError (GWidget site) where
|
||||
handlerError = lift . handlerError
|
||||
|
||||
instance (HandlerError m, MonadTrans t, Monad (t m)) => HandlerError (t m) where
|
||||
instance HandlerError m => HandlerError (HandlerT site m) where
|
||||
handlerError = lift . handlerError
|
||||
|
||||
@ -6,7 +6,8 @@ module Yesod.Core.Class.Yesod where
|
||||
|
||||
import Control.Monad.Logger (logErrorS)
|
||||
import Yesod.Core.Content
|
||||
import Yesod.Core.Handler hiding (getExpires)
|
||||
import Yesod.Core.Handler
|
||||
import Yesod.Core.Class.Handler
|
||||
|
||||
import Yesod.Routes.Class
|
||||
|
||||
@ -17,6 +18,8 @@ import Control.Monad (forM)
|
||||
import Control.Monad.IO.Class (MonadIO (liftIO))
|
||||
import Control.Monad.Logger (LogLevel (LevelInfo, LevelOther),
|
||||
LogSource)
|
||||
import Control.Monad.Trans.Resource
|
||||
import Control.Monad.Trans.Control
|
||||
import qualified Data.ByteString.Char8 as S8
|
||||
import qualified Data.ByteString.Lazy as L
|
||||
import Data.Aeson (object, (.=))
|
||||
@ -77,11 +80,11 @@ class RenderRoute a => Yesod a where
|
||||
approot = ApprootRelative
|
||||
|
||||
-- | Output error response pages.
|
||||
errorHandler :: ErrorResponse -> GHandler sub a TypedContent
|
||||
errorHandler :: ErrorResponse -> GHandler a TypedContent
|
||||
errorHandler = defaultErrorHandler
|
||||
|
||||
-- | Applies some form of layout to the contents of a page.
|
||||
defaultLayout :: GWidget sub a () -> GHandler sub a RepHtml
|
||||
defaultLayout :: GWidget a () -> GHandler a RepHtml
|
||||
defaultLayout w = do
|
||||
p <- widgetToPageContent w
|
||||
mmsg <- getMessage
|
||||
@ -112,7 +115,7 @@ $doctype 5
|
||||
-- If authentication is required, return 'AuthenticationRequired'.
|
||||
isAuthorized :: Route a
|
||||
-> Bool -- ^ is this a write request?
|
||||
-> GHandler s a AuthResult
|
||||
-> GHandler a AuthResult
|
||||
isAuthorized _ _ = return Authorized
|
||||
|
||||
-- | Determines whether the current request is a write request. By default,
|
||||
@ -122,7 +125,7 @@ $doctype 5
|
||||
--
|
||||
-- This function is used to determine if a request is authorized; see
|
||||
-- 'isAuthorized'.
|
||||
isWriteRequest :: Route a -> GHandler s a Bool
|
||||
isWriteRequest :: Route a -> GHandler a Bool
|
||||
isWriteRequest _ = do
|
||||
wai <- waiRequest
|
||||
return $ W.requestMethod wai `notElem`
|
||||
@ -188,7 +191,7 @@ $doctype 5
|
||||
addStaticContent :: Text -- ^ filename extension
|
||||
-> Text -- ^ mime-type
|
||||
-> L.ByteString -- ^ content
|
||||
-> GHandler sub a (Maybe (Either Text (Route a, [(Text, Text)])))
|
||||
-> GHandler a (Maybe (Either Text (Route a, [(Text, Text)])))
|
||||
addStaticContent _ _ _ = return Nothing
|
||||
|
||||
{- Temporarily disabled until we have a better interface.
|
||||
@ -274,7 +277,7 @@ $doctype 5
|
||||
-- performs authorization checks.
|
||||
--
|
||||
-- Since: 1.1.6
|
||||
yesodMiddleware :: GHandler sub a res -> GHandler sub a res
|
||||
yesodMiddleware :: GHandler a res -> GHandler a res
|
||||
yesodMiddleware handler = do
|
||||
setHeader "Vary" "Accept, Accept-Language"
|
||||
route <- getCurrentRoute
|
||||
@ -297,9 +300,9 @@ $doctype 5
|
||||
handler
|
||||
|
||||
-- | Convert a widget to a 'PageContent'.
|
||||
widgetToPageContent :: (Eq (Route master), Yesod master)
|
||||
=> GWidget sub master ()
|
||||
-> GHandler sub master (PageContent (Route master))
|
||||
widgetToPageContent :: (Eq (Route site), Yesod site)
|
||||
=> GWidget site ()
|
||||
-> GHandler site (PageContent (Route site))
|
||||
widgetToPageContent w = do
|
||||
master <- getYesod
|
||||
((), GWData (Body body) (Last mTitle) scripts' stylesheets' style jscript (Head head')) <- unGWidget w
|
||||
@ -393,7 +396,7 @@ $newline never
|
||||
runUniqueList (UniqueList x) = nub $ x []
|
||||
|
||||
-- | The default error handler for 'errorHandler'.
|
||||
defaultErrorHandler :: Yesod y => ErrorResponse -> GHandler sub y TypedContent
|
||||
defaultErrorHandler :: Yesod site => ErrorResponse -> GHandler site TypedContent
|
||||
defaultErrorHandler NotFound = selectRep $ do
|
||||
provideRep $ defaultLayout $ do
|
||||
r <- lift waiRequest
|
||||
@ -557,3 +560,14 @@ fileLocationToString loc = (loc_package loc) ++ ':' : (loc_module loc) ++
|
||||
where
|
||||
line = show . fst . loc_start
|
||||
char = show . snd . loc_start
|
||||
|
||||
class (MonadBaseControl IO m, HandlerState m, HandlerError m, MonadResource m, Yesod (HandlerMaster m)) => MonadHandler m where
|
||||
liftHandler :: GHandler (HandlerMaster m) a -> m a
|
||||
askHandlerData :: m (HandlerData (HandlerSite m))
|
||||
|
||||
instance Yesod site => MonadHandler (GHandler site) where
|
||||
liftHandler = id
|
||||
askHandlerData = GHandler return
|
||||
instance MonadHandler m => MonadHandler (HandlerT site m) where
|
||||
liftHandler = lift . liftHandler
|
||||
askHandlerData = HandlerT return
|
||||
|
||||
@ -122,8 +122,8 @@ mkYesodGeneral name args clazzes isSub resS = do
|
||||
context = if isSub then cxt $ yesod : map return clazzes
|
||||
else return []
|
||||
yesod = classP ''HandlerReader [master]
|
||||
handler = tySynD (mkName "Handler") [] [t| GHandler $master $master |]
|
||||
widget = tySynD (mkName "Widget") [] [t| GWidget $master $master () |]
|
||||
handler = tySynD (mkName "Handler") [] [t| GHandler $master |]
|
||||
widget = tySynD (mkName "Widget") [] [t| GWidget $master () |]
|
||||
res = map (fmap parseType) resS
|
||||
subCons = conT $ mkName name
|
||||
subArgs = map (varT. mkName) args
|
||||
@ -139,7 +139,7 @@ mkDispatchInstance :: CxtQ -- ^ The context
|
||||
-> [ResourceTree a] -- ^ The resource
|
||||
-> DecsQ
|
||||
mkDispatchInstance context _sub master res = do
|
||||
let yDispatch = conT ''YesodDispatch `appT` master `appT` master
|
||||
let yDispatch = conT ''YesodDispatch `appT` master
|
||||
thisDispatch = do
|
||||
clause' <- mkDispatchClause MkDispatchSettings
|
||||
{ mdsRunHandler = [|yesodRunner|]
|
||||
@ -199,38 +199,30 @@ mkYesodSubDispatch res = do
|
||||
-- handler. This is the same as 'toWaiAppPlain', except it includes two
|
||||
-- middlewares: GZIP compression and autohead. This is the
|
||||
-- recommended approach for most users.
|
||||
toWaiApp :: ( Yesod master
|
||||
, YesodDispatch master master
|
||||
) => master -> IO W.Application
|
||||
toWaiApp :: YesodDispatch site => site -> IO W.Application
|
||||
toWaiApp y = gzip (gzipSettings y) . autohead <$> toWaiAppPlain y
|
||||
|
||||
-- | Convert the given argument into a WAI application, executable with any WAI
|
||||
-- handler. This differs from 'toWaiApp' in that it uses no middlewares.
|
||||
toWaiAppPlain :: ( Yesod master
|
||||
, YesodDispatch master master
|
||||
) => master -> IO W.Application
|
||||
toWaiAppPlain :: YesodDispatch site => site -> IO W.Application
|
||||
toWaiAppPlain a = toWaiApp' a <$> getLogger a <*> makeSessionBackend a
|
||||
|
||||
|
||||
toWaiApp' :: ( Yesod master
|
||||
, YesodDispatch master master
|
||||
)
|
||||
=> master
|
||||
toWaiApp' :: YesodDispatch site
|
||||
=> site
|
||||
-> Logger
|
||||
-> Maybe SessionBackend
|
||||
-> W.Application
|
||||
toWaiApp' y logger sb req =
|
||||
case cleanPath y $ W.pathInfo req of
|
||||
Left pieces -> sendRedirect y pieces req
|
||||
toWaiApp' site logger sb req =
|
||||
case cleanPath site $ W.pathInfo req of
|
||||
Left pieces -> sendRedirect site pieces req
|
||||
Right pieces -> yesodDispatch yre req
|
||||
{ W.pathInfo = pieces
|
||||
}
|
||||
where
|
||||
yre = YesodRunnerEnv
|
||||
{ yreLogger = logger
|
||||
, yreMaster = y
|
||||
, yreSub = y
|
||||
, yreToMaster = id
|
||||
, yreSite = site
|
||||
, yreSessionBackend = sb
|
||||
}
|
||||
|
||||
|
||||
@ -25,12 +25,9 @@ module Yesod.Core.Handler
|
||||
, HandlerT
|
||||
-- ** Read information from handler
|
||||
, getYesod
|
||||
, getYesodSub
|
||||
, getUrlRender
|
||||
, getUrlRenderParams
|
||||
, getCurrentRoute
|
||||
, getCurrentRouteSub
|
||||
, getRouteToMaster
|
||||
, getRequest
|
||||
, waiRequest
|
||||
, runRequestBody
|
||||
@ -132,7 +129,7 @@ import Yesod.Core.Internal.Request (langKey, mkFileInfoFile,
|
||||
|
||||
import Control.Applicative ((<$>), (<|>))
|
||||
|
||||
import Control.Monad (ap, liftM)
|
||||
import Control.Monad (liftM)
|
||||
import qualified Control.Monad.Trans.Writer as Writer
|
||||
|
||||
import Control.Monad.IO.Class (MonadIO, liftIO)
|
||||
@ -233,16 +230,12 @@ rbHelper' backend mkFI req =
|
||||
| otherwise = a'
|
||||
go = decodeUtf8With lenientDecode
|
||||
|
||||
-- | Get the sub application argument.
|
||||
getYesodSub :: HandlerReader m => m (HandlerSub m)
|
||||
getYesodSub = rheSub `liftM` askHandlerEnv
|
||||
|
||||
-- | Get the master site appliation argument.
|
||||
getYesod :: HandlerReader m => m (HandlerMaster m)
|
||||
getYesod = rheMaster `liftM` askHandlerEnv
|
||||
getYesod :: HandlerReader m => m (HandlerSite m)
|
||||
getYesod = rheSite `liftM` askHandlerEnv
|
||||
|
||||
-- | Get the URL rendering function.
|
||||
getUrlRender :: HandlerReader m => m (Route (HandlerMaster m) -> Text)
|
||||
getUrlRender :: HandlerReader m => m (Route (HandlerSite m) -> Text)
|
||||
getUrlRender = do
|
||||
x <- rheRender `liftM` askHandlerEnv
|
||||
return $ flip x []
|
||||
@ -250,23 +243,13 @@ getUrlRender = do
|
||||
-- | The URL rendering function with query-string parameters.
|
||||
getUrlRenderParams
|
||||
:: HandlerReader m
|
||||
=> m (Route (HandlerMaster m) -> [(Text, Text)] -> Text)
|
||||
=> m (Route (HandlerSite m) -> [(Text, Text)] -> Text)
|
||||
getUrlRenderParams = rheRender `liftM` askHandlerEnv
|
||||
|
||||
-- | Get the route requested by the user. If this is a 404 response- where the
|
||||
-- user requested an invalid route- this function will return 'Nothing'.
|
||||
getCurrentRoute :: HandlerReader m => m (Maybe (Route (HandlerMaster m)))
|
||||
getCurrentRoute = fmap `liftM` getRouteToMaster `ap` getCurrentRouteSub
|
||||
|
||||
-- | Same as 'getCurrentRoute', but for the subsite.
|
||||
getCurrentRouteSub :: HandlerReader m => m (Maybe (Route (HandlerSub m)))
|
||||
getCurrentRouteSub = rheRoute `liftM` askHandlerEnv
|
||||
|
||||
-- | Get the function to promote a route for a subsite to a route for the
|
||||
-- master site.
|
||||
getRouteToMaster :: HandlerReader m => m (Route (HandlerSub m) -> Route (HandlerMaster m))
|
||||
getRouteToMaster = rheToMaster `liftM` askHandlerEnv
|
||||
|
||||
getCurrentRoute :: HandlerReader m => m (Maybe (Route (HandlerSite m)))
|
||||
getCurrentRoute = rheRoute `liftM` askHandlerEnv
|
||||
|
||||
-- | Returns a function that runs 'GHandler' actions inside @IO@.
|
||||
--
|
||||
@ -304,7 +287,7 @@ getRouteToMaster = rheToMaster `liftM` askHandlerEnv
|
||||
-- This allows the inner 'GHandler' to outlive the outer
|
||||
-- 'GHandler' (e.g., on the @forkIO@ example above, a response
|
||||
-- may be sent to the client without killing the new thread).
|
||||
handlerToIO :: MonadIO m => GHandler sub master (GHandler sub master a -> m a)
|
||||
handlerToIO :: MonadIO m => GHandler site (GHandler site a -> m a)
|
||||
handlerToIO =
|
||||
GHandler $ \oldHandlerData -> do
|
||||
-- Let go of the request body, cache and response headers.
|
||||
@ -344,7 +327,7 @@ handlerToIO =
|
||||
--
|
||||
-- If you want direct control of the final status code, or need a different
|
||||
-- status code, please use 'redirectWith'.
|
||||
redirect :: (HandlerError m, RedirectUrl (HandlerMaster m) url, HandlerReader m)
|
||||
redirect :: (HandlerError m, RedirectUrl (HandlerSite m) url, HandlerReader m)
|
||||
=> url -> m a
|
||||
redirect url = do
|
||||
req <- waiRequest
|
||||
@ -355,7 +338,7 @@ redirect url = do
|
||||
redirectWith status url
|
||||
|
||||
-- | Redirect to the given URL with the specified status code.
|
||||
redirectWith :: (HandlerError m, RedirectUrl (HandlerMaster m) url, HandlerReader m)
|
||||
redirectWith :: (HandlerError m, RedirectUrl (HandlerSite m) url, HandlerReader m)
|
||||
=> H.Status
|
||||
-> url
|
||||
-> m a
|
||||
@ -370,7 +353,7 @@ ultDestKey = "_ULT"
|
||||
--
|
||||
-- An ultimate destination is stored in the user session and can be loaded
|
||||
-- later by 'redirectUltDest'.
|
||||
setUltDest :: (HandlerState m, RedirectUrl (HandlerMaster m) url)
|
||||
setUltDest :: (HandlerState m, RedirectUrl (HandlerSite m) url)
|
||||
=> url
|
||||
-> m ()
|
||||
setUltDest url = do
|
||||
@ -410,7 +393,7 @@ setUltDestReferer = do
|
||||
--
|
||||
-- This function uses 'redirect', and thus will perform a temporary redirect to
|
||||
-- a GET request.
|
||||
redirectUltDest :: (RedirectUrl (HandlerMaster m) url, HandlerState m, HandlerError m)
|
||||
redirectUltDest :: (RedirectUrl (HandlerSite m) url, HandlerState m, HandlerError m)
|
||||
=> url -- ^ default destination if nothing in session
|
||||
-> m a
|
||||
redirectUltDest def = do
|
||||
@ -434,7 +417,7 @@ setMessage = setSession msgKey . T.concat . TL.toChunks . RenderText.renderHtml
|
||||
-- | Sets a message in the user's session.
|
||||
--
|
||||
-- See 'getMessage'.
|
||||
setMessageI :: (HandlerState m, RenderMessage (HandlerMaster m) msg)
|
||||
setMessageI :: (HandlerState m, RenderMessage (HandlerSite m) msg)
|
||||
=> msg -> m ()
|
||||
setMessageI msg = do
|
||||
mr <- getMessageRender
|
||||
@ -479,7 +462,7 @@ sendResponseStatus s = handlerError . HCContent s . toTypedContent
|
||||
|
||||
-- | Send a 201 "Created" response with the given route as the Location
|
||||
-- response header.
|
||||
sendResponseCreated :: HandlerError m => Route (HandlerMaster m) -> m a
|
||||
sendResponseCreated :: HandlerError m => Route (HandlerSite m) -> m a
|
||||
sendResponseCreated url = do
|
||||
r <- getUrlRender
|
||||
handlerError $ HCCreated $ r url
|
||||
@ -507,7 +490,7 @@ permissionDenied :: HandlerError m => Text -> m a
|
||||
permissionDenied = hcError . PermissionDenied
|
||||
|
||||
-- | Return a 403 permission denied page.
|
||||
permissionDeniedI :: (RenderMessage (HandlerMaster m) msg, HandlerError m)
|
||||
permissionDeniedI :: (RenderMessage (HandlerSite m) msg, HandlerError m)
|
||||
=> msg
|
||||
-> m a
|
||||
permissionDeniedI msg = do
|
||||
@ -519,7 +502,7 @@ invalidArgs :: HandlerError m => [Text] -> m a
|
||||
invalidArgs = hcError . InvalidArgs
|
||||
|
||||
-- | Return a 400 invalid arguments page.
|
||||
invalidArgsI :: (HandlerError m, RenderMessage (HandlerMaster m) msg) => [msg] -> m a
|
||||
invalidArgsI :: (HandlerError m, RenderMessage (HandlerSite m) msg) => [msg] -> m a
|
||||
invalidArgsI msg = do
|
||||
mr <- getMessageRender
|
||||
invalidArgs $ map mr msg
|
||||
@ -623,7 +606,7 @@ addHeader = tell . Endo . (:)
|
||||
-- | Some value which can be turned into a URL for redirects.
|
||||
class RedirectUrl master a where
|
||||
-- | Converts the value to the URL and a list of query-string parameters.
|
||||
toTextUrl :: (HandlerReader m, HandlerMaster m ~ master) => a -> m Text
|
||||
toTextUrl :: (HandlerReader m, HandlerSite m ~ master) => a -> m Text
|
||||
|
||||
instance RedirectUrl master Text where
|
||||
toTextUrl = return
|
||||
@ -672,7 +655,7 @@ newIdent = do
|
||||
-- POST form, and some Javascript to automatically submit the form. This can be
|
||||
-- useful when you need to post a plain link somewhere that needs to cause
|
||||
-- changes on the server.
|
||||
redirectToPost :: (HandlerError m, RedirectUrl (HandlerMaster m) url)
|
||||
redirectToPost :: (HandlerError m, RedirectUrl (HandlerSite m) url)
|
||||
=> url
|
||||
-> m a
|
||||
redirectToPost url = do
|
||||
@ -692,7 +675,7 @@ $doctype 5
|
||||
|] >>= sendResponse
|
||||
|
||||
-- | Wraps the 'Content' generated by 'hamletToContent' in a 'RepHtml'.
|
||||
hamletToRepHtml :: HandlerReader m => HtmlUrl (Route (HandlerMaster m)) -> m Html
|
||||
hamletToRepHtml :: HandlerReader m => HtmlUrl (Route (HandlerSite m)) -> m Html
|
||||
hamletToRepHtml = giveUrlRenderer
|
||||
|
||||
-- | Provide a URL rendering function to the given function and return the
|
||||
@ -700,7 +683,7 @@ hamletToRepHtml = giveUrlRenderer
|
||||
--
|
||||
-- Since 1.2.0
|
||||
giveUrlRenderer :: HandlerReader m
|
||||
=> ((Route (HandlerMaster m) -> [(Text, Text)] -> Text) -> output)
|
||||
=> ((Route (HandlerSite m) -> [(Text, Text)] -> Text) -> output)
|
||||
-> m output
|
||||
giveUrlRenderer f = do
|
||||
render <- getUrlRenderParams
|
||||
@ -710,7 +693,7 @@ giveUrlRenderer f = do
|
||||
waiRequest :: HandlerReader m => m W.Request
|
||||
waiRequest = reqWaiRequest `liftM` getRequest
|
||||
|
||||
getMessageRender :: (HandlerReader m, RenderMessage (HandlerMaster m) message)
|
||||
getMessageRender :: (HandlerReader m, RenderMessage (HandlerSite m) message)
|
||||
=> m (message -> Text)
|
||||
getMessageRender = do
|
||||
m <- getYesod
|
||||
|
||||
@ -11,10 +11,9 @@ import Yesod.Core.Class.Handler
|
||||
import Blaze.ByteString.Builder (toByteString)
|
||||
import Control.Applicative ((<$>))
|
||||
import Control.Exception (fromException)
|
||||
import Control.Exception.Lifted (catch, finally)
|
||||
import Control.Exception.Lifted (catch)
|
||||
import Control.Monad.IO.Class (MonadIO)
|
||||
import Control.Monad.IO.Class (liftIO)
|
||||
import Control.Monad.Base (liftBase)
|
||||
import Control.Monad.Logger (LogLevel (LevelError), LogSource,
|
||||
liftLoc)
|
||||
import Control.Monad.Trans.Resource (runResourceT)
|
||||
@ -48,8 +47,8 @@ import Yesod.Routes.Class (Route, renderRoute)
|
||||
-- | Function used internally by Yesod in the process of converting a
|
||||
-- 'GHandler' into an 'Application'. Should not be needed by users.
|
||||
runHandler :: ToTypedContent c
|
||||
=> RunHandlerEnv sub master
|
||||
-> GHandler sub master c
|
||||
=> RunHandlerEnv site
|
||||
-> GHandler site c
|
||||
-> YesodApp
|
||||
runHandler rhe@RunHandlerEnv {..} handler yreq = do
|
||||
let toErrorHandler e =
|
||||
@ -149,25 +148,23 @@ safeEh log' er req = do
|
||||
-- @GHandler@ is completely ignored, including changes to the
|
||||
-- session, cookies or headers. We only return you the
|
||||
-- @GHandler@'s return value.
|
||||
runFakeHandler :: (Yesod master, MonadIO m) =>
|
||||
runFakeHandler :: (Yesod site, MonadIO m) =>
|
||||
SessionMap
|
||||
-> (master -> Logger)
|
||||
-> master
|
||||
-> GHandler master master a
|
||||
-> (site -> Logger)
|
||||
-> site
|
||||
-> GHandler site a
|
||||
-> m (Either ErrorResponse a)
|
||||
runFakeHandler fakeSessionMap logger master handler = liftIO $ do
|
||||
runFakeHandler fakeSessionMap logger site handler = liftIO $ do
|
||||
ret <- I.newIORef (Left $ InternalError "runFakeHandler: no result")
|
||||
let handler' = do liftIO . I.writeIORef ret . Right =<< handler
|
||||
return ()
|
||||
let yapp = runHandler
|
||||
RunHandlerEnv
|
||||
{ rheRender = yesodRender master $ resolveApproot master fakeWaiRequest
|
||||
{ rheRender = yesodRender site $ resolveApproot site fakeWaiRequest
|
||||
, rheRoute = Nothing
|
||||
, rheToMaster = id
|
||||
, rheMaster = master
|
||||
, rheSub = master
|
||||
, rheUpload = fileUpload master
|
||||
, rheLog = messageLoggerSource master $ logger master
|
||||
, rheSite = site
|
||||
, rheUpload = fileUpload site
|
||||
, rheLog = messageLoggerSource site $ logger site
|
||||
, rheOnError = errHandler
|
||||
}
|
||||
handler'
|
||||
@ -210,10 +207,10 @@ runFakeHandler fakeSessionMap logger master handler = liftIO $ do
|
||||
I.readIORef ret
|
||||
{-# WARNING runFakeHandler "Usually you should *not* use runFakeHandler unless you really understand how it works and why you need it." #-}
|
||||
|
||||
yesodRunner :: (ToTypedContent res, Yesod master)
|
||||
=> GHandler sub master res
|
||||
-> YesodRunnerEnv sub master
|
||||
-> Maybe (Route sub)
|
||||
yesodRunner :: (ToTypedContent res, Yesod site)
|
||||
=> GHandler site res
|
||||
-> YesodRunnerEnv site
|
||||
-> Maybe (Route site)
|
||||
-> Application
|
||||
yesodRunner handler' YesodRunnerEnv {..} route req
|
||||
| KnownLength len <- requestBodyLength req, maxLen < len = return tooLargeResponse
|
||||
@ -226,19 +223,17 @@ yesodRunner handler' YesodRunnerEnv {..} route req
|
||||
case mkYesodReq of
|
||||
Left yreq -> return yreq
|
||||
Right needGen -> liftIO $ needGen <$> newStdGen
|
||||
let ra = resolveApproot yreMaster req
|
||||
let log' = messageLoggerSource yreMaster yreLogger
|
||||
let ra = resolveApproot yreSite req
|
||||
let log' = messageLoggerSource yreSite yreLogger
|
||||
-- We set up two environments: the first one has a "safe" error handler
|
||||
-- which will never throw an exception. The second one uses the
|
||||
-- user-provided errorHandler function. If that errorHandler function
|
||||
-- errors out, it will use the safeEh below to recover.
|
||||
rheSafe = RunHandlerEnv
|
||||
{ rheRender = yesodRender yreMaster ra
|
||||
{ rheRender = yesodRender yreSite ra
|
||||
, rheRoute = route
|
||||
, rheToMaster = yreToMaster
|
||||
, rheMaster = yreMaster
|
||||
, rheSub = yreSub
|
||||
, rheUpload = fileUpload yreMaster
|
||||
, rheSite = yreSite
|
||||
, rheUpload = fileUpload yreSite
|
||||
, rheLog = log'
|
||||
, rheOnError = safeEh log'
|
||||
}
|
||||
@ -248,7 +243,7 @@ yesodRunner handler' YesodRunnerEnv {..} route req
|
||||
yar <- runHandler rhe handler yreq
|
||||
liftIO $ yarToResponse yar saveSession yreq
|
||||
where
|
||||
maxLen = maximumContentLength yreMaster $ fmap yreToMaster route
|
||||
maxLen = maximumContentLength yreSite route
|
||||
handler = yesodMiddleware handler'
|
||||
|
||||
yesodRender :: Yesod y
|
||||
@ -274,38 +269,20 @@ resolveApproot master req =
|
||||
ApprootMaster f -> f master
|
||||
ApprootRequest f -> f master req
|
||||
|
||||
fixEnv :: (oldSub -> newSub)
|
||||
-> (Route newSub -> Route oldSub)
|
||||
-> YesodRunnerEnv oldSub master
|
||||
-> YesodRunnerEnv newSub master
|
||||
fixEnv toNewSub toOldRoute envOld =
|
||||
envOld
|
||||
{ yreSub = toNewSub $ yreSub envOld
|
||||
, yreToMaster = yreToMaster envOld . toOldRoute
|
||||
}
|
||||
|
||||
stripHandlerT :: (HandlerState m, MonadBaseControl IO m)
|
||||
stripHandlerT :: (MonadHandler m, MonadBaseControl IO m)
|
||||
=> HandlerT sub m a
|
||||
-> (HandlerMaster m -> sub)
|
||||
-> (Route sub -> Route (HandlerMaster m))
|
||||
-> (HandlerSite m -> sub)
|
||||
-> (Route sub -> Route (HandlerSite m))
|
||||
-> Maybe (Route sub)
|
||||
-> m a
|
||||
stripHandlerT (HandlerT f) getSub toMaster newRoute = do
|
||||
yreq <- askYesodRequest
|
||||
env <- askHandlerEnv
|
||||
ghs <- getGHState
|
||||
ighs <- liftBase $ I.newIORef ghs
|
||||
hd <- askHandlerData
|
||||
|
||||
let sub = getSub $ rheMaster env
|
||||
hd = HandlerData
|
||||
{ handlerRequest = yreq
|
||||
, handlerEnv = env
|
||||
{ rheMaster = sub
|
||||
, rheSub = sub
|
||||
, rheToMaster = id
|
||||
, rheRoute = newRoute
|
||||
, rheRender = \url params -> rheRender env (toMaster url) params
|
||||
}
|
||||
, handlerState = ighs
|
||||
let env = handlerEnv hd
|
||||
f hd
|
||||
{ handlerEnv = env
|
||||
{ rheSite = getSub $ rheSite env
|
||||
, rheRoute = newRoute
|
||||
, rheRender = \url params -> rheRender env (toMaster url) params
|
||||
}
|
||||
f hd `finally` (liftBase (I.readIORef ighs) >>= putGHState)
|
||||
}
|
||||
|
||||
@ -44,10 +44,10 @@ import Data.Maybe (listToMaybe)
|
||||
-- ('defaultLayout').
|
||||
--
|
||||
-- /Since: 0.3.0/
|
||||
defaultLayoutJson :: (Yesod master, J.ToJSON a)
|
||||
=> GWidget sub master () -- ^ HTML
|
||||
-> GHandler sub master a -- ^ JSON
|
||||
-> GHandler sub master TypedContent
|
||||
defaultLayoutJson :: (Yesod site, J.ToJSON a)
|
||||
=> GWidget site () -- ^ HTML
|
||||
-> GHandler site a -- ^ JSON
|
||||
-> GHandler site TypedContent
|
||||
defaultLayoutJson w json = selectRep $ do
|
||||
provideRep $ defaultLayout w
|
||||
provideRep $ fmap J.toJSON json
|
||||
@ -56,7 +56,7 @@ defaultLayoutJson w json = selectRep $ do
|
||||
-- support conversion to JSON via 'J.ToJSON'.
|
||||
--
|
||||
-- /Since: 0.3.0/
|
||||
jsonToRepJson :: J.ToJSON a => a -> GHandler sub master J.Value
|
||||
jsonToRepJson :: J.ToJSON a => a -> GHandler site J.Value
|
||||
jsonToRepJson = return . J.toJSON
|
||||
|
||||
-- | Parse the request body to a data type as a JSON value. The
|
||||
@ -65,7 +65,7 @@ jsonToRepJson = return . J.toJSON
|
||||
-- 'J.Value'@.
|
||||
--
|
||||
-- /Since: 0.3.0/
|
||||
parseJsonBody :: J.FromJSON a => GHandler sub master (J.Result a)
|
||||
parseJsonBody :: J.FromJSON a => GHandler site (J.Result a)
|
||||
parseJsonBody = do
|
||||
req <- waiRequest
|
||||
eValue <- lift
|
||||
@ -78,7 +78,7 @@ parseJsonBody = do
|
||||
|
||||
-- | Same as 'parseJsonBody', but return an invalid args response on a parse
|
||||
-- error.
|
||||
parseJsonBody_ :: J.FromJSON a => GHandler sub master a
|
||||
parseJsonBody_ :: J.FromJSON a => GHandler site a
|
||||
parseJsonBody_ = do
|
||||
ra <- parseJsonBody
|
||||
case ra of
|
||||
@ -96,10 +96,10 @@ array = J.Array . V.fromList . map J.toJSON
|
||||
-- @application\/json@ (e.g. AJAX, see 'acceptsJSON').
|
||||
--
|
||||
-- 2. 3xx otherwise, following the PRG pattern.
|
||||
jsonOrRedirect :: (Yesod master, J.ToJSON a)
|
||||
=> Route master -- ^ Redirect target
|
||||
jsonOrRedirect :: (Yesod site, J.ToJSON a)
|
||||
=> Route site -- ^ Redirect target
|
||||
-> a -- ^ Data to send via JSON
|
||||
-> GHandler sub master J.Value
|
||||
-> GHandler site J.Value
|
||||
jsonOrRedirect r j = do
|
||||
q <- acceptsJson
|
||||
if q then jsonToRepJson (J.toJSON j)
|
||||
@ -107,7 +107,7 @@ jsonOrRedirect r j = do
|
||||
|
||||
-- | Returns @True@ if the client prefers @application\/json@ as
|
||||
-- indicated by the @Accept@ HTTP header.
|
||||
acceptsJson :: Yesod master => GHandler sub master Bool
|
||||
acceptsJson :: Yesod site => GHandler site Bool
|
||||
acceptsJson = maybe False ((== "application/json") . B8.takeWhile (/= ';'))
|
||||
. join
|
||||
. fmap (listToMaybe . parseHttpAccept)
|
||||
|
||||
@ -166,12 +166,10 @@ type Texts = [Text]
|
||||
-- | Wrap up a normal WAI application as a Yesod subsite.
|
||||
newtype WaiSubsite = WaiSubsite { runWaiSubsite :: W.Application }
|
||||
|
||||
data RunHandlerEnv sub master = RunHandlerEnv
|
||||
{ rheRender :: !(Route master -> [(Text, Text)] -> Text)
|
||||
, rheRoute :: !(Maybe (Route sub))
|
||||
, rheToMaster :: !(Route sub -> Route master)
|
||||
, rheMaster :: !master
|
||||
, rheSub :: !sub
|
||||
data RunHandlerEnv site = RunHandlerEnv
|
||||
{ rheRender :: !(Route site -> [(Text, Text)] -> Text)
|
||||
, rheRoute :: !(Maybe (Route site))
|
||||
, rheSite :: !site
|
||||
, rheUpload :: !(RequestBodyLength -> FileUpload)
|
||||
, rheLog :: !(Loc -> LogSource -> LogLevel -> LogStr -> IO ())
|
||||
, rheOnError :: !(ErrorResponse -> YesodApp)
|
||||
@ -180,28 +178,26 @@ data RunHandlerEnv sub master = RunHandlerEnv
|
||||
-- Since 1.2.0
|
||||
}
|
||||
|
||||
data HandlerData sub master = HandlerData
|
||||
data HandlerData site = HandlerData
|
||||
{ handlerRequest :: !YesodRequest
|
||||
, handlerEnv :: !(RunHandlerEnv sub master)
|
||||
, handlerEnv :: !(RunHandlerEnv site)
|
||||
, handlerState :: !(IORef GHState)
|
||||
}
|
||||
|
||||
data YesodRunnerEnv sub master = YesodRunnerEnv
|
||||
data YesodRunnerEnv site = YesodRunnerEnv
|
||||
{ yreLogger :: !Logger
|
||||
, yreMaster :: !master
|
||||
, yreSub :: !sub
|
||||
, yreToMaster :: !(Route sub -> Route master)
|
||||
, yreSite :: !site
|
||||
, yreSessionBackend :: !(Maybe SessionBackend)
|
||||
}
|
||||
|
||||
-- | A generic handler monad, which can have a different subsite and master
|
||||
-- site. We define a newtype for better error message.
|
||||
newtype GHandler sub master a = GHandler
|
||||
{ unGHandler :: HandlerData sub master -> ResourceT IO a
|
||||
newtype GHandler site a = GHandler
|
||||
{ unGHandler :: HandlerData site -> ResourceT IO a
|
||||
}
|
||||
|
||||
newtype HandlerT sub m a = HandlerT
|
||||
{ unHandlerT :: HandlerData sub sub -> m a
|
||||
newtype HandlerT site m a = HandlerT
|
||||
{ unHandlerT :: HandlerData site -> m a
|
||||
}
|
||||
|
||||
instance Monad m => Monad (HandlerT sub m) where
|
||||
@ -229,11 +225,11 @@ type YesodApp = YesodRequest -> ResourceT IO YesodResponse
|
||||
-- | A generic widget, allowing specification of both the subsite and master
|
||||
-- site datatypes. While this is simply a @WriterT@, we define a newtype for
|
||||
-- better error messages.
|
||||
newtype GWidget sub master a = GWidget
|
||||
{ unGWidget :: GHandler sub master (a, GWData (Route master))
|
||||
newtype GWidget site a = GWidget -- FIXME change to WidgetT?
|
||||
{ unGWidget :: GHandler site (a, GWData (Route site))
|
||||
}
|
||||
|
||||
instance (a ~ ()) => Monoid (GWidget sub master a) where
|
||||
instance (a ~ ()) => Monoid (GWidget site a) where
|
||||
mempty = return ()
|
||||
mappend x y = x >> y
|
||||
|
||||
@ -349,60 +345,60 @@ instance Show HandlerContents where
|
||||
instance Exception HandlerContents
|
||||
|
||||
-- Instances for GWidget
|
||||
instance Functor (GWidget sub master) where
|
||||
instance Functor (GWidget site) where
|
||||
fmap f (GWidget x) = GWidget (fmap (first f) x)
|
||||
instance Applicative (GWidget sub master) where
|
||||
instance Applicative (GWidget site) where
|
||||
pure a = GWidget $ pure (a, mempty)
|
||||
GWidget f <*> GWidget v =
|
||||
GWidget $ k <$> f <*> v
|
||||
where
|
||||
k (a, wa) (b, wb) = (a b, wa `mappend` wb)
|
||||
instance Monad (GWidget sub master) where
|
||||
instance Monad (GWidget site) where
|
||||
return = pure
|
||||
GWidget x >>= f = GWidget $ do
|
||||
(a, wa) <- x
|
||||
(b, wb) <- unGWidget (f a)
|
||||
return (b, wa `mappend` wb)
|
||||
instance MonadIO (GWidget sub master) where
|
||||
instance MonadIO (GWidget site) where
|
||||
liftIO = GWidget . fmap (\a -> (a, mempty)) . liftIO
|
||||
instance MonadBase IO (GWidget sub master) where
|
||||
instance MonadBase IO (GWidget site) where
|
||||
liftBase = GWidget . fmap (\a -> (a, mempty)) . liftBase
|
||||
instance MonadBaseControl IO (GWidget sub master) where
|
||||
data StM (GWidget sub master) a =
|
||||
StW (StM (GHandler sub master) (a, GWData (Route master)))
|
||||
instance MonadBaseControl IO (GWidget site) where
|
||||
data StM (GWidget site) a =
|
||||
StW (StM (GHandler site) (a, GWData (Route site)))
|
||||
liftBaseWith f = GWidget $ liftBaseWith $ \runInBase ->
|
||||
liftM (\x -> (x, mempty))
|
||||
(f $ liftM StW . runInBase . unGWidget)
|
||||
restoreM (StW base) = GWidget $ restoreM base
|
||||
|
||||
instance MonadUnsafeIO (GWidget sub master) where
|
||||
instance MonadUnsafeIO (GWidget site) where
|
||||
unsafeLiftIO = liftIO
|
||||
instance MonadThrow (GWidget sub master) where
|
||||
instance MonadThrow (GWidget site) where
|
||||
monadThrow = liftIO . throwIO
|
||||
instance MonadResource (GWidget sub master) where
|
||||
instance MonadResource (GWidget site) where
|
||||
liftResourceT = lift . liftResourceT
|
||||
|
||||
instance MonadLogger (GWidget sub master) where
|
||||
instance MonadLogger (GWidget site) where
|
||||
monadLoggerLog a b c = lift . monadLoggerLog a b c
|
||||
|
||||
instance MonadLift (GHandler sub master) (GWidget sub master) where
|
||||
instance MonadLift (GHandler site) (GWidget site) where
|
||||
lift = GWidget . fmap (\x -> (x, mempty))
|
||||
|
||||
instance MonadLift (ResourceT IO) (GHandler sub master) where
|
||||
instance MonadLift (ResourceT IO) (GHandler site) where
|
||||
lift = GHandler . const
|
||||
|
||||
-- Instances for GHandler
|
||||
instance Functor (GHandler sub master) where
|
||||
instance Functor (GHandler site) where
|
||||
fmap f (GHandler x) = GHandler $ \r -> fmap f (x r)
|
||||
instance Applicative (GHandler sub master) where
|
||||
instance Applicative (GHandler site) where
|
||||
pure = GHandler . const . pure
|
||||
GHandler f <*> GHandler x = GHandler $ \r -> f r <*> x r
|
||||
instance Monad (GHandler sub master) where
|
||||
instance Monad (GHandler site) where
|
||||
return = pure
|
||||
GHandler x >>= f = GHandler $ \r -> x r >>= \x' -> unGHandler (f x') r
|
||||
instance MonadIO (GHandler sub master) where
|
||||
instance MonadIO (GHandler site) where
|
||||
liftIO = GHandler . const . lift
|
||||
instance MonadBase IO (GHandler sub master) where
|
||||
instance MonadBase IO (GHandler site) where
|
||||
liftBase = GHandler . const . lift
|
||||
-- | Note: although we provide a @MonadBaseControl@ instance, @lifted-base@'s
|
||||
-- @fork@ function is incompatible with the underlying @ResourceT@ system.
|
||||
@ -412,25 +408,25 @@ instance MonadBase IO (GHandler sub master) where
|
||||
-- Using fork usually leads to an exception that says
|
||||
-- \"Control.Monad.Trans.Resource.register\': The mutable state is being accessed
|
||||
-- after cleanup. Please contact the maintainers.\"
|
||||
instance MonadBaseControl IO (GHandler sub master) where
|
||||
data StM (GHandler sub master) a = StH (StM (ResourceT IO) a)
|
||||
instance MonadBaseControl IO (GHandler site) where
|
||||
data StM (GHandler site) a = StH (StM (ResourceT IO) a)
|
||||
liftBaseWith f = GHandler $ \reader ->
|
||||
liftBaseWith $ \runInBase ->
|
||||
f $ liftM StH . runInBase . (\(GHandler r) -> r reader)
|
||||
restoreM (StH base) = GHandler $ const $ restoreM base
|
||||
|
||||
instance MonadUnsafeIO (GHandler sub master) where
|
||||
instance MonadUnsafeIO (GHandler site) where
|
||||
unsafeLiftIO = liftIO
|
||||
instance MonadThrow (GHandler sub master) where
|
||||
instance MonadThrow (GHandler site) where
|
||||
monadThrow = liftIO . throwIO
|
||||
instance MonadResource (GHandler sub master) where
|
||||
instance MonadResource (GHandler site) where
|
||||
liftResourceT = lift . liftResourceT
|
||||
|
||||
instance MonadLogger (GHandler sub master) where
|
||||
instance MonadLogger (GHandler site) where
|
||||
monadLoggerLog a b c d = GHandler $ \hd ->
|
||||
liftIO $ rheLog (handlerEnv hd) a b c (toLogStr d)
|
||||
|
||||
instance Exception e => Failure e (GHandler sub master) where
|
||||
instance Exception e => Failure e (GHandler site) where
|
||||
failure = liftIO . throwIO
|
||||
|
||||
instance Monoid (UniqueList x) where
|
||||
|
||||
@ -25,8 +25,6 @@ module Yesod.Core.Widget
|
||||
-- ** Head of page
|
||||
, setTitle
|
||||
, setTitleI
|
||||
-- ** Body
|
||||
, addSubWidget
|
||||
-- ** CSS
|
||||
, addStylesheet
|
||||
, addStylesheetAttrs
|
||||
@ -70,121 +68,109 @@ import Yesod.Core.Types
|
||||
preEscapedLazyText :: TL.Text -> Html
|
||||
preEscapedLazyText = preEscapedToMarkup
|
||||
|
||||
addSubWidget :: (Route sub -> Route master) -> sub -> GWidget sub master a -> GWidget sub' master a
|
||||
addSubWidget toMaster sub (GWidget (GHandler f)) =
|
||||
GWidget $ GHandler $ f . modHD
|
||||
where
|
||||
modHD hd = hd
|
||||
{ handlerEnv = (handlerEnv hd)
|
||||
{ rheRoute = Nothing
|
||||
, rheSub = sub
|
||||
, rheToMaster = toMaster
|
||||
}
|
||||
}
|
||||
class ToWidget site a where
|
||||
toWidget :: a -> GWidget site ()
|
||||
|
||||
class ToWidget sub master a where
|
||||
toWidget :: a -> GWidget sub master ()
|
||||
|
||||
instance render ~ RY master => ToWidget sub master (render -> Html) where
|
||||
instance render ~ RY site => ToWidget site (render -> Html) where
|
||||
toWidget x = tell $ GWData (Body x) mempty mempty mempty mempty mempty mempty
|
||||
instance render ~ RY master => ToWidget sub master (render -> Css) where
|
||||
instance render ~ RY site => ToWidget site (render -> Css) where
|
||||
toWidget x = toWidget $ CssBuilder . fromLazyText . renderCss . x
|
||||
instance render ~ RY master => ToWidget sub master (render -> CssBuilder) where
|
||||
instance render ~ RY site => ToWidget site (render -> CssBuilder) where
|
||||
toWidget x = tell $ GWData mempty mempty mempty mempty (Map.singleton Nothing $ unCssBuilder . x) mempty mempty
|
||||
instance render ~ RY master => ToWidget sub master (render -> Javascript) where
|
||||
instance render ~ RY site => ToWidget site (render -> Javascript) where
|
||||
toWidget x = tell $ GWData mempty mempty mempty mempty mempty (Just x) mempty
|
||||
instance (sub' ~ sub, master' ~ master) => ToWidget sub' master' (GWidget sub master ()) where
|
||||
instance (site' ~ site) => ToWidget site' (GWidget site ()) where
|
||||
toWidget = id
|
||||
instance ToWidget sub master Html where
|
||||
instance ToWidget site Html where
|
||||
toWidget = toWidget . const
|
||||
|
||||
-- | Allows adding some CSS to the page with a specific media type.
|
||||
--
|
||||
-- Since 1.2
|
||||
class ToWidgetMedia sub master a where
|
||||
class ToWidgetMedia site a where
|
||||
-- | Add the given content to the page, but only for the given media type.
|
||||
--
|
||||
-- Since 1.2
|
||||
toWidgetMedia :: Text -- ^ media value
|
||||
-> a
|
||||
-> GWidget sub master ()
|
||||
instance render ~ RY master => ToWidgetMedia sub master (render -> Css) where
|
||||
-> GWidget site ()
|
||||
instance render ~ RY site => ToWidgetMedia site (render -> Css) where
|
||||
toWidgetMedia media x = toWidgetMedia media $ CssBuilder . fromLazyText . renderCss . x
|
||||
instance render ~ RY master => ToWidgetMedia sub master (render -> CssBuilder) where
|
||||
instance render ~ RY site => ToWidgetMedia site (render -> CssBuilder) where
|
||||
toWidgetMedia media x = tell $ GWData mempty mempty mempty mempty (Map.singleton (Just media) $ unCssBuilder . x) mempty mempty
|
||||
|
||||
class ToWidgetBody sub master a where
|
||||
toWidgetBody :: a -> GWidget sub master ()
|
||||
class ToWidgetBody site a where
|
||||
toWidgetBody :: a -> GWidget site ()
|
||||
|
||||
instance render ~ RY master => ToWidgetBody sub master (render -> Html) where
|
||||
instance render ~ RY site => ToWidgetBody site (render -> Html) where
|
||||
toWidgetBody = toWidget
|
||||
instance render ~ RY master => ToWidgetBody sub master (render -> Javascript) where
|
||||
instance render ~ RY site => ToWidgetBody site (render -> Javascript) where
|
||||
toWidgetBody j = toWidget $ \r -> H.script $ preEscapedLazyText $ renderJavascriptUrl r j
|
||||
instance ToWidgetBody sub master Html where
|
||||
instance ToWidgetBody site Html where
|
||||
toWidgetBody = toWidget
|
||||
|
||||
class ToWidgetHead sub master a where
|
||||
toWidgetHead :: a -> GWidget sub master ()
|
||||
class ToWidgetHead site a where
|
||||
toWidgetHead :: a -> GWidget site ()
|
||||
|
||||
instance render ~ RY master => ToWidgetHead sub master (render -> Html) where
|
||||
instance render ~ RY site => ToWidgetHead site (render -> Html) where
|
||||
toWidgetHead = tell . GWData mempty mempty mempty mempty mempty mempty . Head
|
||||
instance render ~ RY master => ToWidgetHead sub master (render -> Css) where
|
||||
instance render ~ RY site => ToWidgetHead site (render -> Css) where
|
||||
toWidgetHead = toWidget
|
||||
instance render ~ RY master => ToWidgetHead sub master (render -> CssBuilder) where
|
||||
instance render ~ RY site => ToWidgetHead site (render -> CssBuilder) where
|
||||
toWidgetHead = toWidget
|
||||
instance render ~ RY master => ToWidgetHead sub master (render -> Javascript) where
|
||||
instance render ~ RY site => ToWidgetHead site (render -> Javascript) where
|
||||
toWidgetHead j = toWidgetHead $ \r -> H.script $ preEscapedLazyText $ renderJavascriptUrl r j
|
||||
instance ToWidgetHead sub master Html where
|
||||
instance ToWidgetHead site Html where
|
||||
toWidgetHead = toWidgetHead . const
|
||||
|
||||
-- | Set the page title. Calling 'setTitle' multiple times overrides previously
|
||||
-- set values.
|
||||
setTitle :: Html -> GWidget sub master ()
|
||||
setTitle :: Html -> GWidget site ()
|
||||
setTitle x = tell $ GWData mempty (Last $ Just $ Title x) mempty mempty mempty mempty mempty
|
||||
|
||||
-- | Set the page title. Calling 'setTitle' multiple times overrides previously
|
||||
-- set values.
|
||||
setTitleI :: RenderMessage master msg => msg -> GWidget sub master ()
|
||||
setTitleI :: RenderMessage site msg => msg -> GWidget site ()
|
||||
setTitleI msg = do
|
||||
mr <- lift getMessageRender
|
||||
setTitle $ toHtml $ mr msg
|
||||
|
||||
-- | Link to the specified local stylesheet.
|
||||
addStylesheet :: Route master -> GWidget sub master ()
|
||||
addStylesheet :: Route site -> GWidget site ()
|
||||
addStylesheet = flip addStylesheetAttrs []
|
||||
|
||||
-- | Link to the specified local stylesheet.
|
||||
addStylesheetAttrs :: Route master -> [(Text, Text)] -> GWidget sub master ()
|
||||
addStylesheetAttrs :: Route site -> [(Text, Text)] -> GWidget site ()
|
||||
addStylesheetAttrs x y = tell $ GWData mempty mempty mempty (toUnique $ Stylesheet (Local x) y) mempty mempty mempty
|
||||
|
||||
-- | Link to the specified remote stylesheet.
|
||||
addStylesheetRemote :: Text -> GWidget sub master ()
|
||||
addStylesheetRemote :: Text -> GWidget site ()
|
||||
addStylesheetRemote = flip addStylesheetRemoteAttrs []
|
||||
|
||||
-- | Link to the specified remote stylesheet.
|
||||
addStylesheetRemoteAttrs :: Text -> [(Text, Text)] -> GWidget sub master ()
|
||||
addStylesheetRemoteAttrs :: Text -> [(Text, Text)] -> GWidget site ()
|
||||
addStylesheetRemoteAttrs x y = tell $ GWData mempty mempty mempty (toUnique $ Stylesheet (Remote x) y) mempty mempty mempty
|
||||
|
||||
addStylesheetEither :: Either (Route master) Text -> GWidget sub master ()
|
||||
addStylesheetEither :: Either (Route site) Text -> GWidget site ()
|
||||
addStylesheetEither = either addStylesheet addStylesheetRemote
|
||||
|
||||
addScriptEither :: Either (Route master) Text -> GWidget sub master ()
|
||||
addScriptEither :: Either (Route site) Text -> GWidget site ()
|
||||
addScriptEither = either addScript addScriptRemote
|
||||
|
||||
-- | Link to the specified local script.
|
||||
addScript :: Route master -> GWidget sub master ()
|
||||
addScript :: Route site -> GWidget site ()
|
||||
addScript = flip addScriptAttrs []
|
||||
|
||||
-- | Link to the specified local script.
|
||||
addScriptAttrs :: Route master -> [(Text, Text)] -> GWidget sub master ()
|
||||
addScriptAttrs :: Route site -> [(Text, Text)] -> GWidget site ()
|
||||
addScriptAttrs x y = tell $ GWData mempty mempty (toUnique $ Script (Local x) y) mempty mempty mempty mempty
|
||||
|
||||
-- | Link to the specified remote script.
|
||||
addScriptRemote :: Text -> GWidget sub master ()
|
||||
addScriptRemote :: Text -> GWidget site ()
|
||||
addScriptRemote = flip addScriptRemoteAttrs []
|
||||
|
||||
-- | Link to the specified remote script.
|
||||
addScriptRemoteAttrs :: Text -> [(Text, Text)] -> GWidget sub master ()
|
||||
addScriptRemoteAttrs :: Text -> [(Text, Text)] -> GWidget site ()
|
||||
addScriptRemoteAttrs x y = tell $ GWData mempty mempty (toUnique $ Script (Remote x) y) mempty mempty mempty mempty
|
||||
|
||||
whamlet :: QuasiQuoter
|
||||
@ -214,20 +200,20 @@ rules = do
|
||||
return $ NP.HamletRules ah ur $ \_ b -> return $ ah `AppE` b
|
||||
|
||||
-- | Wraps the 'Content' generated by 'hamletToContent' in a 'RepHtml'.
|
||||
ihamletToRepHtml :: RenderMessage master message
|
||||
=> HtmlUrlI18n message (Route master)
|
||||
-> GHandler sub master Html
|
||||
ihamletToRepHtml :: RenderMessage site message
|
||||
=> HtmlUrlI18n message (Route site)
|
||||
-> GHandler site Html
|
||||
ihamletToRepHtml ih = do
|
||||
urender <- getUrlRenderParams
|
||||
mrender <- getMessageRender
|
||||
return $ ih (toHtml . mrender) urender
|
||||
|
||||
tell :: GWData (Route master) -> GWidget sub master ()
|
||||
tell :: GWData (Route site) -> GWidget site ()
|
||||
tell w = GWidget $ return ((), w)
|
||||
|
||||
-- | Type-restricted version of @lift@. Used internally to create better error
|
||||
-- messages.
|
||||
liftW :: GHandler sub master a -> GWidget sub master a
|
||||
liftW :: GHandler site a -> GWidget site a
|
||||
liftW = lift
|
||||
|
||||
toUnique :: x -> UniqueList x
|
||||
|
||||
@ -30,5 +30,5 @@ specs = describe "Test.JsLoader" $ do
|
||||
res <- request defaultRequest
|
||||
assertBody "<!DOCTYPE html>\n<html><head><title></title></head><body><script src=\"load.js\"></script></body></html>" res
|
||||
|
||||
runner :: (YesodDispatch master master, Yesod master) => master -> Session () -> IO ()
|
||||
runner :: YesodDispatch master => master -> Session () -> IO ()
|
||||
runner app f = toWaiApp app >>= runSession f
|
||||
|
||||
@ -15,16 +15,16 @@ import qualified Data.ByteString.Lazy.Char8 as L8
|
||||
getSubsite :: a -> Subsite
|
||||
getSubsite = const Subsite
|
||||
|
||||
instance YesodSubDispatch Subsite (GHandler master master) where
|
||||
instance YesodSubDispatch Subsite (GHandler master) where
|
||||
yesodSubDispatch = $(mkYesodSubDispatch resourcesSubsite)
|
||||
|
||||
getBarR :: Monad m => m T.Text
|
||||
getBarR = return $ T.pack "BarR"
|
||||
|
||||
getBazR :: Yesod master => HandlerT Subsite (GHandler master master) RepHtml
|
||||
getBazR :: Yesod master => HandlerT Subsite (GHandler master) RepHtml
|
||||
getBazR = lift $ defaultLayout [whamlet|Used Default Layout|]
|
||||
|
||||
getBinR :: MonadHandlerBase m => HandlerT Subsite m RepHtml
|
||||
getBinR :: MonadHandler m => HandlerT Subsite m RepHtml
|
||||
getBinR = defaultLayoutT
|
||||
[whamlet|
|
||||
<p>Used defaultLayoutT
|
||||
|
||||
@ -14,5 +14,5 @@ import Network.Wai.Test
|
||||
import Network.Wai
|
||||
import Test.Hspec
|
||||
|
||||
yesod :: (YesodDispatch y y, Yesod y) => y -> Session a -> IO a
|
||||
yesod :: YesodDispatch y => y -> Session a -> IO a
|
||||
yesod app f = toWaiApp app >>= runSession f
|
||||
|
||||
Loading…
Reference in New Issue
Block a user