Initial refactoring work: no polymorphic insanity
This commit is contained in:
parent
a3a5d03e2d
commit
713304e7ef
@ -16,33 +16,41 @@ module Yesod.Form
|
|||||||
, FieldInfo (..)
|
, FieldInfo (..)
|
||||||
-- ** Utilities
|
-- ** Utilities
|
||||||
, formFailures
|
, formFailures
|
||||||
|
{-
|
||||||
-- * Type synonyms
|
-- * Type synonyms
|
||||||
, Form
|
, Form
|
||||||
, Formlet
|
, Formlet
|
||||||
, FormField
|
, FormField
|
||||||
, FormletField
|
, FormletField
|
||||||
, FormInput
|
, FormInput
|
||||||
|
-}
|
||||||
-- * Unwrapping functions
|
-- * Unwrapping functions
|
||||||
, generateForm
|
, generateForm
|
||||||
, runFormGet
|
, runFormGet
|
||||||
, runFormMonadGet
|
--, runFormMonadGet
|
||||||
, runFormPost
|
, runFormPost
|
||||||
, runFormPostNoNonce
|
, runFormPostNoNonce
|
||||||
|
{-
|
||||||
, runFormMonadPost
|
, runFormMonadPost
|
||||||
, runFormGet'
|
, runFormGet'
|
||||||
, runFormPost'
|
, runFormPost'
|
||||||
|
-}
|
||||||
-- ** High-level form post unwrappers
|
-- ** High-level form post unwrappers
|
||||||
|
{-
|
||||||
, runFormTable
|
, runFormTable
|
||||||
, runFormDivs
|
, runFormDivs
|
||||||
|
-}
|
||||||
-- * Field/form helpers
|
-- * Field/form helpers
|
||||||
, fieldsToTable
|
, fieldsToTable
|
||||||
, fieldsToDivs
|
, fieldsToDivs
|
||||||
, fieldsToPlain
|
, fieldsToPlain
|
||||||
|
{-
|
||||||
, checkForm
|
, checkForm
|
||||||
|
-}
|
||||||
-- * Type classes
|
-- * Type classes
|
||||||
, module Yesod.Form.Class
|
, module Yesod.Form.Class
|
||||||
-- * Template Haskell
|
-- * Template Haskell
|
||||||
, mkToForm
|
--, mkToForm
|
||||||
, module Yesod.Form.Fields
|
, module Yesod.Form.Fields
|
||||||
) where
|
) where
|
||||||
|
|
||||||
@ -50,14 +58,14 @@ import Yesod.Form.Core
|
|||||||
import Yesod.Form.Fields
|
import Yesod.Form.Fields
|
||||||
import Yesod.Form.Class
|
import Yesod.Form.Class
|
||||||
import Yesod.Form.Profiles (Textarea (..))
|
import Yesod.Form.Profiles (Textarea (..))
|
||||||
import Yesod.Widget (GWidget)
|
import Yesod.Widget (GWidget, GGWidget)
|
||||||
|
|
||||||
import Text.Hamlet
|
import Text.Hamlet
|
||||||
import Yesod.Request
|
import Yesod.Request
|
||||||
import Yesod.Handler
|
import Yesod.Handler
|
||||||
import Control.Applicative hiding (optional)
|
import Control.Applicative hiding (optional)
|
||||||
import Data.Maybe (fromMaybe, mapMaybe)
|
import Data.Maybe (fromMaybe, mapMaybe)
|
||||||
import Control.Monad ((<=<))
|
import Control.Monad ((<=<), liftM)
|
||||||
import Language.Haskell.TH.Syntax hiding (lift)
|
import Language.Haskell.TH.Syntax hiding (lift)
|
||||||
import Database.Persist.Base (EntityDef (..), PersistEntity (entityDef))
|
import Database.Persist.Base (EntityDef (..), PersistEntity (entityDef))
|
||||||
import Data.Char (toUpper, isUpper)
|
import Data.Char (toUpper, isUpper)
|
||||||
@ -65,6 +73,7 @@ import Control.Arrow ((&&&))
|
|||||||
import Data.List (group, sort)
|
import Data.List (group, sort)
|
||||||
import Data.Monoid (mempty)
|
import Data.Monoid (mempty)
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
|
import Control.Monad.Trans.RWS (runRWST)
|
||||||
|
|
||||||
#if __GLASGOW_HASKELL__ >= 700
|
#if __GLASGOW_HASKELL__ >= 700
|
||||||
#define HAMLET hamlet
|
#define HAMLET hamlet
|
||||||
@ -72,12 +81,12 @@ import Data.Text (Text)
|
|||||||
#define HAMLET $hamlet
|
#define HAMLET $hamlet
|
||||||
#endif
|
#endif
|
||||||
-- | Display only the actual input widget code, without any decoration.
|
-- | Display only the actual input widget code, without any decoration.
|
||||||
fieldsToPlain :: FormField sub y a -> Form sub y a
|
fieldsToPlain :: (Monad mo, Monad mo') => GForm [FieldInfo (GGWidget master mo' ())] mo a -> GForm (GGWidget master mo' ()) mo a
|
||||||
fieldsToPlain = mapFormXml $ mapM_ fiInput
|
fieldsToPlain = mapFormXml $ mapM_ fiInput
|
||||||
|
|
||||||
-- | Display the label, tooltip, input code and errors in a single row of a
|
-- | Display the label, tooltip, input code and errors in a single row of a
|
||||||
-- table.
|
-- table.
|
||||||
fieldsToTable :: FormField sub y a -> Form sub y a
|
fieldsToTable :: (Monad mo, Monad mo') => GForm [FieldInfo (GGWidget master mo' ())] mo a -> GForm (GGWidget master mo' ()) mo a
|
||||||
fieldsToTable = mapFormXml $ mapM_ go
|
fieldsToTable = mapFormXml $ mapM_ go
|
||||||
where
|
where
|
||||||
go fi = [HAMLET|
|
go fi = [HAMLET|
|
||||||
@ -93,7 +102,7 @@ fieldsToTable = mapFormXml $ mapM_ go
|
|||||||
clazz fi = if fiRequired fi then "required" else "optional" :: Text
|
clazz fi = if fiRequired fi then "required" else "optional" :: Text
|
||||||
|
|
||||||
-- | Display the label, tooltip, input code and errors in a single div.
|
-- | Display the label, tooltip, input code and errors in a single div.
|
||||||
fieldsToDivs :: FormField sub y a -> Form sub y a
|
fieldsToDivs :: (Monad mo, Monad mo') => GForm [FieldInfo (GGWidget master mo' ())] mo a -> GForm (GGWidget master mo' ()) mo a
|
||||||
fieldsToDivs = mapFormXml $ mapM_ go
|
fieldsToDivs = mapFormXml $ mapM_ go
|
||||||
where
|
where
|
||||||
go fi = [HAMLET|
|
go fi = [HAMLET|
|
||||||
@ -107,7 +116,7 @@ fieldsToDivs = mapFormXml $ mapM_ go
|
|||||||
clazz fi = if fiRequired fi then "required" else "optional" :: Text
|
clazz fi = if fiRequired fi then "required" else "optional" :: Text
|
||||||
|
|
||||||
-- | Run a form against POST parameters, without CSRF protection.
|
-- | Run a form against POST parameters, without CSRF protection.
|
||||||
runFormPostNoNonce :: GForm s m xml a -> GHandler s m (FormResult a, xml, Enctype)
|
runFormPostNoNonce :: GForm xml (GHandler s m) a -> GHandler s m (a, xml, Enctype)
|
||||||
runFormPostNoNonce f = do
|
runFormPostNoNonce f = do
|
||||||
(pp, files) <- runRequestBody
|
(pp, files) <- runRequestBody
|
||||||
runFormGeneric pp files f
|
runFormGeneric pp files f
|
||||||
@ -117,17 +126,17 @@ runFormPostNoNonce f = do
|
|||||||
-- This function includes CSRF protection by checking a nonce value. You must
|
-- This function includes CSRF protection by checking a nonce value. You must
|
||||||
-- therefore embed this nonce in the form as a hidden field; that is the
|
-- therefore embed this nonce in the form as a hidden field; that is the
|
||||||
-- meaning of the fourth element in the tuple.
|
-- meaning of the fourth element in the tuple.
|
||||||
runFormPost :: GForm s m xml a -> GHandler s m (FormResult a, xml, Enctype, Html)
|
runFormPost :: GForm xml (GHandler s m) (FormResult a) -> GHandler s m (FormResult a, xml, Enctype, Html)
|
||||||
runFormPost f = do
|
runFormPost f = do
|
||||||
(pp, files) <- runRequestBody
|
(pp, files) <- runRequestBody
|
||||||
nonce <- fmap reqNonce getRequest
|
nonce <- liftM reqNonce getRequest
|
||||||
(res, xml, enctype) <- runFormGeneric pp files f
|
(res, xml, enctype) <- runFormGeneric pp files f
|
||||||
let res' =
|
let res' =
|
||||||
case res of
|
case res of
|
||||||
FormSuccess x ->
|
FormSuccess x ->
|
||||||
if lookup nonceName pp == nonce
|
if lookup nonceName pp == nonce
|
||||||
then FormSuccess x
|
then FormSuccess x
|
||||||
else FormFailure ["As a protection against cross-site request forgery attacks, please confirm your form submission."]
|
else FormFailure ["As a protection against cross-site request forgery attacks, please confirm your form submission."] -- TRANS
|
||||||
_ -> res
|
_ -> res
|
||||||
return (res', xml, enctype, maybe mempty hidden nonce)
|
return (res', xml, enctype, maybe mempty hidden nonce)
|
||||||
where
|
where
|
||||||
@ -138,13 +147,7 @@ runFormPost f = do
|
|||||||
nonceName :: Text
|
nonceName :: Text
|
||||||
nonceName = "_nonce"
|
nonceName = "_nonce"
|
||||||
|
|
||||||
-- | Run a form against POST parameters. Please note that this does not provide
|
{- FIXME
|
||||||
-- CSRF protection.
|
|
||||||
runFormMonadPost :: GFormMonad s m a -> GHandler s m (a, Enctype)
|
|
||||||
runFormMonadPost f = do
|
|
||||||
(pp, files) <- runRequestBody
|
|
||||||
runFormGeneric pp files f
|
|
||||||
|
|
||||||
-- | Run a form against POST parameters, disregarding the resulting HTML and
|
-- | Run a form against POST parameters, disregarding the resulting HTML and
|
||||||
-- returning an error response on invalid input. Note: this does /not/ perform
|
-- returning an error response on invalid input. Note: this does /not/ perform
|
||||||
-- CSRF protection.
|
-- CSRF protection.
|
||||||
@ -153,7 +156,9 @@ runFormPost' f = do
|
|||||||
(pp, files) <- runRequestBody
|
(pp, files) <- runRequestBody
|
||||||
x <- runFormGeneric pp files f
|
x <- runFormGeneric pp files f
|
||||||
helper x
|
helper x
|
||||||
|
-}
|
||||||
|
|
||||||
|
{- FIXME
|
||||||
-- | Create a table-styled form.
|
-- | Create a table-styled form.
|
||||||
--
|
--
|
||||||
-- This function wraps around 'runFormPost' and 'fieldsToTable', taking care of
|
-- This function wraps around 'runFormPost' and 'fieldsToTable', taking care of
|
||||||
@ -173,7 +178,9 @@ runFormTable dest inputLabel form = do
|
|||||||
\#{nonce}
|
\#{nonce}
|
||||||
<input type="submit" value="#{inputLabel}">
|
<input type="submit" value="#{inputLabel}">
|
||||||
|])
|
|])
|
||||||
|
-}
|
||||||
|
|
||||||
|
{- FIXME
|
||||||
-- | Same as 'runFormPostTable', but uses 'fieldsToDivs' for styling.
|
-- | Same as 'runFormPostTable', but uses 'fieldsToDivs' for styling.
|
||||||
runFormDivs :: Route m -> String -> FormField s m a
|
runFormDivs :: Route m -> String -> FormField s m a
|
||||||
-> GHandler s m (FormResult a, GWidget s m ())
|
-> GHandler s m (FormResult a, GWidget s m ())
|
||||||
@ -186,11 +193,14 @@ runFormDivs dest inputLabel form = do
|
|||||||
\#{nonce}
|
\#{nonce}
|
||||||
<input type="submit" value="#{inputLabel}">
|
<input type="submit" value="#{inputLabel}">
|
||||||
|])
|
|])
|
||||||
|
-}
|
||||||
|
|
||||||
|
{- FIXME
|
||||||
-- | Run a form against GET parameters, disregarding the resulting HTML and
|
-- | Run a form against GET parameters, disregarding the resulting HTML and
|
||||||
-- returning an error response on invalid input.
|
-- returning an error response on invalid input.
|
||||||
runFormGet' :: GForm sub y xml a -> GHandler sub y a
|
runFormGet' :: GForm xml mo a -> GHandler sub y a
|
||||||
runFormGet' = helper <=< runFormGet
|
runFormGet' = helper <=< runFormGet
|
||||||
|
-}
|
||||||
|
|
||||||
helper :: (FormResult a, b, c) -> GHandler sub y a
|
helper :: (FormResult a, b, c) -> GHandler sub y a
|
||||||
helper (FormSuccess a, _, _) = return a
|
helper (FormSuccess a, _, _) = return a
|
||||||
@ -199,26 +209,27 @@ helper (FormMissing, _, _) = invalidArgs ["No input found"]
|
|||||||
|
|
||||||
-- | Generate a form, feeding it no data. The third element in the result tuple
|
-- | Generate a form, feeding it no data. The third element in the result tuple
|
||||||
-- is a nonce hidden field.
|
-- is a nonce hidden field.
|
||||||
generateForm :: GForm s m xml a -> GHandler s m (xml, Enctype, Html)
|
generateForm :: Monad mo => GForm xml (GGHandler s m mo) a -> GGHandler s m mo (xml, Enctype, Html)
|
||||||
generateForm f = do
|
generateForm f = do
|
||||||
(_, b, c) <- runFormGeneric [] [] f
|
(_, b, c) <- runFormGeneric [] [] f
|
||||||
nonce <- fmap reqNonce getRequest
|
nonce <- liftM reqNonce getRequest
|
||||||
return (b, c, [HAMLET|\
|
return (b, c, [HAMLET|\
|
||||||
$maybe n <- nonce
|
$maybe n <- nonce
|
||||||
<input type="hidden" name="#{nonceName}" value="#{n}">
|
<input type="hidden" name="#{nonceName}" value="#{n}">
|
||||||
|])
|
|])
|
||||||
|
|
||||||
-- | Run a form against GET parameters.
|
-- | Run a form against GET parameters.
|
||||||
runFormGet :: GForm s m xml a -> GHandler s m (FormResult a, xml, Enctype)
|
runFormGet :: Monad mo => GForm xml (GGHandler s m mo) a -> GGHandler s m mo (a, xml, Enctype)
|
||||||
runFormGet f = do
|
runFormGet f = do
|
||||||
gs <- reqGetParams `fmap` getRequest
|
gs <- reqGetParams `liftM` getRequest
|
||||||
runFormGeneric gs [] f
|
runFormGeneric gs [] f
|
||||||
|
|
||||||
runFormMonadGet :: GFormMonad s m a -> GHandler s m (a, Enctype)
|
runFormGeneric :: Monad mo => Env -> FileEnv -> GForm xml mo a -> mo (a, xml, Enctype)
|
||||||
runFormMonadGet f = do
|
runFormGeneric e fe f = do
|
||||||
gs <- reqGetParams `fmap` getRequest
|
(a, _s, (enc, xml)) <- runRWST f (e, fe) (IntSingle 1)
|
||||||
runFormGeneric gs [] f
|
return (a, xml, enc)
|
||||||
|
|
||||||
|
{- FIXME
|
||||||
-- | Create 'ToForm' instances for the given entity. In addition to regular 'EntityDef' attributes understood by persistent, it also understands label= and tooltip=.
|
-- | Create 'ToForm' instances for the given entity. In addition to regular 'EntityDef' attributes understood by persistent, it also understands label= and tooltip=.
|
||||||
mkToForm :: PersistEntity v => v -> Q [Dec]
|
mkToForm :: PersistEntity v => v -> Q [Dec]
|
||||||
mkToForm =
|
mkToForm =
|
||||||
@ -298,6 +309,7 @@ mkToForm =
|
|||||||
(stm name)
|
(stm name)
|
||||||
in VarE (mkName tff) `AppE` ffs `AppE` ex
|
in VarE (mkName tff) `AppE` ffs `AppE` ex
|
||||||
ap' ap x y = InfixE (Just x) ap (Just y)
|
ap' ap x y = InfixE (Just x) ap (Just y)
|
||||||
|
-}
|
||||||
|
|
||||||
toLabel :: String -> String
|
toLabel :: String -> String
|
||||||
toLabel "" = ""
|
toLabel "" = ""
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
{-# LANGUAGE FlexibleInstances #-}
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
{-# LANGUAGE TypeSynonymInstances #-}
|
{-# LANGUAGE TypeSynonymInstances #-}
|
||||||
module Yesod.Form.Class
|
module Yesod.Form.Class
|
||||||
|
() where
|
||||||
|
{- FIXME Maybe we should remove this module entirely...
|
||||||
( ToForm (..)
|
( ToForm (..)
|
||||||
, ToFormField (..)
|
, ToFormField (..)
|
||||||
) where
|
) where
|
||||||
@ -67,3 +69,4 @@ instance ToFormField Textarea y where
|
|||||||
toFormField = textareaField
|
toFormField = textareaField
|
||||||
instance ToFormField (Maybe Textarea) y where
|
instance ToFormField (Maybe Textarea) y where
|
||||||
toFormField = maybeTextareaField
|
toFormField = maybeTextareaField
|
||||||
|
-}
|
||||||
|
|||||||
@ -8,39 +8,38 @@ module Yesod.Form.Core
|
|||||||
( FormResult (..)
|
( FormResult (..)
|
||||||
, GForm (..)
|
, GForm (..)
|
||||||
, newFormIdent
|
, newFormIdent
|
||||||
|
{- FIXME
|
||||||
, deeperFormIdent
|
, deeperFormIdent
|
||||||
, shallowerFormIdent
|
, shallowerFormIdent
|
||||||
|
-}
|
||||||
, Env
|
, Env
|
||||||
, FileEnv
|
, FileEnv
|
||||||
, Enctype (..)
|
, Enctype (..)
|
||||||
, Ints (..)
|
, Ints (..)
|
||||||
, requiredFieldHelper
|
, requiredFieldHelper
|
||||||
, optionalFieldHelper
|
, optionalFieldHelper
|
||||||
, fieldsToInput
|
|
||||||
, mapFormXml
|
, mapFormXml
|
||||||
|
{- FIXME
|
||||||
, checkForm
|
, checkForm
|
||||||
, checkField
|
, checkField
|
||||||
|
-}
|
||||||
, askParams
|
, askParams
|
||||||
, askFiles
|
, askFiles
|
||||||
, liftForm
|
|
||||||
, IsForm (..)
|
|
||||||
, RunForm (..)
|
|
||||||
, GFormMonad
|
|
||||||
-- * Data types
|
-- * Data types
|
||||||
, FieldInfo (..)
|
, FieldInfo (..)
|
||||||
, FormFieldSettings (..)
|
, FormFieldSettings (..)
|
||||||
, FieldProfile (..)
|
, FieldProfile (..)
|
||||||
-- * Type synonyms
|
-- * Type synonyms
|
||||||
|
{- FIXME
|
||||||
, Form
|
, Form
|
||||||
, Formlet
|
, Formlet
|
||||||
, FormField
|
, FormField
|
||||||
, FormletField
|
, FormletField
|
||||||
, FormInput
|
, FormInput
|
||||||
|
-}
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad.Trans.State
|
import Control.Monad.Trans.RWS
|
||||||
import Control.Monad.Trans.Reader
|
|
||||||
import Control.Monad.Trans.Writer
|
|
||||||
import Control.Monad.Trans.Class (lift)
|
import Control.Monad.Trans.Class (lift)
|
||||||
import Yesod.Handler
|
import Yesod.Handler
|
||||||
import Yesod.Widget
|
import Yesod.Widget
|
||||||
@ -83,7 +82,7 @@ instance Monoid m => Monoid (FormResult m) where
|
|||||||
mempty = pure mempty
|
mempty = pure mempty
|
||||||
mappend x y = mappend <$> x <*> y
|
mappend x y = mappend <$> x <*> y
|
||||||
|
|
||||||
-- | The encoding type required by a form. The 'Show' instance produces values
|
-- | The encoding type required by a form. The 'ToHtml' instance produces values
|
||||||
-- that can be inserted directly into HTML.
|
-- that can be inserted directly into HTML.
|
||||||
data Enctype = UrlEncoded | Multipart
|
data Enctype = UrlEncoded | Multipart
|
||||||
deriving (Eq, Enum, Bounded)
|
deriving (Eq, Enum, Bounded)
|
||||||
@ -104,32 +103,19 @@ incrInts :: Ints -> Ints
|
|||||||
incrInts (IntSingle i) = IntSingle $ i + 1
|
incrInts (IntSingle i) = IntSingle $ i + 1
|
||||||
incrInts (IntCons i is) = (i + 1) `IntCons` is
|
incrInts (IntCons i is) = (i + 1) `IntCons` is
|
||||||
|
|
||||||
-- | A generic form, allowing you to specifying the subsite datatype, master
|
type GForm xml m a = RWST (Env, FileEnv) (Enctype, xml) Ints m a -- FIXME rename to Form
|
||||||
-- site datatype, a datatype for the form XML and the return type.
|
|
||||||
newtype GForm s m xml a = GForm
|
|
||||||
{ deform :: FormInner s m (FormResult a, xml, Enctype)
|
|
||||||
}
|
|
||||||
|
|
||||||
type GFormMonad s m a = WriterT Enctype (FormInner s m) a
|
|
||||||
|
|
||||||
type FormInner s m =
|
|
||||||
StateT Ints (
|
|
||||||
ReaderT Env (
|
|
||||||
ReaderT FileEnv (
|
|
||||||
GHandler s m
|
|
||||||
)))
|
|
||||||
|
|
||||||
type Env = [(Text, Text)]
|
type Env = [(Text, Text)]
|
||||||
type FileEnv = [(Text, FileInfo)]
|
type FileEnv = [(Text, FileInfo)]
|
||||||
|
|
||||||
-- | Get a unique identifier.
|
-- | Get a unique identifier.
|
||||||
newFormIdent :: Monad m => StateT Ints m Text
|
newFormIdent :: (Monoid xml, Monad m) => GForm xml m Text
|
||||||
newFormIdent = do
|
newFormIdent = do
|
||||||
i <- get
|
i <- get
|
||||||
let i' = incrInts i
|
let i' = incrInts i
|
||||||
put i'
|
put i'
|
||||||
return $ pack $ 'f' : show i'
|
return $ pack $ 'f' : show i'
|
||||||
|
|
||||||
|
{- FIXME
|
||||||
deeperFormIdent :: Monad m => StateT Ints m ()
|
deeperFormIdent :: Monad m => StateT Ints m ()
|
||||||
deeperFormIdent = do
|
deeperFormIdent = do
|
||||||
i <- get
|
i <- get
|
||||||
@ -140,30 +126,18 @@ shallowerFormIdent :: Monad m => StateT Ints m ()
|
|||||||
shallowerFormIdent = do
|
shallowerFormIdent = do
|
||||||
IntCons _ i <- get
|
IntCons _ i <- get
|
||||||
put i
|
put i
|
||||||
|
-}
|
||||||
instance Monoid xml => Functor (GForm sub url xml) where
|
|
||||||
fmap f (GForm g) =
|
|
||||||
GForm $ liftM (first3 $ fmap f) g
|
|
||||||
where
|
|
||||||
first3 f' (x, y, z) = (f' x, y, z)
|
|
||||||
|
|
||||||
instance Monoid xml => Applicative (GForm sub url xml) where
|
|
||||||
pure a = GForm $ return (pure a, mempty, mempty)
|
|
||||||
(GForm f) <*> (GForm g) = GForm $ do
|
|
||||||
(f1, f2, f3) <- f
|
|
||||||
(g1, g2, g3) <- g
|
|
||||||
return (f1 <*> g1, f2 `mappend` g2, f3 `mappend` g3)
|
|
||||||
|
|
||||||
-- | Create a required field (ie, one that cannot be blank) from a
|
-- | Create a required field (ie, one that cannot be blank) from a
|
||||||
-- 'FieldProfile'.
|
-- 'FieldProfile'.
|
||||||
requiredFieldHelper
|
requiredFieldHelper
|
||||||
:: IsForm f
|
:: (Monoid xml', Monad m)
|
||||||
=> FieldProfile (FormSub f) (FormMaster f) (FormType f)
|
=> FieldProfile xml a
|
||||||
-> FormFieldSettings
|
-> FormFieldSettings
|
||||||
-> Maybe (FormType f)
|
-> Maybe a
|
||||||
-> f
|
-> GForm xml' m (FormResult a, FieldInfo xml)
|
||||||
requiredFieldHelper (FieldProfile parse render mkWidget) ffs orig = toForm $ do
|
requiredFieldHelper (FieldProfile parse render mkWidget) ffs orig = do
|
||||||
env <- lift ask
|
env <- askParams
|
||||||
let (FormFieldSettings label tooltip theId' name') = ffs
|
let (FormFieldSettings label tooltip theId' name') = ffs
|
||||||
name <- maybe newFormIdent return name'
|
name <- maybe newFormIdent return name'
|
||||||
theId <- maybe newFormIdent return theId'
|
theId <- maybe newFormIdent return theId'
|
||||||
@ -172,7 +146,7 @@ requiredFieldHelper (FieldProfile parse render mkWidget) ffs orig = toForm $ do
|
|||||||
then (FormMissing, maybe "" render orig)
|
then (FormMissing, maybe "" render orig)
|
||||||
else case lookup name env of
|
else case lookup name env of
|
||||||
Nothing -> (FormMissing, "")
|
Nothing -> (FormMissing, "")
|
||||||
Just "" -> (FormFailure ["Value is required"], "")
|
Just "" -> (FormFailure ["Value is required"], "") -- TRANS
|
||||||
Just x ->
|
Just x ->
|
||||||
case parse x of
|
case parse x of
|
||||||
Left e -> (FormFailure [e], x)
|
Left e -> (FormFailure [e], x)
|
||||||
@ -190,68 +164,18 @@ requiredFieldHelper (FieldProfile parse render mkWidget) ffs orig = toForm $ do
|
|||||||
let res' = case res of
|
let res' = case res of
|
||||||
FormFailure [e] -> FormFailure [label ++ ": " ++ e]
|
FormFailure [e] -> FormFailure [label ++ ": " ++ e]
|
||||||
_ -> res
|
_ -> res
|
||||||
return (res', fi, UrlEncoded)
|
return (res', fi)
|
||||||
|
|
||||||
class IsForm f where
|
|
||||||
type FormSub f
|
|
||||||
type FormMaster f
|
|
||||||
type FormType f
|
|
||||||
toForm :: FormInner
|
|
||||||
(FormSub f)
|
|
||||||
(FormMaster f)
|
|
||||||
(FormResult (FormType f),
|
|
||||||
FieldInfo (FormSub f) (FormMaster f),
|
|
||||||
Enctype) -> f
|
|
||||||
instance IsForm (FormField s m a) where
|
|
||||||
type FormSub (FormField s m a) = s
|
|
||||||
type FormMaster (FormField s m a) = m
|
|
||||||
type FormType (FormField s m a) = a
|
|
||||||
toForm x = GForm $ do
|
|
||||||
(a, b, c) <- x
|
|
||||||
return (a, [b], c)
|
|
||||||
instance (FormResult ~ formResult) => IsForm (GFormMonad s m (formResult a, FieldInfo s m)) where
|
|
||||||
type FormSub (GFormMonad s m (formResult a, FieldInfo s m)) = s
|
|
||||||
type FormMaster (GFormMonad s m (formResult a, FieldInfo s m)) = m
|
|
||||||
type FormType (GFormMonad s m (formResult a, FieldInfo s m)) = a
|
|
||||||
toForm x = do
|
|
||||||
(res, fi, enctype) <- lift x
|
|
||||||
tell enctype
|
|
||||||
return (res, fi)
|
|
||||||
|
|
||||||
class RunForm f where
|
|
||||||
type RunFormSub f
|
|
||||||
type RunFormMaster f
|
|
||||||
type RunFormType f
|
|
||||||
runFormGeneric :: Env -> FileEnv -> f
|
|
||||||
-> GHandler (RunFormSub f)
|
|
||||||
(RunFormMaster f)
|
|
||||||
(RunFormType f)
|
|
||||||
|
|
||||||
instance RunForm (GForm s m xml a) where
|
|
||||||
type RunFormSub (GForm s m xml a) = s
|
|
||||||
type RunFormMaster (GForm s m xml a) = m
|
|
||||||
type RunFormType (GForm s m xml a) =
|
|
||||||
(FormResult a, xml, Enctype)
|
|
||||||
runFormGeneric env fe (GForm f) =
|
|
||||||
runReaderT (runReaderT (evalStateT f $ IntSingle 1) env) fe
|
|
||||||
|
|
||||||
instance RunForm (GFormMonad s m a) where
|
|
||||||
type RunFormSub (GFormMonad s m a) = s
|
|
||||||
type RunFormMaster (GFormMonad s m a) = m
|
|
||||||
type RunFormType (GFormMonad s m a) = (a, Enctype)
|
|
||||||
runFormGeneric e fe f =
|
|
||||||
runReaderT (runReaderT (evalStateT (runWriterT f) $ IntSingle 1) e) fe
|
|
||||||
|
|
||||||
-- | Create an optional field (ie, one that can be blank) from a
|
-- | Create an optional field (ie, one that can be blank) from a
|
||||||
-- 'FieldProfile'.
|
-- 'FieldProfile'.
|
||||||
optionalFieldHelper
|
optionalFieldHelper
|
||||||
:: (IsForm f, Maybe b ~ FormType f)
|
:: (Monad m, Monoid xml')
|
||||||
=> FieldProfile (FormSub f) (FormMaster f) b
|
=> FieldProfile xml b
|
||||||
-> FormFieldSettings
|
-> FormFieldSettings
|
||||||
-> Maybe (Maybe b)
|
-> Maybe (Maybe b)
|
||||||
-> f
|
-> GForm xml' m (FormResult (Maybe b), FieldInfo xml)
|
||||||
optionalFieldHelper (FieldProfile parse render mkWidget) ffs orig' = toForm $ do
|
optionalFieldHelper (FieldProfile parse render mkWidget) ffs orig' = do
|
||||||
env <- lift ask
|
env <- askParams
|
||||||
let (FormFieldSettings label tooltip theId' name') = ffs
|
let (FormFieldSettings label tooltip theId' name') = ffs
|
||||||
let orig = join orig'
|
let orig = join orig'
|
||||||
name <- maybe newFormIdent return name'
|
name <- maybe newFormIdent return name'
|
||||||
@ -279,25 +203,22 @@ optionalFieldHelper (FieldProfile parse render mkWidget) ffs orig' = toForm $ do
|
|||||||
let res' = case res of
|
let res' = case res of
|
||||||
FormFailure [e] -> FormFailure [label ++ ": " ++ e]
|
FormFailure [e] -> FormFailure [label ++ ": " ++ e]
|
||||||
_ -> res
|
_ -> res
|
||||||
return (res', fi, UrlEncoded)
|
return (res', fi)
|
||||||
|
|
||||||
fieldsToInput :: [FieldInfo sub y] -> [GWidget sub y ()]
|
|
||||||
fieldsToInput = map fiInput
|
|
||||||
|
|
||||||
-- | Convert the XML in a 'GForm'.
|
-- | Convert the XML in a 'GForm'.
|
||||||
mapFormXml :: (xml1 -> xml2) -> GForm s y xml1 a -> GForm s y xml2 a
|
mapFormXml :: Monad m => (xml1 -> xml2) -> GForm xml1 m a -> GForm xml2 m a
|
||||||
mapFormXml f (GForm g) = GForm $ do
|
mapFormXml f = mapRWST $ \x -> do
|
||||||
(res, xml, enc) <- g
|
(a, b, (c, d)) <- x
|
||||||
return (res, f xml, enc)
|
return (a, b, (c, f d))
|
||||||
|
|
||||||
-- | Using this as the intermediate XML representation for fields allows us to
|
-- | Using this as the intermediate XML representation for fields allows us to
|
||||||
-- write generic field functions and then different functions for producing
|
-- write generic field functions and then different functions for producing
|
||||||
-- actual HTML. See, for example, 'fieldsToTable' and 'fieldsToPlain'.
|
-- actual HTML. See, for example, 'fieldsToTable' and 'fieldsToPlain'.
|
||||||
data FieldInfo sub y = FieldInfo
|
data FieldInfo xml = FieldInfo
|
||||||
{ fiLabel :: Html
|
{ fiLabel :: Html
|
||||||
, fiTooltip :: Html
|
, fiTooltip :: Html
|
||||||
, fiIdent :: Text
|
, fiIdent :: Text
|
||||||
, fiInput :: GWidget sub y ()
|
, fiInput :: xml
|
||||||
, fiErrors :: Maybe Html
|
, fiErrors :: Maybe Html
|
||||||
, fiRequired :: Bool
|
, fiRequired :: Bool
|
||||||
}
|
}
|
||||||
@ -314,19 +235,22 @@ instance IsString FormFieldSettings where
|
|||||||
-- | A generic definition of a form field that can be used for generating both
|
-- | A generic definition of a form field that can be used for generating both
|
||||||
-- required and optional fields. See 'requiredFieldHelper and
|
-- required and optional fields. See 'requiredFieldHelper and
|
||||||
-- 'optionalFieldHelper'.
|
-- 'optionalFieldHelper'.
|
||||||
data FieldProfile sub y a = FieldProfile
|
data FieldProfile xml a = FieldProfile
|
||||||
{ fpParse :: Text -> Either Text a
|
{ fpParse :: Text -> Either Text a
|
||||||
, fpRender :: a -> Text
|
, fpRender :: a -> Text
|
||||||
-- | ID, name, value, required
|
-- | ID, name, value, required
|
||||||
, fpWidget :: Text -> Text -> Text -> Bool -> GWidget sub y ()
|
, fpWidget :: Text -> Text -> Text -> Bool -> xml
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{- FIXME
|
||||||
type Form sub y = GForm sub y (GWidget sub y ())
|
type Form sub y = GForm sub y (GWidget sub y ())
|
||||||
type Formlet sub y a = Maybe a -> Form sub y a
|
type Formlet sub y a = Maybe a -> Form sub y a
|
||||||
type FormField sub y = GForm sub y [FieldInfo sub y]
|
|
||||||
type FormletField sub y a = Maybe a -> FormField sub y a
|
|
||||||
type FormInput sub y = GForm sub y [GWidget sub y ()]
|
type FormInput sub y = GForm sub y [GWidget sub y ()]
|
||||||
|
type FormField xml m = GForm xml m [FieldInfo xml]
|
||||||
|
type FormletField xml m a = Maybe a -> FormField xml a
|
||||||
|
-}
|
||||||
|
|
||||||
|
{- FIXME
|
||||||
-- | Add a validation check to a form.
|
-- | Add a validation check to a form.
|
||||||
--
|
--
|
||||||
-- Note that if there is a validation error, this message will /not/
|
-- Note that if there is a validation error, this message will /not/
|
||||||
@ -345,7 +269,7 @@ checkForm f (GForm form) = GForm $ do
|
|||||||
-- Unlike 'checkForm', the validation error will appear in the generated HTML
|
-- Unlike 'checkForm', the validation error will appear in the generated HTML
|
||||||
-- of the form.
|
-- of the form.
|
||||||
checkField :: (a -> Either Text b) -> FormField s m a -> FormField s m b
|
checkField :: (a -> Either Text b) -> FormField s m a -> FormField s m b
|
||||||
checkField f (GForm form) = GForm $ do
|
checkField f form = do
|
||||||
(res, xml, enc) <- form
|
(res, xml, enc) <- form
|
||||||
let (res', merr) =
|
let (res', merr) =
|
||||||
case res of
|
case res of
|
||||||
@ -365,12 +289,10 @@ checkField f (GForm form) = GForm $ do
|
|||||||
Just x -> x
|
Just x -> x
|
||||||
}
|
}
|
||||||
return (res', xml', enc)
|
return (res', xml', enc)
|
||||||
|
-}
|
||||||
|
|
||||||
askParams :: Monad m => StateT Ints (ReaderT Env m) Env
|
askParams :: (Monoid xml, Monad m) => GForm xml m Env
|
||||||
askParams = lift ask
|
askParams = liftM fst ask
|
||||||
|
|
||||||
askFiles :: Monad m => StateT Ints (ReaderT Env (ReaderT FileEnv m)) FileEnv
|
askFiles :: (Monoid xml, Monad m) => GForm xml m FileEnv
|
||||||
askFiles = lift $ lift ask
|
askFiles = liftM snd ask
|
||||||
|
|
||||||
liftForm :: Monad m => m a -> StateT Ints (ReaderT Env (ReaderT FileEnv m)) a
|
|
||||||
liftForm = lift . lift . lift
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE CPP #-}
|
{-# LANGUAGE CPP #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE NoMonomorphismRestriction #-} -- FIXME remove
|
||||||
module Yesod.Form.Fields
|
module Yesod.Form.Fields
|
||||||
( -- * Fields
|
( -- * Fields
|
||||||
-- ** Required
|
-- ** Required
|
||||||
@ -38,6 +39,7 @@ module Yesod.Form.Fields
|
|||||||
, maybeSearchField
|
, maybeSearchField
|
||||||
, maybeUrlField
|
, maybeUrlField
|
||||||
, maybeFileField
|
, maybeFileField
|
||||||
|
{- FIXME
|
||||||
-- * Inputs
|
-- * Inputs
|
||||||
-- ** Required
|
-- ** Required
|
||||||
, stringInput
|
, stringInput
|
||||||
@ -50,6 +52,7 @@ module Yesod.Form.Fields
|
|||||||
, maybeStringInput
|
, maybeStringInput
|
||||||
, maybeDayInput
|
, maybeDayInput
|
||||||
, maybeIntInput
|
, maybeIntInput
|
||||||
|
-}
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Yesod.Form.Core
|
import Yesod.Form.Core
|
||||||
@ -72,67 +75,41 @@ import qualified Data.Text as T
|
|||||||
#define HAMLET $hamlet
|
#define HAMLET $hamlet
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
stringField :: (IsForm f, FormType f ~ Text)
|
|
||||||
=> FormFieldSettings -> Maybe Text -> f
|
|
||||||
stringField = requiredFieldHelper stringFieldProfile
|
stringField = requiredFieldHelper stringFieldProfile
|
||||||
|
|
||||||
maybeStringField :: (IsForm f, FormType f ~ Maybe Text)
|
|
||||||
=> FormFieldSettings -> Maybe (Maybe Text) -> f
|
|
||||||
maybeStringField = optionalFieldHelper stringFieldProfile
|
maybeStringField = optionalFieldHelper stringFieldProfile
|
||||||
|
|
||||||
passwordField :: (IsForm f, FormType f ~ Text)
|
|
||||||
=> FormFieldSettings -> Maybe Text -> f
|
|
||||||
passwordField = requiredFieldHelper passwordFieldProfile
|
passwordField = requiredFieldHelper passwordFieldProfile
|
||||||
|
|
||||||
maybePasswordField :: (IsForm f, FormType f ~ Maybe Text)
|
|
||||||
=> FormFieldSettings -> Maybe (Maybe Text) -> f
|
|
||||||
maybePasswordField = optionalFieldHelper passwordFieldProfile
|
maybePasswordField = optionalFieldHelper passwordFieldProfile
|
||||||
|
|
||||||
intInput :: Integral i => Text -> FormInput sub master i
|
{- FIXME
|
||||||
intInput n =
|
intInput n =
|
||||||
mapFormXml fieldsToInput $
|
mapFormXml fieldsToInput $
|
||||||
requiredFieldHelper intFieldProfile (nameSettings n) Nothing
|
requiredFieldHelper intFieldProfile (nameSettings n) Nothing
|
||||||
|
|
||||||
maybeIntInput :: Integral i => Text -> FormInput sub master (Maybe i)
|
|
||||||
maybeIntInput n =
|
maybeIntInput n =
|
||||||
mapFormXml fieldsToInput $
|
mapFormXml fieldsToInput $
|
||||||
optionalFieldHelper intFieldProfile (nameSettings n) Nothing
|
optionalFieldHelper intFieldProfile (nameSettings n) Nothing
|
||||||
|
-}
|
||||||
|
|
||||||
intField :: (Integral (FormType f), IsForm f)
|
|
||||||
=> FormFieldSettings -> Maybe (FormType f) -> f
|
|
||||||
intField = requiredFieldHelper intFieldProfile
|
intField = requiredFieldHelper intFieldProfile
|
||||||
|
|
||||||
maybeIntField :: (Integral i, FormType f ~ Maybe i, IsForm f)
|
|
||||||
=> FormFieldSettings -> Maybe (FormType f) -> f
|
|
||||||
maybeIntField = optionalFieldHelper intFieldProfile
|
maybeIntField = optionalFieldHelper intFieldProfile
|
||||||
|
|
||||||
doubleField :: (IsForm f, FormType f ~ Double)
|
|
||||||
=> FormFieldSettings -> Maybe Double -> f
|
|
||||||
doubleField = requiredFieldHelper doubleFieldProfile
|
doubleField = requiredFieldHelper doubleFieldProfile
|
||||||
|
|
||||||
maybeDoubleField :: (IsForm f, FormType f ~ Maybe Double)
|
|
||||||
=> FormFieldSettings -> Maybe (Maybe Double) -> f
|
|
||||||
maybeDoubleField = optionalFieldHelper doubleFieldProfile
|
maybeDoubleField = optionalFieldHelper doubleFieldProfile
|
||||||
|
|
||||||
dayField :: (IsForm f, FormType f ~ Day)
|
|
||||||
=> FormFieldSettings -> Maybe Day -> f
|
|
||||||
dayField = requiredFieldHelper dayFieldProfile
|
dayField = requiredFieldHelper dayFieldProfile
|
||||||
|
|
||||||
maybeDayField :: (IsForm f, FormType f ~ Maybe Day)
|
|
||||||
=> FormFieldSettings -> Maybe (Maybe Day) -> f
|
|
||||||
maybeDayField = optionalFieldHelper dayFieldProfile
|
maybeDayField = optionalFieldHelper dayFieldProfile
|
||||||
|
|
||||||
timeField :: (IsForm f, FormType f ~ TimeOfDay)
|
|
||||||
=> FormFieldSettings -> Maybe TimeOfDay -> f
|
|
||||||
timeField = requiredFieldHelper timeFieldProfile
|
timeField = requiredFieldHelper timeFieldProfile
|
||||||
|
|
||||||
maybeTimeField :: (IsForm f, FormType f ~ Maybe TimeOfDay)
|
|
||||||
=> FormFieldSettings -> Maybe (Maybe TimeOfDay) -> f
|
|
||||||
maybeTimeField = optionalFieldHelper timeFieldProfile
|
maybeTimeField = optionalFieldHelper timeFieldProfile
|
||||||
|
|
||||||
boolField :: (IsForm f, FormType f ~ Bool)
|
boolField ffs orig = do
|
||||||
=> FormFieldSettings -> Maybe Bool -> f
|
|
||||||
boolField ffs orig = toForm $ do
|
|
||||||
env <- askParams
|
env <- askParams
|
||||||
let label = ffsLabel ffs
|
let label = ffsLabel ffs
|
||||||
tooltip = ffsTooltip ffs
|
tooltip = ffsTooltip ffs
|
||||||
@ -160,20 +137,11 @@ boolField ffs orig = toForm $ do
|
|||||||
}
|
}
|
||||||
return (res, fi, UrlEncoded)
|
return (res, fi, UrlEncoded)
|
||||||
|
|
||||||
htmlField :: (IsForm f, FormType f ~ Html)
|
|
||||||
=> FormFieldSettings -> Maybe Html -> f
|
|
||||||
htmlField = requiredFieldHelper htmlFieldProfile
|
htmlField = requiredFieldHelper htmlFieldProfile
|
||||||
|
|
||||||
maybeHtmlField :: (IsForm f, FormType f ~ Maybe Html)
|
|
||||||
=> FormFieldSettings -> Maybe (Maybe Html) -> f
|
|
||||||
maybeHtmlField = optionalFieldHelper htmlFieldProfile
|
maybeHtmlField = optionalFieldHelper htmlFieldProfile
|
||||||
|
|
||||||
selectField :: (Eq x, IsForm f, FormType f ~ x)
|
selectField pairs ffs initial = do
|
||||||
=> [(x, Text)]
|
|
||||||
-> FormFieldSettings
|
|
||||||
-> Maybe x
|
|
||||||
-> f
|
|
||||||
selectField pairs ffs initial = toForm $ do
|
|
||||||
env <- askParams
|
env <- askParams
|
||||||
let label = ffsLabel ffs
|
let label = ffsLabel ffs
|
||||||
tooltip = ffsTooltip ffs
|
tooltip = ffsTooltip ffs
|
||||||
@ -217,12 +185,7 @@ selectField pairs ffs initial = toForm $ do
|
|||||||
}
|
}
|
||||||
return (res, fi, UrlEncoded)
|
return (res, fi, UrlEncoded)
|
||||||
|
|
||||||
maybeSelectField :: (Eq x, IsForm f, Maybe x ~ FormType f)
|
maybeSelectField pairs ffs initial' = do
|
||||||
=> [(x, Text)]
|
|
||||||
-> FormFieldSettings
|
|
||||||
-> Maybe (FormType f)
|
|
||||||
-> f
|
|
||||||
maybeSelectField pairs ffs initial' = toForm $ do
|
|
||||||
env <- askParams
|
env <- askParams
|
||||||
let initial = join initial'
|
let initial = join initial'
|
||||||
label = ffsLabel ffs
|
label = ffsLabel ffs
|
||||||
@ -267,6 +230,7 @@ maybeSelectField pairs ffs initial' = toForm $ do
|
|||||||
}
|
}
|
||||||
return (res, fi, UrlEncoded)
|
return (res, fi, UrlEncoded)
|
||||||
|
|
||||||
|
{- FIXME
|
||||||
stringInput :: Text -> FormInput sub master Text
|
stringInput :: Text -> FormInput sub master Text
|
||||||
stringInput n =
|
stringInput n =
|
||||||
mapFormXml fieldsToInput $
|
mapFormXml fieldsToInput $
|
||||||
@ -299,62 +263,46 @@ maybeDayInput :: Text -> FormInput sub master (Maybe Day)
|
|||||||
maybeDayInput n =
|
maybeDayInput n =
|
||||||
mapFormXml fieldsToInput $
|
mapFormXml fieldsToInput $
|
||||||
optionalFieldHelper dayFieldProfile (nameSettings n) Nothing
|
optionalFieldHelper dayFieldProfile (nameSettings n) Nothing
|
||||||
|
-}
|
||||||
|
|
||||||
nameSettings :: Text -> FormFieldSettings
|
nameSettings :: Text -> FormFieldSettings
|
||||||
nameSettings n = FormFieldSettings mempty mempty (Just n) (Just n)
|
nameSettings n = FormFieldSettings mempty mempty (Just n) (Just n)
|
||||||
|
|
||||||
urlField :: (IsForm f, FormType f ~ Text)
|
|
||||||
=> FormFieldSettings -> Maybe Text -> f
|
|
||||||
urlField = requiredFieldHelper urlFieldProfile
|
urlField = requiredFieldHelper urlFieldProfile
|
||||||
|
|
||||||
maybeUrlField :: (IsForm f, FormType f ~ Maybe Text)
|
|
||||||
=> FormFieldSettings -> Maybe (Maybe Text) -> f
|
|
||||||
maybeUrlField = optionalFieldHelper urlFieldProfile
|
maybeUrlField = optionalFieldHelper urlFieldProfile
|
||||||
|
|
||||||
|
{- FIXME
|
||||||
urlInput :: Text -> FormInput sub master Text
|
urlInput :: Text -> FormInput sub master Text
|
||||||
urlInput n =
|
urlInput n =
|
||||||
mapFormXml fieldsToInput $
|
mapFormXml fieldsToInput $
|
||||||
requiredFieldHelper urlFieldProfile (nameSettings n) Nothing
|
requiredFieldHelper urlFieldProfile (nameSettings n) Nothing
|
||||||
|
-}
|
||||||
|
|
||||||
emailField :: (IsForm f, FormType f ~ Text)
|
|
||||||
=> FormFieldSettings -> Maybe Text -> f
|
|
||||||
emailField = requiredFieldHelper emailFieldProfile
|
emailField = requiredFieldHelper emailFieldProfile
|
||||||
|
|
||||||
maybeEmailField :: (IsForm f, FormType f ~ Maybe Text)
|
|
||||||
=> FormFieldSettings -> Maybe (Maybe Text) -> f
|
|
||||||
maybeEmailField = optionalFieldHelper emailFieldProfile
|
maybeEmailField = optionalFieldHelper emailFieldProfile
|
||||||
|
|
||||||
|
{- FIXME
|
||||||
emailInput :: Text -> FormInput sub master Text
|
emailInput :: Text -> FormInput sub master Text
|
||||||
emailInput n =
|
emailInput n =
|
||||||
mapFormXml fieldsToInput $
|
mapFormXml fieldsToInput $
|
||||||
requiredFieldHelper emailFieldProfile (nameSettings n) Nothing
|
requiredFieldHelper emailFieldProfile (nameSettings n) Nothing
|
||||||
|
-}
|
||||||
|
|
||||||
searchField :: (IsForm f, FormType f ~ Text)
|
|
||||||
=> AutoFocus -> FormFieldSettings -> Maybe Text -> f
|
|
||||||
searchField = requiredFieldHelper . searchFieldProfile
|
searchField = requiredFieldHelper . searchFieldProfile
|
||||||
|
|
||||||
maybeSearchField :: (IsForm f, FormType f ~ Maybe Text)
|
|
||||||
=> AutoFocus -> FormFieldSettings -> Maybe (Maybe Text) -> f
|
|
||||||
maybeSearchField = optionalFieldHelper . searchFieldProfile
|
maybeSearchField = optionalFieldHelper . searchFieldProfile
|
||||||
|
|
||||||
textareaField :: (IsForm f, FormType f ~ Textarea)
|
|
||||||
=> FormFieldSettings -> Maybe Textarea -> f
|
|
||||||
textareaField = requiredFieldHelper textareaFieldProfile
|
textareaField = requiredFieldHelper textareaFieldProfile
|
||||||
|
|
||||||
maybeTextareaField :: FormFieldSettings -> FormletField sub y (Maybe Textarea)
|
|
||||||
maybeTextareaField = optionalFieldHelper textareaFieldProfile
|
maybeTextareaField = optionalFieldHelper textareaFieldProfile
|
||||||
|
|
||||||
hiddenField :: (IsForm f, FormType f ~ Text)
|
|
||||||
=> FormFieldSettings -> Maybe Text -> f
|
|
||||||
hiddenField = requiredFieldHelper hiddenFieldProfile
|
hiddenField = requiredFieldHelper hiddenFieldProfile
|
||||||
|
|
||||||
maybeHiddenField :: (IsForm f, FormType f ~ Maybe Text)
|
|
||||||
=> FormFieldSettings -> Maybe (Maybe Text) -> f
|
|
||||||
maybeHiddenField = optionalFieldHelper hiddenFieldProfile
|
maybeHiddenField = optionalFieldHelper hiddenFieldProfile
|
||||||
|
|
||||||
fileField :: (IsForm f, FormType f ~ FileInfo)
|
fileField ffs = do
|
||||||
=> FormFieldSettings -> f
|
|
||||||
fileField ffs = toForm $ do
|
|
||||||
env <- lift ask
|
env <- lift ask
|
||||||
fenv <- lift $ lift ask
|
fenv <- lift $ lift ask
|
||||||
let (FormFieldSettings label tooltip theId' name') = ffs
|
let (FormFieldSettings label tooltip theId' name') = ffs
|
||||||
@ -381,9 +329,7 @@ fileField ffs = toForm $ do
|
|||||||
_ -> res
|
_ -> res
|
||||||
return (res', fi, Multipart)
|
return (res', fi, Multipart)
|
||||||
|
|
||||||
maybeFileField :: (IsForm f, FormType f ~ Maybe FileInfo)
|
maybeFileField ffs = do
|
||||||
=> FormFieldSettings -> f
|
|
||||||
maybeFileField ffs = toForm $ do
|
|
||||||
fenv <- lift $ lift ask
|
fenv <- lift $ lift ask
|
||||||
let (FormFieldSettings label tooltip theId' name') = ffs
|
let (FormFieldSettings label tooltip theId' name') = ffs
|
||||||
name <- maybe newFormIdent return name'
|
name <- maybe newFormIdent return name'
|
||||||
@ -404,12 +350,7 @@ fileWidget theId name isReq = [HAMLET|
|
|||||||
<input id="#{theId}" type="file" name="#{name}" :isReq:required="">
|
<input id="#{theId}" type="file" name="#{name}" :isReq:required="">
|
||||||
|]
|
|]
|
||||||
|
|
||||||
radioField :: (Eq x, IsForm f, FormType f ~ x)
|
radioField pairs ffs initial = do
|
||||||
=> [(x, Text)]
|
|
||||||
-> FormFieldSettings
|
|
||||||
-> Maybe x
|
|
||||||
-> f
|
|
||||||
radioField pairs ffs initial = toForm $ do
|
|
||||||
env <- askParams
|
env <- askParams
|
||||||
let label = ffsLabel ffs
|
let label = ffsLabel ffs
|
||||||
tooltip = ffsTooltip ffs
|
tooltip = ffsTooltip ffs
|
||||||
@ -449,13 +390,7 @@ radioField pairs ffs initial = toForm $ do
|
|||||||
}
|
}
|
||||||
return (res, fi, UrlEncoded)
|
return (res, fi, UrlEncoded)
|
||||||
|
|
||||||
maybeRadioField
|
maybeRadioField pairs ffs initial' = do
|
||||||
:: (Eq x, IsForm f, FormType f ~ Maybe x)
|
|
||||||
=> [(x, Text)]
|
|
||||||
-> FormFieldSettings
|
|
||||||
-> Maybe (FormType f)
|
|
||||||
-> f
|
|
||||||
maybeRadioField pairs ffs initial' = toForm $ do
|
|
||||||
env <- askParams
|
env <- askParams
|
||||||
let initial = join initial'
|
let initial = join initial'
|
||||||
label = ffsLabel ffs
|
label = ffsLabel ffs
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE CPP #-}
|
{-# LANGUAGE CPP #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE NoMonomorphismRestriction #-} -- FIXME remove
|
||||||
-- | Some fields spiced up with jQuery UI.
|
-- | Some fields spiced up with jQuery UI.
|
||||||
module Yesod.Form.Jquery
|
module Yesod.Form.Jquery
|
||||||
( YesodJquery (..)
|
( YesodJquery (..)
|
||||||
@ -67,23 +68,10 @@ class YesodJquery a where
|
|||||||
urlJqueryUiDateTimePicker :: a -> Either (Route a) Text
|
urlJqueryUiDateTimePicker :: a -> Either (Route a) Text
|
||||||
urlJqueryUiDateTimePicker _ = Right "http://github.com/gregwebs/jquery.ui.datetimepicker/raw/master/jquery.ui.datetimepicker.js"
|
urlJqueryUiDateTimePicker _ = Right "http://github.com/gregwebs/jquery.ui.datetimepicker/raw/master/jquery.ui.datetimepicker.js"
|
||||||
|
|
||||||
jqueryDayField :: (IsForm f, FormType f ~ Day, YesodJquery (FormMaster f))
|
|
||||||
=> JqueryDaySettings
|
|
||||||
-> FormFieldSettings
|
|
||||||
-> Maybe (FormType f)
|
|
||||||
-> f
|
|
||||||
jqueryDayField = requiredFieldHelper . jqueryDayFieldProfile
|
jqueryDayField = requiredFieldHelper . jqueryDayFieldProfile
|
||||||
|
|
||||||
maybeJqueryDayField
|
|
||||||
:: (IsForm f, FormType f ~ Maybe Day, YesodJquery (FormMaster f))
|
|
||||||
=> JqueryDaySettings
|
|
||||||
-> FormFieldSettings
|
|
||||||
-> Maybe (FormType f)
|
|
||||||
-> f
|
|
||||||
maybeJqueryDayField = optionalFieldHelper . jqueryDayFieldProfile
|
maybeJqueryDayField = optionalFieldHelper . jqueryDayFieldProfile
|
||||||
|
|
||||||
jqueryDayFieldProfile :: YesodJquery y
|
|
||||||
=> JqueryDaySettings -> FieldProfile sub y Day
|
|
||||||
jqueryDayFieldProfile jds = FieldProfile
|
jqueryDayFieldProfile jds = FieldProfile
|
||||||
{ fpParse = maybe
|
{ fpParse = maybe
|
||||||
(Left "Invalid day, must be in YYYY-MM-DD format")
|
(Left "Invalid day, must be in YYYY-MM-DD format")
|
||||||
@ -128,11 +116,6 @@ ifRight e f = case e of
|
|||||||
showLeadingZero :: (Show a) => a -> String
|
showLeadingZero :: (Show a) => a -> String
|
||||||
showLeadingZero time = let t = show time in if length t == 1 then "0" ++ t else t
|
showLeadingZero time = let t = show time in if length t == 1 then "0" ++ t else t
|
||||||
|
|
||||||
jqueryDayTimeField
|
|
||||||
:: (IsForm f, FormType f ~ UTCTime, YesodJquery (FormMaster f))
|
|
||||||
=> FormFieldSettings
|
|
||||||
-> Maybe (FormType f)
|
|
||||||
-> f
|
|
||||||
jqueryDayTimeField = requiredFieldHelper jqueryDayTimeFieldProfile
|
jqueryDayTimeField = requiredFieldHelper jqueryDayTimeFieldProfile
|
||||||
|
|
||||||
-- use A.M/P.M and drop seconds and "UTC" (as opposed to normal UTCTime show)
|
-- use A.M/P.M and drop seconds and "UTC" (as opposed to normal UTCTime show)
|
||||||
@ -145,7 +128,6 @@ jqueryDayTimeUTCTime (UTCTime day utcTime) =
|
|||||||
let (h, apm) = if hour < 12 then (hour, "AM") else (hour - 12, "PM")
|
let (h, apm) = if hour < 12 then (hour, "AM") else (hour - 12, "PM")
|
||||||
in (show h) ++ ":" ++ (showLeadingZero minute) ++ " " ++ apm
|
in (show h) ++ ":" ++ (showLeadingZero minute) ++ " " ++ apm
|
||||||
|
|
||||||
jqueryDayTimeFieldProfile :: YesodJquery y => FieldProfile sub y UTCTime
|
|
||||||
jqueryDayTimeFieldProfile = FieldProfile
|
jqueryDayTimeFieldProfile = FieldProfile
|
||||||
{ fpParse = parseUTCTime . unpack
|
{ fpParse = parseUTCTime . unpack
|
||||||
, fpRender = pack . jqueryDayTimeUTCTime
|
, fpRender = pack . jqueryDayTimeUTCTime
|
||||||
@ -172,24 +154,12 @@ parseUTCTime s =
|
|||||||
ifRight (parseTime timeS)
|
ifRight (parseTime timeS)
|
||||||
(UTCTime date . timeOfDayToTime)
|
(UTCTime date . timeOfDayToTime)
|
||||||
|
|
||||||
jqueryAutocompleteField
|
|
||||||
:: (IsForm f, FormType f ~ Text, YesodJquery (FormMaster f))
|
|
||||||
=> Route (FormMaster f)
|
|
||||||
-> FormFieldSettings
|
|
||||||
-> Maybe (FormType f)
|
|
||||||
-> f
|
|
||||||
jqueryAutocompleteField = requiredFieldHelper . jqueryAutocompleteFieldProfile
|
jqueryAutocompleteField = requiredFieldHelper . jqueryAutocompleteFieldProfile
|
||||||
|
|
||||||
maybeJqueryAutocompleteField
|
|
||||||
:: (IsForm f, FormType f ~ Maybe Text, YesodJquery (FormMaster f))
|
|
||||||
=> Route (FormMaster f)
|
|
||||||
-> FormFieldSettings
|
|
||||||
-> Maybe (FormType f)
|
|
||||||
-> f
|
|
||||||
maybeJqueryAutocompleteField src =
|
maybeJqueryAutocompleteField src =
|
||||||
optionalFieldHelper $ jqueryAutocompleteFieldProfile src
|
optionalFieldHelper $ jqueryAutocompleteFieldProfile src
|
||||||
|
|
||||||
jqueryAutocompleteFieldProfile :: YesodJquery y => Route y -> FieldProfile sub y Text
|
jqueryAutocompleteFieldProfile :: YesodJquery master => Route master -> FieldProfile (GWidget sub master ()) Text
|
||||||
jqueryAutocompleteFieldProfile src = FieldProfile
|
jqueryAutocompleteFieldProfile src = FieldProfile
|
||||||
{ fpParse = Right
|
{ fpParse = Right
|
||||||
, fpRender = id
|
, fpRender = id
|
||||||
@ -205,7 +175,6 @@ $(function(){$("##{theId}").autocomplete({source:"@{src}",minLength:2})});
|
|||||||
|]
|
|]
|
||||||
}
|
}
|
||||||
|
|
||||||
addScript' :: (y -> Either (Route y) Text) -> GWidget sub y ()
|
|
||||||
addScript' f = do
|
addScript' f = do
|
||||||
y <- lift getYesod
|
y <- lift getYesod
|
||||||
addScriptEither $ f y
|
addScriptEither $ f y
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE CPP #-}
|
{-# LANGUAGE CPP #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE NoMonomorphismRestriction #-} -- FIXME remove
|
||||||
-- | Provide the user with a rich text editor.
|
-- | Provide the user with a rich text editor.
|
||||||
module Yesod.Form.Nic
|
module Yesod.Form.Nic
|
||||||
( YesodNic (..)
|
( YesodNic (..)
|
||||||
@ -26,16 +27,11 @@ class YesodNic a where
|
|||||||
urlNicEdit :: a -> Either (Route a) Text
|
urlNicEdit :: a -> Either (Route a) Text
|
||||||
urlNicEdit _ = Right "http://js.nicedit.com/nicEdit-latest.js"
|
urlNicEdit _ = Right "http://js.nicedit.com/nicEdit-latest.js"
|
||||||
|
|
||||||
nicHtmlField :: (IsForm f, FormType f ~ Html, YesodNic (FormMaster f))
|
|
||||||
=> FormFieldSettings -> Maybe Html -> f
|
|
||||||
nicHtmlField = requiredFieldHelper nicHtmlFieldProfile
|
nicHtmlField = requiredFieldHelper nicHtmlFieldProfile
|
||||||
|
|
||||||
maybeNicHtmlField
|
|
||||||
:: (IsForm f, FormType f ~ Maybe Html, YesodNic (FormMaster f))
|
|
||||||
=> FormFieldSettings -> Maybe (FormType f) -> f
|
|
||||||
maybeNicHtmlField = optionalFieldHelper nicHtmlFieldProfile
|
maybeNicHtmlField = optionalFieldHelper nicHtmlFieldProfile
|
||||||
|
|
||||||
nicHtmlFieldProfile :: YesodNic y => FieldProfile sub y Html
|
--nicHtmlFieldProfile :: YesodNic y => FieldProfile sub y Html
|
||||||
nicHtmlFieldProfile = FieldProfile
|
nicHtmlFieldProfile = FieldProfile
|
||||||
{ fpParse = Right . preEscapedString . sanitizeBalance . unpack -- FIXME
|
{ fpParse = Right . preEscapedString . sanitizeBalance . unpack -- FIXME
|
||||||
, fpRender = pack . renderHtml
|
, fpRender = pack . renderHtml
|
||||||
|
|||||||
@ -52,7 +52,7 @@ import Data.Text (Text, unpack, pack)
|
|||||||
#define JULIUS $julius
|
#define JULIUS $julius
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
intFieldProfile :: Integral i => FieldProfile sub y i
|
intFieldProfile :: (Monad monad, Integral i) => FieldProfile (GGWidget master monad ()) i
|
||||||
intFieldProfile = FieldProfile
|
intFieldProfile = FieldProfile
|
||||||
{ fpParse = maybe (Left "Invalid integer") Right . readMayI . unpack -- FIXME Data.Text.Read
|
{ fpParse = maybe (Left "Invalid integer") Right . readMayI . unpack -- FIXME Data.Text.Read
|
||||||
, fpRender = pack . showI
|
, fpRender = pack . showI
|
||||||
@ -67,7 +67,7 @@ intFieldProfile = FieldProfile
|
|||||||
(x, _):_ -> Just $ fromInteger x
|
(x, _):_ -> Just $ fromInteger x
|
||||||
[] -> Nothing
|
[] -> Nothing
|
||||||
|
|
||||||
doubleFieldProfile :: FieldProfile sub y Double
|
doubleFieldProfile :: Monad monad => FieldProfile (GGWidget master monad ()) Double
|
||||||
doubleFieldProfile = FieldProfile
|
doubleFieldProfile = FieldProfile
|
||||||
{ fpParse = maybe (Left "Invalid number") Right . readMay . unpack -- FIXME use Data.Text.Read
|
{ fpParse = maybe (Left "Invalid number") Right . readMay . unpack -- FIXME use Data.Text.Read
|
||||||
, fpRender = pack . show
|
, fpRender = pack . show
|
||||||
@ -77,7 +77,7 @@ doubleFieldProfile = FieldProfile
|
|||||||
|]
|
|]
|
||||||
}
|
}
|
||||||
|
|
||||||
dayFieldProfile :: FieldProfile sub y Day
|
dayFieldProfile :: Monad monad => FieldProfile (GGWidget master monad ()) Day
|
||||||
dayFieldProfile = FieldProfile
|
dayFieldProfile = FieldProfile
|
||||||
{ fpParse = parseDate . unpack
|
{ fpParse = parseDate . unpack
|
||||||
, fpRender = pack . show
|
, fpRender = pack . show
|
||||||
@ -87,7 +87,7 @@ dayFieldProfile = FieldProfile
|
|||||||
|]
|
|]
|
||||||
}
|
}
|
||||||
|
|
||||||
timeFieldProfile :: FieldProfile sub y TimeOfDay
|
timeFieldProfile :: Monad monad => FieldProfile (GGWidget master monad ()) TimeOfDay
|
||||||
timeFieldProfile = FieldProfile
|
timeFieldProfile = FieldProfile
|
||||||
{ fpParse = parseTime . unpack
|
{ fpParse = parseTime . unpack
|
||||||
, fpRender = pack . show . roundFullSeconds
|
, fpRender = pack . show . roundFullSeconds
|
||||||
@ -102,7 +102,7 @@ timeFieldProfile = FieldProfile
|
|||||||
where
|
where
|
||||||
fullSec = fromInteger $ floor $ todSec tod
|
fullSec = fromInteger $ floor $ todSec tod
|
||||||
|
|
||||||
htmlFieldProfile :: FieldProfile sub y Html
|
htmlFieldProfile :: Monad monad => FieldProfile (GGWidget master monad ()) Html
|
||||||
htmlFieldProfile = FieldProfile
|
htmlFieldProfile = FieldProfile
|
||||||
{ fpParse = Right . preEscapedString . sanitizeBalance . unpack -- FIXME make changes to xss-sanitize
|
{ fpParse = Right . preEscapedString . sanitizeBalance . unpack -- FIXME make changes to xss-sanitize
|
||||||
, fpRender = pack . renderHtml
|
, fpRender = pack . renderHtml
|
||||||
@ -130,7 +130,7 @@ instance ToHtml Textarea where
|
|||||||
writeHtmlEscapedChar '\n' = writeByteString "<br>"
|
writeHtmlEscapedChar '\n' = writeByteString "<br>"
|
||||||
writeHtmlEscapedChar c = B.writeHtmlEscapedChar c
|
writeHtmlEscapedChar c = B.writeHtmlEscapedChar c
|
||||||
|
|
||||||
textareaFieldProfile :: FieldProfile sub y Textarea
|
textareaFieldProfile :: Monad monad => FieldProfile (GGWidget master monad ()) Textarea
|
||||||
textareaFieldProfile = FieldProfile
|
textareaFieldProfile = FieldProfile
|
||||||
{ fpParse = Right . Textarea
|
{ fpParse = Right . Textarea
|
||||||
, fpRender = unTextarea
|
, fpRender = unTextarea
|
||||||
@ -140,7 +140,7 @@ textareaFieldProfile = FieldProfile
|
|||||||
|]
|
|]
|
||||||
}
|
}
|
||||||
|
|
||||||
hiddenFieldProfile :: FieldProfile sub y Text
|
hiddenFieldProfile :: Monad monad => FieldProfile (GGWidget master monad ()) Text
|
||||||
hiddenFieldProfile = FieldProfile
|
hiddenFieldProfile = FieldProfile
|
||||||
{ fpParse = Right
|
{ fpParse = Right
|
||||||
, fpRender = id
|
, fpRender = id
|
||||||
@ -150,7 +150,7 @@ hiddenFieldProfile = FieldProfile
|
|||||||
|]
|
|]
|
||||||
}
|
}
|
||||||
|
|
||||||
stringFieldProfile :: FieldProfile sub y Text
|
stringFieldProfile :: Monad monad => FieldProfile (GGWidget master monad ()) Text
|
||||||
stringFieldProfile = FieldProfile
|
stringFieldProfile = FieldProfile
|
||||||
{ fpParse = Right
|
{ fpParse = Right
|
||||||
, fpRender = id
|
, fpRender = id
|
||||||
@ -160,7 +160,7 @@ stringFieldProfile = FieldProfile
|
|||||||
|]
|
|]
|
||||||
}
|
}
|
||||||
|
|
||||||
passwordFieldProfile :: FieldProfile s m Text
|
passwordFieldProfile :: Monad monad => FieldProfile (GGWidget master monad ()) Text
|
||||||
passwordFieldProfile = FieldProfile
|
passwordFieldProfile = FieldProfile
|
||||||
{ fpParse = Right
|
{ fpParse = Right
|
||||||
, fpRender = id
|
, fpRender = id
|
||||||
@ -208,7 +208,7 @@ parseTimeHelper (h1, h2, m1, m2, s1, s2)
|
|||||||
m = read [m1, m2]
|
m = read [m1, m2]
|
||||||
s = fromInteger $ read [s1, s2]
|
s = fromInteger $ read [s1, s2]
|
||||||
|
|
||||||
emailFieldProfile :: FieldProfile s y Text
|
emailFieldProfile :: Monad monad => FieldProfile (GGWidget master monad ()) Text
|
||||||
emailFieldProfile = FieldProfile
|
emailFieldProfile = FieldProfile
|
||||||
{ fpParse = \s -> if Email.isValid (unpack s)
|
{ fpParse = \s -> if Email.isValid (unpack s)
|
||||||
then Right s
|
then Right s
|
||||||
@ -221,7 +221,7 @@ emailFieldProfile = FieldProfile
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AutoFocus = Bool
|
type AutoFocus = Bool
|
||||||
searchFieldProfile :: AutoFocus -> FieldProfile s y Text
|
searchFieldProfile :: Monad monad => AutoFocus -> FieldProfile (GGWidget master monad ()) Text
|
||||||
searchFieldProfile autoFocus = FieldProfile
|
searchFieldProfile autoFocus = FieldProfile
|
||||||
{ fpParse = Right
|
{ fpParse = Right
|
||||||
, fpRender = id
|
, fpRender = id
|
||||||
@ -238,14 +238,14 @@ searchFieldProfile autoFocus = FieldProfile
|
|||||||
|]
|
|]
|
||||||
}
|
}
|
||||||
|
|
||||||
urlFieldProfile :: FieldProfile s y Text
|
urlFieldProfile :: Monad monad => FieldProfile (GGWidget master monad ()) Text
|
||||||
urlFieldProfile = FieldProfile
|
urlFieldProfile = FieldProfile
|
||||||
{ fpParse = \s -> case parseURI $ unpack s of
|
{ fpParse = \s -> case parseURI $ unpack s of
|
||||||
Nothing -> Left "Invalid URL"
|
Nothing -> Left "Invalid URL"
|
||||||
Just _ -> Right s
|
Just _ -> Right s
|
||||||
, fpRender = id
|
, fpRender = id
|
||||||
, fpWidget = \theId name val isReq -> addHamlet
|
, fpWidget = \theId name val isReq -> addHtml
|
||||||
[HAMLET|\
|
[HAMLET|
|
||||||
<input id="#{theId}" name="#{name}" type="url" :isReq:required="" value="#{val}">
|
<input ##{theId} name=#{name} type=url :isReq:required value=#{val}>
|
||||||
|]
|
|]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
name: yesod-form
|
name: yesod-form
|
||||||
version: 0.1.0.1
|
version: 0.2.0
|
||||||
license: BSD3
|
license: BSD3
|
||||||
license-file: LICENSE
|
license-file: LICENSE
|
||||||
author: Michael Snoyman <michael@snoyman.com>
|
author: Michael Snoyman <michael@snoyman.com>
|
||||||
@ -36,7 +36,7 @@ library
|
|||||||
Yesod.Form.Jquery
|
Yesod.Form.Jquery
|
||||||
Yesod.Form.Nic
|
Yesod.Form.Nic
|
||||||
Yesod.Form.Profiles
|
Yesod.Form.Profiles
|
||||||
Yesod.Helpers.Crud
|
-- FIXME Yesod.Helpers.Crud
|
||||||
ghc-options: -Wall
|
ghc-options: -Wall
|
||||||
|
|
||||||
source-repository head
|
source-repository head
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user