State for session
This commit is contained in:
parent
05b4d3e9ce
commit
1069df2665
@ -71,6 +71,8 @@ import Web.Routes
|
|||||||
import Control.Arrow (first)
|
import Control.Arrow (first)
|
||||||
import System.Random (randomR, newStdGen)
|
import System.Random (randomR, newStdGen)
|
||||||
|
|
||||||
|
import qualified Data.Map as Map
|
||||||
|
|
||||||
#if TEST
|
#if TEST
|
||||||
import Test.Framework (testGroup, Test)
|
import Test.Framework (testGroup, Test)
|
||||||
import Test.Framework.Providers.QuickCheck2 (testProperty)
|
import Test.Framework.Providers.QuickCheck2 (testProperty)
|
||||||
@ -265,10 +267,12 @@ toWaiApp' y segments env = do
|
|||||||
let eurl' = either (const Nothing) Just eurl
|
let eurl' = either (const Nothing) Just eurl
|
||||||
let eh er = runHandler (errorHandler' er) render eurl' id y id
|
let eh er = runHandler (errorHandler' er) render eurl' id y id
|
||||||
let ya = runHandler h render eurl' id y id
|
let ya = runHandler h render eurl' id y id
|
||||||
(s, hs, ct, c, sessionFinal) <- unYesodApp ya eh rr types
|
let sessionMap = Map.fromList
|
||||||
|
$ filter (\(x, _) -> x /= nonceKey) session'
|
||||||
|
(s, hs, ct, c, sessionFinal) <- unYesodApp ya eh rr types sessionMap
|
||||||
let sessionVal = encodeSession key' exp' host
|
let sessionVal = encodeSession key' exp' host
|
||||||
$ (nonceKey, reqNonce rr)
|
$ Map.toList
|
||||||
: sessionFinal
|
$ Map.insert nonceKey (reqNonce rr) sessionFinal
|
||||||
let hs' = AddCookie (clientSessionDuration y) sessionName
|
let hs' = AddCookie (clientSessionDuration y) sessionName
|
||||||
(bsToChars sessionVal)
|
(bsToChars sessionVal)
|
||||||
: hs
|
: hs
|
||||||
@ -337,7 +341,7 @@ parseWaiRequest env session' = do
|
|||||||
Nothing -> do
|
Nothing -> do
|
||||||
g <- newStdGen
|
g <- newStdGen
|
||||||
return $ fst $ randomString 10 g
|
return $ fst $ randomString 10 g
|
||||||
return $ Request gets' cookies' session' rbthunk env langs''' nonce
|
return $ Request gets' cookies' rbthunk env langs''' nonce
|
||||||
where
|
where
|
||||||
randomString len =
|
randomString len =
|
||||||
first (map toChar) . sequence' (replicate len (randomR (0, 61)))
|
first (map toChar) . sequence' (replicate len (randomR (0, 61)))
|
||||||
|
|||||||
@ -58,6 +58,7 @@ module Yesod.Handler
|
|||||||
, alreadyExpired
|
, alreadyExpired
|
||||||
, expiresAt
|
, expiresAt
|
||||||
-- * Session
|
-- * Session
|
||||||
|
, lookupSession
|
||||||
, setSession
|
, setSession
|
||||||
, deleteSession
|
, deleteSession
|
||||||
-- ** Ultimate destination
|
-- ** Ultimate destination
|
||||||
@ -82,7 +83,6 @@ module Yesod.Handler
|
|||||||
import Prelude hiding (catch)
|
import Prelude hiding (catch)
|
||||||
import Yesod.Request
|
import Yesod.Request
|
||||||
import Yesod.Internal
|
import Yesod.Internal
|
||||||
import Data.List (foldl')
|
|
||||||
import Data.Neither
|
import Data.Neither
|
||||||
import Data.Time (UTCTime)
|
import Data.Time (UTCTime)
|
||||||
|
|
||||||
@ -94,6 +94,7 @@ import Control.Monad.IO.Class
|
|||||||
import Control.Monad.Trans.Class
|
import Control.Monad.Trans.Class
|
||||||
import Control.Monad.Trans.Writer
|
import Control.Monad.Trans.Writer
|
||||||
import Control.Monad.Trans.Reader
|
import Control.Monad.Trans.Reader
|
||||||
|
import Control.Monad.Trans.State
|
||||||
|
|
||||||
import System.IO
|
import System.IO
|
||||||
import qualified Network.Wai as W
|
import qualified Network.Wai as W
|
||||||
@ -103,6 +104,7 @@ import Text.Hamlet
|
|||||||
|
|
||||||
import Control.Monad.Invert (MonadInvertIO (..))
|
import Control.Monad.Invert (MonadInvertIO (..))
|
||||||
import Control.Monad (liftM)
|
import Control.Monad (liftM)
|
||||||
|
import qualified Data.Map as Map
|
||||||
|
|
||||||
#if TEST
|
#if TEST
|
||||||
import Test.Framework (testGroup, Test)
|
import Test.Framework (testGroup, Test)
|
||||||
@ -162,16 +164,18 @@ type GHInner s m =
|
|||||||
ReaderT (HandlerData s m) (
|
ReaderT (HandlerData s m) (
|
||||||
MEitherT HandlerContents (
|
MEitherT HandlerContents (
|
||||||
WriterT (Endo [Header]) (
|
WriterT (Endo [Header]) (
|
||||||
WriterT (Endo [(String, Maybe String)]) (
|
StateT SessionMap ( -- session
|
||||||
IO
|
IO
|
||||||
))))
|
))))
|
||||||
|
|
||||||
|
type SessionMap = Map.Map String String
|
||||||
|
|
||||||
instance MonadInvertIO (GHandler s m) where
|
instance MonadInvertIO (GHandler s m) where
|
||||||
newtype InvertedIO (GHandler s m) a =
|
newtype InvertedIO (GHandler s m) a =
|
||||||
InvGHandlerIO
|
InvGHandlerIO
|
||||||
{ runInvGHandlerIO :: InvertedIO (GHInner s m) a
|
{ runInvGHandlerIO :: InvertedIO (GHInner s m) a
|
||||||
}
|
}
|
||||||
type InvertedArg (GHandler s m) = (HandlerData s m, ())
|
type InvertedArg (GHandler s m) = (HandlerData s m, (SessionMap, ()))
|
||||||
invertIO = liftM (fmap InvGHandlerIO) . invertIO . unGHandler
|
invertIO = liftM (fmap InvGHandlerIO) . invertIO . unGHandler
|
||||||
revertIO f = GHandler $ revertIO $ liftM runInvGHandlerIO . f
|
revertIO f = GHandler $ revertIO $ liftM runInvGHandlerIO . f
|
||||||
|
|
||||||
@ -185,7 +189,8 @@ newtype YesodApp = YesodApp
|
|||||||
:: (ErrorResponse -> YesodApp)
|
:: (ErrorResponse -> YesodApp)
|
||||||
-> Request
|
-> Request
|
||||||
-> [ContentType]
|
-> [ContentType]
|
||||||
-> IO (W.Status, [Header], ContentType, Content, [(String, String)])
|
-> SessionMap
|
||||||
|
-> IO (W.Status, [Header], ContentType, Content, SessionMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
data HandlerContents =
|
data HandlerContents =
|
||||||
@ -227,16 +232,6 @@ getCurrentRoute = handlerRoute <$> GHandler ask
|
|||||||
getRouteToMaster :: GHandler sub master (Route sub -> Route master)
|
getRouteToMaster :: GHandler sub master (Route sub -> Route master)
|
||||||
getRouteToMaster = handlerToMaster <$> GHandler ask
|
getRouteToMaster = handlerToMaster <$> GHandler ask
|
||||||
|
|
||||||
modifySession :: [(String, String)] -> (String, Maybe String)
|
|
||||||
-> [(String, String)]
|
|
||||||
modifySession orig (k, v) =
|
|
||||||
case v of
|
|
||||||
Nothing -> dropKeys k orig
|
|
||||||
Just v' -> (k, v') : dropKeys k orig
|
|
||||||
|
|
||||||
dropKeys :: String -> [(String, x)] -> [(String, x)]
|
|
||||||
dropKeys k = filter $ \(x, _) -> x /= k
|
|
||||||
|
|
||||||
-- | Function used internally by Yesod in the process of converting a
|
-- | Function used internally by Yesod in the process of converting a
|
||||||
-- 'GHandler' into an 'W.Application'. Should not be needed by users.
|
-- 'GHandler' into an 'W.Application'. Should not be needed by users.
|
||||||
runHandler :: HasReps c
|
runHandler :: HasReps c
|
||||||
@ -247,7 +242,8 @@ runHandler :: HasReps c
|
|||||||
-> master
|
-> master
|
||||||
-> (master -> sub)
|
-> (master -> sub)
|
||||||
-> YesodApp
|
-> YesodApp
|
||||||
runHandler handler mrender sroute tomr ma tosa = YesodApp $ \eh rr cts -> do
|
runHandler handler mrender sroute tomr ma tosa =
|
||||||
|
YesodApp $ \eh rr cts initSession -> do
|
||||||
let toErrorHandler =
|
let toErrorHandler =
|
||||||
InternalError
|
InternalError
|
||||||
. (show :: Control.Exception.SomeException -> String)
|
. (show :: Control.Exception.SomeException -> String)
|
||||||
@ -259,17 +255,16 @@ runHandler handler mrender sroute tomr ma tosa = YesodApp $ \eh rr cts -> do
|
|||||||
, handlerRender = mrender
|
, handlerRender = mrender
|
||||||
, handlerToMaster = tomr
|
, handlerToMaster = tomr
|
||||||
}
|
}
|
||||||
((contents', headers), session') <- E.catch (
|
((contents', headers), finalSession) <- E.catch (
|
||||||
runWriterT
|
flip runStateT initSession
|
||||||
$ runWriterT
|
$ runWriterT
|
||||||
$ runMEitherT
|
$ runMEitherT
|
||||||
$ flip runReaderT hd
|
$ flip runReaderT hd
|
||||||
$ unGHandler handler
|
$ unGHandler handler
|
||||||
) (\e -> return ((MLeft $ HCError $ toErrorHandler e, id), id))
|
) (\e -> return ((MLeft $ HCError $ toErrorHandler e, id), initSession))
|
||||||
let contents = meither id (HCContent . chooseRep) contents'
|
let contents = meither id (HCContent . chooseRep) contents'
|
||||||
let finalSession = foldl' modifySession (reqSession rr) $ session' []
|
|
||||||
let handleError e = do
|
let handleError e = do
|
||||||
(_, hs, ct, c, sess) <- unYesodApp (eh e) safeEh rr cts
|
(_, hs, ct, c, sess) <- unYesodApp (eh e) safeEh rr cts finalSession
|
||||||
let hs' = headers hs
|
let hs' = headers hs
|
||||||
return (getStatus e, hs', ct, c, sess)
|
return (getStatus e, hs', ct, c, sess)
|
||||||
let sendFile' ct fp =
|
let sendFile' ct fp =
|
||||||
@ -288,9 +283,10 @@ runHandler handler mrender sroute tomr ma tosa = YesodApp $ \eh rr cts -> do
|
|||||||
(handleError . toErrorHandler)
|
(handleError . toErrorHandler)
|
||||||
|
|
||||||
safeEh :: ErrorResponse -> YesodApp
|
safeEh :: ErrorResponse -> YesodApp
|
||||||
safeEh er = YesodApp $ \_ _ _ -> do
|
safeEh er = YesodApp $ \_ _ _ session -> do
|
||||||
liftIO $ hPutStrLn stderr $ "Error handler errored out: " ++ show er
|
liftIO $ hPutStrLn stderr $ "Error handler errored out: " ++ show er
|
||||||
return (W.status500, [], typePlain, toContent "Internal Server Error", [])
|
return (W.status500, [], typePlain, toContent "Internal Server Error",
|
||||||
|
session)
|
||||||
|
|
||||||
-- | Redirect to the given route.
|
-- | Redirect to the given route.
|
||||||
redirect :: RedirectType -> Route master -> GHandler sub master a
|
redirect :: RedirectType -> Route master -> GHandler sub master a
|
||||||
@ -334,9 +330,9 @@ setUltDest' = do
|
|||||||
Nothing -> return ()
|
Nothing -> return ()
|
||||||
Just r -> do
|
Just r -> do
|
||||||
tm <- getRouteToMaster
|
tm <- getRouteToMaster
|
||||||
gets <- reqGetParams <$> getRequest
|
gets' <- reqGetParams <$> getRequest
|
||||||
render <- getUrlRenderParams
|
render <- getUrlRenderParams
|
||||||
setUltDestString $ render (tm r) gets
|
setUltDestString $ render (tm r) gets'
|
||||||
|
|
||||||
-- | Redirect to the ultimate destination in the user's session. Clear the
|
-- | Redirect to the ultimate destination in the user's session. Clear the
|
||||||
-- value from the session.
|
-- value from the session.
|
||||||
@ -355,9 +351,6 @@ msgKey = "_MSG"
|
|||||||
|
|
||||||
-- | Sets a message in the user's session.
|
-- | Sets a message in the user's session.
|
||||||
--
|
--
|
||||||
-- The message set here will not be visible within the current request;
|
|
||||||
-- instead, it will only appear in the next request.
|
|
||||||
--
|
|
||||||
-- See 'getMessage'.
|
-- See 'getMessage'.
|
||||||
setMessage :: Html -> GHandler sub master ()
|
setMessage :: Html -> GHandler sub master ()
|
||||||
setMessage = setSession msgKey . lbsToChars . renderHtml
|
setMessage = setSession msgKey . lbsToChars . renderHtml
|
||||||
@ -412,7 +405,8 @@ setCookie a b = addHeader . AddCookie a b
|
|||||||
deleteCookie :: String -> GHandler sub master ()
|
deleteCookie :: String -> GHandler sub master ()
|
||||||
deleteCookie = addHeader . DeleteCookie
|
deleteCookie = addHeader . DeleteCookie
|
||||||
|
|
||||||
-- | Set the language in the user session. Will show up in 'languages'.
|
-- | Set the language in the user session. Will show up in 'languages' on the
|
||||||
|
-- next request.
|
||||||
setLanguage :: String -> GHandler sub master ()
|
setLanguage :: String -> GHandler sub master ()
|
||||||
setLanguage = setSession langKey
|
setLanguage = setSession langKey
|
||||||
|
|
||||||
@ -448,17 +442,14 @@ expiresAt = setHeader "Expires" . formatRFC1123
|
|||||||
-- The session is handled by the clientsession package: it sets an encrypted
|
-- The session is handled by the clientsession package: it sets an encrypted
|
||||||
-- and hashed cookie on the client. This ensures that all data is secure and
|
-- and hashed cookie on the client. This ensures that all data is secure and
|
||||||
-- not tampered with.
|
-- not tampered with.
|
||||||
--
|
|
||||||
-- Please note that the value you set here will not be available via
|
|
||||||
-- 'getSession' until the /next/ request.
|
|
||||||
setSession :: String -- ^ key
|
setSession :: String -- ^ key
|
||||||
-> String -- ^ value
|
-> String -- ^ value
|
||||||
-> GHandler sub master ()
|
-> GHandler sub master ()
|
||||||
setSession k v = GHandler . lift . lift . lift . tell $ (:) (k, Just v)
|
setSession k = GHandler . lift . lift . lift . modify . Map.insert k
|
||||||
|
|
||||||
-- | Unsets a session variable. See 'setSession'.
|
-- | Unsets a session variable. See 'setSession'.
|
||||||
deleteSession :: String -> GHandler sub master ()
|
deleteSession :: String -> GHandler sub master ()
|
||||||
deleteSession k = GHandler . lift . lift . lift . tell $ (:) (k, Nothing)
|
deleteSession = GHandler . lift . lift . lift . modify . Map.delete
|
||||||
|
|
||||||
-- | Internal use only, not to be confused with 'setHeader'.
|
-- | Internal use only, not to be confused with 'setHeader'.
|
||||||
addHeader :: Header -> GHandler sub master ()
|
addHeader :: Header -> GHandler sub master ()
|
||||||
@ -486,6 +477,12 @@ localNoCurrent :: GHandler s m a -> GHandler s m a
|
|||||||
localNoCurrent =
|
localNoCurrent =
|
||||||
GHandler . local (\hd -> hd { handlerRoute = Nothing }) . unGHandler
|
GHandler . local (\hd -> hd { handlerRoute = Nothing }) . unGHandler
|
||||||
|
|
||||||
|
-- | Lookup for session data.
|
||||||
|
lookupSession :: ParamName -> GHandler s m (Maybe ParamValue)
|
||||||
|
lookupSession n = GHandler $ do
|
||||||
|
m <- lift $ lift $ lift get
|
||||||
|
return $ Map.lookup n m
|
||||||
|
|
||||||
#if TEST
|
#if TEST
|
||||||
|
|
||||||
testSuite :: Test
|
testSuite :: Test
|
||||||
|
|||||||
@ -28,13 +28,11 @@ module Yesod.Request
|
|||||||
, lookupGetParam
|
, lookupGetParam
|
||||||
, lookupPostParam
|
, lookupPostParam
|
||||||
, lookupCookie
|
, lookupCookie
|
||||||
, lookupSession
|
|
||||||
, lookupFile
|
, lookupFile
|
||||||
-- ** Multi-lookup
|
-- ** Multi-lookup
|
||||||
, lookupGetParams
|
, lookupGetParams
|
||||||
, lookupPostParams
|
, lookupPostParams
|
||||||
, lookupCookies
|
, lookupCookies
|
||||||
, lookupSessions
|
|
||||||
, lookupFiles
|
, lookupFiles
|
||||||
-- * Parameter type synonyms
|
-- * Parameter type synonyms
|
||||||
, ParamName
|
, ParamName
|
||||||
@ -98,8 +96,6 @@ data FileInfo = FileInfo
|
|||||||
data Request = Request
|
data Request = Request
|
||||||
{ reqGetParams :: [(ParamName, ParamValue)]
|
{ reqGetParams :: [(ParamName, ParamValue)]
|
||||||
, reqCookies :: [(ParamName, ParamValue)]
|
, reqCookies :: [(ParamName, ParamValue)]
|
||||||
-- | Session data stored in a cookie via the clientsession package.
|
|
||||||
, reqSession :: [(ParamName, ParamValue)]
|
|
||||||
-- | The POST parameters and submitted files. This is stored in an IO
|
-- | The POST parameters and submitted files. This is stored in an IO
|
||||||
-- thunk, which essentially means it will be computed once at most, but
|
-- thunk, which essentially means it will be computed once at most, but
|
||||||
-- only if requested. This allows avoidance of the potentially costly
|
-- only if requested. This allows avoidance of the potentially costly
|
||||||
@ -163,13 +159,3 @@ lookupCookies :: RequestReader m => ParamName -> m [ParamValue]
|
|||||||
lookupCookies pn = do
|
lookupCookies pn = do
|
||||||
rr <- getRequest
|
rr <- getRequest
|
||||||
return $ lookup' pn $ reqCookies rr
|
return $ lookup' pn $ reqCookies rr
|
||||||
|
|
||||||
-- | Lookup for session data.
|
|
||||||
lookupSession :: RequestReader m => ParamName -> m (Maybe ParamValue)
|
|
||||||
lookupSession = liftM listToMaybe . lookupSessions
|
|
||||||
|
|
||||||
-- | Lookup for session data.
|
|
||||||
lookupSessions :: RequestReader m => ParamName -> m [ParamValue]
|
|
||||||
lookupSessions pn = do
|
|
||||||
rr <- getRequest
|
|
||||||
return $ lookup' pn $ reqSession rr
|
|
||||||
|
|||||||
@ -47,6 +47,7 @@ import Yesod.Internal
|
|||||||
|
|
||||||
import Control.Monad.Invert (MonadInvertIO (..))
|
import Control.Monad.Invert (MonadInvertIO (..))
|
||||||
import Control.Monad (liftM)
|
import Control.Monad (liftM)
|
||||||
|
import qualified Data.Map as Map
|
||||||
|
|
||||||
-- | A generic widget, allowing specification of both the subsite and master
|
-- | A generic widget, allowing specification of both the subsite and master
|
||||||
-- site datatypes. This is basically a large 'WriterT' stack keeping track of
|
-- site datatypes. This is basically a large 'WriterT' stack keeping track of
|
||||||
@ -73,7 +74,7 @@ instance MonadInvertIO (GWidget s m) where
|
|||||||
{ runInvGWidgetIO :: InvertedIO (GWInner s m) a
|
{ runInvGWidgetIO :: InvertedIO (GWInner s m) a
|
||||||
}
|
}
|
||||||
type InvertedArg (GWidget s m) =
|
type InvertedArg (GWidget s m) =
|
||||||
(Int, (HandlerData s m, ()))
|
(Int, (HandlerData s m, (Map.Map String String, ())))
|
||||||
invertIO = liftM (fmap InvGWidgetIO) . invertIO . unGWidget
|
invertIO = liftM (fmap InvGWidgetIO) . invertIO . unGWidget
|
||||||
revertIO f = GWidget $ revertIO $ liftM runInvGWidgetIO . f
|
revertIO f = GWidget $ revertIO $ liftM runInvGWidgetIO . f
|
||||||
|
|
||||||
|
|||||||
@ -37,10 +37,10 @@ wrapper h = [$hamlet|
|
|||||||
#wrapper ^h^
|
#wrapper ^h^
|
||||||
%footer Brought to you by Yesod Widgets™
|
%footer Brought to you by Yesod Widgets™
|
||||||
|]
|
|]
|
||||||
getRootR = defaultLayout $ flip wrapWidget wrapper $ do
|
getRootR = defaultLayout $ wrapper $ do
|
||||||
i <- newIdent
|
i <- newIdent
|
||||||
setTitle $ string "Hello Widgets"
|
setTitle $ string "Hello Widgets"
|
||||||
addStyle [$cassius|
|
addCassius [$cassius|
|
||||||
#$i$
|
#$i$
|
||||||
color: red
|
color: red
|
||||||
|]
|
|]
|
||||||
@ -48,7 +48,7 @@ getRootR = defaultLayout $ flip wrapWidget wrapper $ do
|
|||||||
addStylesheetRemote "http://localhost:3000/static/style2.css"
|
addStylesheetRemote "http://localhost:3000/static/style2.css"
|
||||||
addScriptRemote "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"
|
addScriptRemote "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"
|
||||||
addScript $ StaticR $ StaticRoute ["script.js"] []
|
addScript $ StaticR $ StaticRoute ["script.js"] []
|
||||||
addBody [$hamlet|
|
addHamlet [$hamlet|
|
||||||
%h1#$i$ Welcome to my first widget!!!
|
%h1#$i$ Welcome to my first widget!!!
|
||||||
%p
|
%p
|
||||||
%a!href=@RootR@ Recursive link.
|
%a!href=@RootR@ Recursive link.
|
||||||
@ -58,10 +58,10 @@ getRootR = defaultLayout $ flip wrapWidget wrapper $ do
|
|||||||
%a!href=@CustomFormR@ Custom form arrangement.
|
%a!href=@CustomFormR@ Custom form arrangement.
|
||||||
%p.noscript Your script did not load. :(
|
%p.noscript Your script did not load. :(
|
||||||
|]
|
|]
|
||||||
addHead [$hamlet|%meta!keywords=haskell|]
|
addHtmlHead [$hamlet|%meta!keywords=haskell|]
|
||||||
|
|
||||||
handleFormR = do
|
handleFormR = do
|
||||||
(res, form, enctype, hidden) <- runFormPost $ fieldsToTable $ (,,,,,,,,,,)
|
(res, form, enctype, hidden) <- runFormPost $ fieldsToTable $ (,,,,,,,,,)
|
||||||
<$> stringField (FormFieldSettings "My Field" "Some tooltip info" Nothing Nothing) Nothing
|
<$> stringField (FormFieldSettings "My Field" "Some tooltip info" Nothing Nothing) Nothing
|
||||||
<*> stringField ("Another field") (Just "some default text")
|
<*> stringField ("Another field") (Just "some default text")
|
||||||
<*> intField (FormFieldSettings "A number field" "some nums" Nothing Nothing) (Just 5)
|
<*> intField (FormFieldSettings "A number field" "some nums" Nothing Nothing) (Just 5)
|
||||||
@ -72,7 +72,6 @@ handleFormR = do
|
|||||||
, jdsNumberOfMonths = Right (2, 3)
|
, jdsNumberOfMonths = Right (2, 3)
|
||||||
} ("A day field") Nothing
|
} ("A day field") Nothing
|
||||||
<*> timeField ("A time field") Nothing
|
<*> timeField ("A time field") Nothing
|
||||||
<*> jqueryDayTimeField ("A day/time field") Nothing
|
|
||||||
<*> boolField FormFieldSettings
|
<*> boolField FormFieldSettings
|
||||||
{ ffsLabel = "A checkbox"
|
{ ffsLabel = "A checkbox"
|
||||||
, ffsTooltip = ""
|
, ffsTooltip = ""
|
||||||
@ -86,23 +85,23 @@ handleFormR = do
|
|||||||
<*> maybeEmailField ("An e-mail addres") Nothing
|
<*> maybeEmailField ("An e-mail addres") Nothing
|
||||||
<*> maybeTextareaField "A text area" Nothing
|
<*> maybeTextareaField "A text area" Nothing
|
||||||
let mhtml = case res of
|
let mhtml = case res of
|
||||||
FormSuccess (_, _, _, _, _, _, _, _, x, _, _) -> Just x
|
FormSuccess (_, _, _, _, _, _, _, x, _, _) -> Just x
|
||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
let txt = case res of
|
let txt = case res of
|
||||||
FormSuccess (_, _, _, _, _, _, _, _, _, _, Just x) -> Just x
|
FormSuccess (_, _, _, _, _, _, _, _, _, Just x) -> Just x
|
||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
addStyle [$cassius|
|
addCassius [$cassius|
|
||||||
.tooltip
|
.tooltip
|
||||||
color: #666
|
color: #666
|
||||||
font-style: italic
|
font-style: italic
|
||||||
|]
|
|]
|
||||||
addStyle [$cassius|
|
addCassius [$cassius|
|
||||||
textarea.html
|
textarea.html
|
||||||
width: 300px
|
width: 300px
|
||||||
height: 150px
|
height: 150px
|
||||||
|]
|
|]
|
||||||
wrapWidget form $ \h -> [$hamlet|
|
addWidget [$hamlet|
|
||||||
$maybe formFailures.res failures
|
$maybe formFailures.res failures
|
||||||
%ul.errors
|
%ul.errors
|
||||||
$forall failures f
|
$forall failures f
|
||||||
@ -110,7 +109,7 @@ $maybe formFailures.res failures
|
|||||||
%form!method=post!enctype=$enctype$
|
%form!method=post!enctype=$enctype$
|
||||||
$hidden$
|
$hidden$
|
||||||
%table
|
%table
|
||||||
^h^
|
^form^
|
||||||
%tr
|
%tr
|
||||||
%td!colspan=2
|
%td!colspan=2
|
||||||
%input!type=submit
|
%input!type=submit
|
||||||
@ -140,7 +139,7 @@ getCustomFormR = do
|
|||||||
let b = do
|
let b = do
|
||||||
b1' <- extractBody b1
|
b1' <- extractBody b1
|
||||||
b2' <- extractBody b2
|
b2' <- extractBody b2
|
||||||
addBody [$hamlet|
|
addHamlet [$hamlet|
|
||||||
%p This is a custom layout.
|
%p This is a custom layout.
|
||||||
%h1 Name Follows!
|
%h1 Name Follows!
|
||||||
%p ^b1'^
|
%p ^b1'^
|
||||||
@ -150,7 +149,7 @@ getCustomFormR = do
|
|||||||
(_, wform, enctype) <- runFormGet customForm
|
(_, wform, enctype) <- runFormGet customForm
|
||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
form <- extractBody wform
|
form <- extractBody wform
|
||||||
addBody [$hamlet|
|
addHamlet [$hamlet|
|
||||||
%form
|
%form
|
||||||
^form^
|
^form^
|
||||||
%div
|
%div
|
||||||
|
|||||||
@ -48,6 +48,7 @@ library
|
|||||||
, xss-sanitize >= 0.2 && < 0.3
|
, xss-sanitize >= 0.2 && < 0.3
|
||||||
, data-default >= 0.2 && < 0.3
|
, data-default >= 0.2 && < 0.3
|
||||||
, failure >= 0.1 && < 0.2
|
, failure >= 0.1 && < 0.2
|
||||||
|
, containers >= 0.2 && < 0.5
|
||||||
exposed-modules: Yesod
|
exposed-modules: Yesod
|
||||||
Yesod.Content
|
Yesod.Content
|
||||||
Yesod.Dispatch
|
Yesod.Dispatch
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user