Minor rearranging and renaming

This commit is contained in:
Michael Snoyman 2010-08-13 16:24:51 +03:00
parent 2a19d1a4e8
commit c7ac7f191c
8 changed files with 146 additions and 135 deletions

View File

@ -8,7 +8,13 @@ module Yesod.Form
( -- * Data types ( -- * Data types
GForm GForm
, FormResult (..) , FormResult (..)
, Enctype (..) , Enctype
-- * Type synonyms
, Form
, Formlet
, FormField
, FormletField
, FormInput
-- * Unwrapping functions -- * Unwrapping functions
, runFormGet , runFormGet
, runFormPost , runFormPost

View File

@ -8,6 +8,7 @@ module Yesod.Form.Class
import Text.Hamlet import Text.Hamlet
import Yesod.Form.Fields import Yesod.Form.Fields
import Yesod.Form.Core
import Data.Int (Int64) import Data.Int (Int64)
import Data.Time (Day, TimeOfDay) import Data.Time (Day, TimeOfDay)

View File

@ -1,3 +1,4 @@
{-# LANGUAGE OverloadedStrings #-}
module Yesod.Form.Core module Yesod.Form.Core
( FormResult (..) ( FormResult (..)
, GForm (..) , GForm (..)
@ -8,14 +9,32 @@ module Yesod.Form.Core
, FileEnv , FileEnv
, Enctype (..) , Enctype (..)
, Ints (..) , Ints (..)
, requiredFieldHelper
, optionalFieldHelper
, fieldsToInput
, mapFormXml
-- * Data types
, FieldInfo (..)
, FormFieldSettings (..)
, FieldProfile (..)
-- * Type synonyms
, Form
, Formlet
, FormField
, FormletField
, FormInput
) where ) where
import Control.Monad.Trans.State import Control.Monad.Trans.State
import Yesod.Handler import Yesod.Handler
import Yesod.Widget
import Data.Monoid (Monoid (..)) import Data.Monoid (Monoid (..))
import Control.Applicative import Control.Applicative
import Yesod.Request import Yesod.Request
import Control.Monad (liftM) import Control.Monad (liftM)
import Text.Hamlet
import Data.String
import Control.Monad (join)
-- | A form can produce three different results: there was no data available, -- | A form can produce three different results: there was no data available,
-- the data was invalid, or there was a successful parse. -- the data was invalid, or there was a successful parse.
@ -44,9 +63,10 @@ instance Monoid m => Monoid (FormResult m) where
-- | The encoding type required by a form. The 'Show' instance produces values -- | The encoding type required by a form. The 'Show' 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
instance Show Enctype where deriving (Eq, Enum, Bounded)
show UrlEncoded = "application/x-www-form-urlencoded" instance ToHtml Enctype where
show Multipart = "multipart/form-data" toHtml UrlEncoded = unsafeByteString "application/x-www-form-urlencoded"
toHtml Multipart = unsafeByteString "multipart/form-data"
instance Monoid Enctype where instance Monoid Enctype where
mempty = UrlEncoded mempty = UrlEncoded
mappend UrlEncoded UrlEncoded = UrlEncoded mappend UrlEncoded UrlEncoded = UrlEncoded
@ -101,3 +121,112 @@ instance Monoid xml => Applicative (GForm sub url xml) where
(f1, f2, f3) <- f env fe (f1, f2, f3) <- f env fe
(g1, g2, g3) <- g env fe (g1, g2, g3) <- g env fe
return (f1 <*> g1, f2 `mappend` g2, f3 `mappend` g3) return (f1 <*> g1, f2 `mappend` g2, f3 `mappend` g3)
-- | Create a required field (ie, one that cannot be blank) from a
-- 'FieldProfile'.ngs
requiredFieldHelper :: FieldProfile sub y a -> FormFieldSettings
-> Maybe a -> FormField sub y a
requiredFieldHelper (FieldProfile parse render mkXml w) ffs orig =
GForm $ \env _ -> do
let (FormFieldSettings label tooltip theId' name') = ffs
name <- maybe newFormIdent return name'
theId <- maybe newFormIdent return theId'
let (res, val) =
if null env
then (FormMissing, maybe "" render orig)
else case lookup name env of
Nothing -> (FormMissing, "")
Just "" -> (FormFailure ["Value is required"], "")
Just x ->
case parse x of
Left e -> (FormFailure [e], x)
Right y -> (FormSuccess y, x)
let fi = FieldInfo
{ fiLabel = label
, fiTooltip = tooltip
, fiIdent = theId
, fiName = name
, fiInput = w theId >> addBody (mkXml theId name val True)
, fiErrors = case res of
FormFailure [x] -> Just $ string x
_ -> Nothing
}
return (res, [fi], UrlEncoded)
-- | Create an optional field (ie, one that can be blank) from a
-- 'FieldProfile'.
optionalFieldHelper :: FieldProfile sub y a -> FormFieldSettings
-> FormletField sub y (Maybe a)
optionalFieldHelper (FieldProfile parse render mkXml w) ffs orig' =
GForm $ \env _ -> do
let (FormFieldSettings label tooltip theId' name') = ffs
let orig = join orig'
name <- maybe newFormIdent return name'
theId <- maybe newFormIdent return theId'
let (res, val) =
if null env
then (FormSuccess Nothing, maybe "" render orig)
else case lookup name env of
Nothing -> (FormSuccess Nothing, "")
Just "" -> (FormSuccess Nothing, "")
Just x ->
case parse x of
Left e -> (FormFailure [e], x)
Right y -> (FormSuccess $ Just y, x)
let fi = FieldInfo
{ fiLabel = label
, fiTooltip = tooltip
, fiIdent = theId
, fiName = name
, fiInput = w theId >> addBody (mkXml theId name val False)
, fiErrors = case res of
FormFailure [x] -> Just $ string x
_ -> Nothing
}
return (res, [fi], UrlEncoded)
fieldsToInput :: [FieldInfo sub y] -> [GWidget sub y ()]
fieldsToInput = map fiInput
-- | Convert the XML in a 'GForm'.
mapFormXml :: (xml1 -> xml2) -> GForm s y xml1 a -> GForm s y xml2 a
mapFormXml f (GForm g) = GForm $ \e fe -> do
(res, xml, enc) <- g e fe
return (res, f xml, enc)
-- | Using this as the intermediate XML representation for fields allows us to
-- write generic field functions and then different functions for producing
-- actual HTML. See, for example, 'fieldsToTable' and 'fieldsToPlain'.
data FieldInfo sub y = FieldInfo
{ fiLabel :: Html
, fiTooltip :: Html
, fiIdent :: String
, fiName :: String
, fiInput :: GWidget sub y ()
, fiErrors :: Maybe Html
}
data FormFieldSettings = FormFieldSettings
{ ffsLabel :: Html
, ffsTooltip :: Html
, ffsId :: Maybe String
, ffsName :: Maybe String
}
instance IsString FormFieldSettings where
fromString s = FormFieldSettings (string s) mempty Nothing Nothing
-- | A generic definition of a form field that can be used for generating both
-- required and optional fields. See 'requiredFieldHelper and
-- 'optionalFieldHelper'.
data FieldProfile sub y a = FieldProfile
{ fpParse :: String -> Either String a
, fpRender :: a -> String
, fpHamlet :: String -> String -> String -> Bool -> Hamlet (Route y)
, fpWidget :: String -> 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 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 ()]

View File

@ -1,17 +1,8 @@
{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE QuasiQuotes #-}
module Yesod.Form.Fields module Yesod.Form.Fields
( -- * Type synonyms ( -- * Fields
Form
, Formlet
, FormField
, FormletField
, FormInput
-- * Data types
, FieldInfo (..)
, FormFieldSettings (..)
-- * Fields
-- ** Required -- ** Required
, stringField stringField
, textareaField , textareaField
, hiddenField , hiddenField
, intField , intField
@ -46,11 +37,6 @@ module Yesod.Form.Fields
-- ** Optional -- ** Optional
, maybeStringInput , maybeStringInput
, maybeDayInput , maybeDayInput
-- * Utils
, requiredFieldHelper
, optionalFieldHelper
, fieldsToInput
, mapFormXml
) where ) where
import Yesod.Form.Core import Yesod.Form.Core
@ -61,34 +47,6 @@ import Text.Hamlet
import Data.Monoid import Data.Monoid
import Control.Monad (join) import Control.Monad (join)
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
import Data.String
data FormFieldSettings = FormFieldSettings
{ ffsLabel :: Html
, ffsTooltip :: Html
, ffsId :: Maybe String
, ffsName :: Maybe String
}
instance IsString FormFieldSettings where
fromString s = FormFieldSettings (string s) mempty Nothing Nothing
-- | Using this as the intermediate XML representation for fields allows us to
-- write generic field functions and then different functions for producing
-- actual HTML. See, for example, 'fieldsToTable' and 'fieldsToPlain'.
data FieldInfo sub y = FieldInfo
{ fiLabel :: Html
, fiTooltip :: Html
, fiIdent :: String
, fiName :: String
, fiInput :: GWidget sub y ()
, fiErrors :: Maybe Html
}
type Form sub y = GForm sub y (GWidget sub y ())
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 ()]
stringField :: FormFieldSettings -> FormletField sub y String stringField :: FormFieldSettings -> FormletField sub y String
stringField = requiredFieldHelper stringFieldProfile stringField = requiredFieldHelper stringFieldProfile
@ -269,78 +227,6 @@ maybeDayInput n =
nameSettings :: String -> FormFieldSettings nameSettings :: String -> FormFieldSettings
nameSettings n = FormFieldSettings mempty mempty (Just n) (Just n) nameSettings n = FormFieldSettings mempty mempty (Just n) (Just n)
-- | Create a required field (ie, one that cannot be blank) from a
-- 'FieldProfile'.ngs
requiredFieldHelper :: FieldProfile sub y a -> FormFieldSettings
-> Maybe a -> FormField sub y a
requiredFieldHelper (FieldProfile parse render mkXml w) ffs orig =
GForm $ \env _ -> do
let (FormFieldSettings label tooltip theId' name') = ffs
name <- maybe newFormIdent return name'
theId <- maybe newFormIdent return theId'
let (res, val) =
if null env
then (FormMissing, maybe "" render orig)
else case lookup name env of
Nothing -> (FormMissing, "")
Just "" -> (FormFailure ["Value is required"], "")
Just x ->
case parse x of
Left e -> (FormFailure [e], x)
Right y -> (FormSuccess y, x)
let fi = FieldInfo
{ fiLabel = label
, fiTooltip = tooltip
, fiIdent = theId
, fiName = name
, fiInput = w theId >> addBody (mkXml theId name val True)
, fiErrors = case res of
FormFailure [x] -> Just $ string x
_ -> Nothing
}
return (res, [fi], UrlEncoded)
-- | Create an optional field (ie, one that can be blank) from a
-- 'FieldProfile'.
optionalFieldHelper :: FieldProfile sub y a -> FormFieldSettings
-> FormletField sub y (Maybe a)
optionalFieldHelper (FieldProfile parse render mkXml w) ffs orig' =
GForm $ \env _ -> do
let (FormFieldSettings label tooltip theId' name') = ffs
let orig = join orig'
name <- maybe newFormIdent return name'
theId <- maybe newFormIdent return theId'
let (res, val) =
if null env
then (FormSuccess Nothing, maybe "" render orig)
else case lookup name env of
Nothing -> (FormSuccess Nothing, "")
Just "" -> (FormSuccess Nothing, "")
Just x ->
case parse x of
Left e -> (FormFailure [e], x)
Right y -> (FormSuccess $ Just y, x)
let fi = FieldInfo
{ fiLabel = label
, fiTooltip = tooltip
, fiIdent = theId
, fiName = name
, fiInput = w theId >> addBody (mkXml theId name val False)
, fiErrors = case res of
FormFailure [x] -> Just $ string x
_ -> Nothing
}
return (res, [fi], UrlEncoded)
fieldsToInput :: [FieldInfo sub y] -> [GWidget sub y ()]
fieldsToInput = map fiInput
-- | Convert the XML in a 'GForm'.
mapFormXml :: (xml1 -> xml2) -> GForm s y xml1 a -> GForm s y xml2 a
mapFormXml f (GForm g) = GForm $ \e fe -> do
(res, xml, enc) <- g e fe
return (res, f xml, enc)
urlField :: FormFieldSettings -> FormletField sub y String urlField :: FormFieldSettings -> FormletField sub y String
urlField = requiredFieldHelper urlFieldProfile urlField = requiredFieldHelper urlFieldProfile

View File

@ -11,7 +11,7 @@ module Yesod.Form.Jquery
) where ) where
import Yesod.Handler import Yesod.Handler
import Yesod.Form import Yesod.Form.Core
import Yesod.Form.Profiles import Yesod.Form.Profiles
import Yesod.Widget import Yesod.Widget
import Data.Time (UTCTime (..), Day, TimeOfDay (..), timeOfDayToTime, import Data.Time (UTCTime (..), Day, TimeOfDay (..), timeOfDayToTime,

View File

@ -6,7 +6,7 @@ module Yesod.Form.Nic
) where ) where
import Yesod.Handler import Yesod.Handler
import Yesod.Form import Yesod.Form.Core
import Yesod.Form.Profiles import Yesod.Form.Profiles
import Yesod.Hamlet import Yesod.Hamlet
import Yesod.Widget import Yesod.Widget

View File

@ -15,24 +15,13 @@ module Yesod.Form.Profiles
, parseTime , parseTime
) where ) where
import Yesod.Widget import Yesod.Form.Core
import Yesod.Handler
import Text.Hamlet import Text.Hamlet
import Data.Time (Day, TimeOfDay(..)) import Data.Time (Day, TimeOfDay(..))
import qualified Data.ByteString.Lazy.UTF8 as U import qualified Data.ByteString.Lazy.UTF8 as U
import qualified Text.Email.Validate as Email import qualified Text.Email.Validate as Email
import Network.URI (parseURI) import Network.URI (parseURI)
-- | A generic definition of a form field that can be used for generating both
-- required and optional fields. See 'requiredFieldHelper and
-- 'optionalFieldHelper'.
data FieldProfile sub y a = FieldProfile
{ fpParse :: String -> Either String a
, fpRender :: a -> String
, fpHamlet :: String -> String -> String -> Bool -> Hamlet (Route y)
, fpWidget :: String -> GWidget sub y ()
}
intFieldProfile :: Integral i => FieldProfile sub y i intFieldProfile :: Integral i => FieldProfile sub y i
intFieldProfile = FieldProfile intFieldProfile = FieldProfile
{ fpParse = maybe (Left "Invalid integer") Right . readMayI { fpParse = maybe (Left "Invalid integer") Right . readMayI

View File

@ -160,7 +160,7 @@ crudHelper title me isPost = do
%p %p
%a!href=@toMaster.CrudListR@ Return to list %a!href=@toMaster.CrudListR@ Return to list
%h1 $title$ %h1 $title$
%form!method=post!enctype=$show.enctype$ %form!method=post!enctype=$enctype$
%table %table
^form^ ^form^
%tr %tr