diff --git a/Yesod/Form/Class.hs b/Yesod/Form/Class.hs index 2eaa137e..cdac8dc7 100644 --- a/Yesod/Form/Class.hs +++ b/Yesod/Form/Class.hs @@ -1,6 +1,7 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeSynonymInstances #-} +{-# LANGUAGE FlexibleContexts #-} module Yesod.Form.Class ( ToForm (..) , ToField (..) @@ -15,12 +16,13 @@ import Data.Int (Int64) import Data.Time (Day, TimeOfDay) import Data.Text (Text) import Yesod.Handler (GGHandler) +import Yesod.Message (RenderMessage) class ToForm a master monad where - toForm :: AForm ([FieldView (GGWidget master monad ())] -> [FieldView (GGWidget master monad ())]) monad a + toForm :: AForm ([FieldView (GGWidget master monad ())] -> [FieldView (GGWidget master monad ())]) master monad a class ToField a master monad where - toField :: FieldSettings -> Maybe a -> AForm ([FieldView (GGWidget master monad ())] -> [FieldView (GGWidget master monad ())]) monad a + toField :: RenderMessage master msg => FieldSettings msg -> Maybe a -> AForm ([FieldView (GGWidget master monad ())] -> [FieldView (GGWidget master monad ())]) master monad a {- FIXME instance ToFormField String y where @@ -29,44 +31,44 @@ instance ToFormField (Maybe String) y where toFormField = maybeStringField -} -instance Monad m => ToField Text master (GGHandler sub master m) where +instance (Monad m, RenderMessage master FormMessage) => ToField Text master (GGHandler sub master m) where toField = areq textField -instance Monad m => ToField (Maybe Text) master (GGHandler sub master m) where +instance (Monad m, RenderMessage master FormMessage) => ToField (Maybe Text) master (GGHandler sub master m) where toField = aopt textField -instance Monad m => ToField Int master (GGHandler sub master m) where +instance (Monad m, RenderMessage master FormMessage) => ToField Int master (GGHandler sub master m) where toField = areq intField -instance Monad m => ToField (Maybe Int) master (GGHandler sub master m) where +instance (Monad m, RenderMessage master FormMessage) => ToField (Maybe Int) master (GGHandler sub master m) where toField = aopt intField -instance Monad m => ToField Int64 master (GGHandler sub master m) where +instance (Monad m, RenderMessage master FormMessage) => ToField Int64 master (GGHandler sub master m) where toField = areq intField -instance Monad m => ToField (Maybe Int64) master (GGHandler sub master m) where +instance (Monad m, RenderMessage master FormMessage) => ToField (Maybe Int64) master (GGHandler sub master m) where toField = aopt intField -instance Monad m => ToField Double master (GGHandler sub master m) where +instance (Monad m, RenderMessage master FormMessage) => ToField Double master (GGHandler sub master m) where toField = areq doubleField -instance Monad m => ToField (Maybe Double) master (GGHandler sub master m) where +instance (Monad m, RenderMessage master FormMessage) => ToField (Maybe Double) master (GGHandler sub master m) where toField = aopt doubleField -instance Monad m => ToField Day master (GGHandler sub master m) where +instance (Monad m, RenderMessage master FormMessage) => ToField Day master (GGHandler sub master m) where toField = areq dayField -instance Monad m => ToField (Maybe Day) master (GGHandler sub master m) where +instance (Monad m, RenderMessage master FormMessage) => ToField (Maybe Day) master (GGHandler sub master m) where toField = aopt dayField -instance Monad m => ToField TimeOfDay master (GGHandler sub master m) where +instance (Monad m, RenderMessage master FormMessage) => ToField TimeOfDay master (GGHandler sub master m) where toField = areq timeField -instance Monad m => ToField (Maybe TimeOfDay) master (GGHandler sub master m) where +instance (Monad m, RenderMessage master FormMessage) => ToField (Maybe TimeOfDay) master (GGHandler sub master m) where toField = aopt timeField -instance Monad m => ToField Html master (GGHandler sub master m) where +instance (Monad m, RenderMessage master FormMessage) => ToField Html master (GGHandler sub master m) where toField = areq htmlField -instance Monad m => ToField (Maybe Html) master (GGHandler sub master m) where +instance (Monad m, RenderMessage master FormMessage) => ToField (Maybe Html) master (GGHandler sub master m) where toField = aopt htmlField -instance Monad m => ToField Textarea master (GGHandler sub master m) where +instance (Monad m, RenderMessage master FormMessage) => ToField Textarea master (GGHandler sub master m) where toField = areq textareaField -instance Monad m => ToField (Maybe Textarea) master (GGHandler sub master m) where +instance (Monad m, RenderMessage master FormMessage) => ToField (Maybe Textarea) master (GGHandler sub master m) where toField = aopt textareaField {- FIXME diff --git a/Yesod/Form/Fields.hs b/Yesod/Form/Fields.hs index 3a61091c..f73b5c43 100644 --- a/Yesod/Form/Fields.hs +++ b/Yesod/Form/Fields.hs @@ -3,7 +3,9 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE CPP #-} module Yesod.Form.Fields - ( textField + ( FormMessage (..) + , defaultFormMessage + , textField , passwordField , textareaField , hiddenField @@ -13,6 +15,7 @@ module Yesod.Form.Fields , htmlField , emailField , searchField + , selectField , AutoFocus , urlField , doubleField @@ -41,6 +44,8 @@ import Text.Blaze.Renderer.String (renderHtml) import qualified Data.ByteString as S import qualified Data.ByteString.Lazy as L import Data.Text (Text, unpack, pack) +import qualified Data.Text.Read +import Data.Monoid (mappend) #if __GLASGOW_HASKELL__ >= 700 #define WHAMLET whamlet @@ -54,9 +59,32 @@ import Data.Text (Text, unpack, pack) #define JULIUS $julius #endif -intField :: (Monad monad, Integral i) => Field (GGWidget master monad ()) i +data FormMessage = MsgInvalidInteger Text + | MsgInvalidNumber Text + | MsgInvalidEntry Text + | MsgInvalidUrl Text + | MsgInvalidEmail Text + | MsgInvalidTimeFormat + | MsgInvalidHour Text + | MsgInvalidMinute Text + | MsgInvalidSecond Text + | MsgInvalidDay + +defaultFormMessage :: FormMessage -> Text +defaultFormMessage (MsgInvalidInteger t) = "Invalid integer: " `mappend` t +defaultFormMessage (MsgInvalidNumber t) = "Invalid number: " `mappend` t +defaultFormMessage (MsgInvalidEntry t) = "Invalid entry: " `mappend` t +defaultFormMessage MsgInvalidTimeFormat = "Invalid time, must be in HH:MM[:SS] format" +defaultFormMessage MsgInvalidDay = "Invalid day, must be in YYYY-MM-DD format" +defaultFormMessage (MsgInvalidUrl t) = "Invalid URL: " `mappend` t +defaultFormMessage (MsgInvalidEmail t) = "Invalid e-mail address: " `mappend` t +defaultFormMessage (MsgInvalidHour t) = "Invalid hour: " `mappend` t +defaultFormMessage (MsgInvalidMinute t) = "Invalid minute: " `mappend` t +defaultFormMessage (MsgInvalidSecond t) = "Invalid second: " `mappend` t + +intField :: (Monad monad, Integral i) => Field (GGWidget master monad ()) FormMessage i intField = Field - { fieldParse = maybe (Left "Invalid integer") Right . readMayI . unpack -- FIXME Data.Text.Read + { fieldParse = \s -> maybe (Left $ MsgInvalidInteger s) Right . readMayI $ unpack s -- FIXME Data.Text.Read , fieldRender = pack . showI , fieldView = \theId name val isReq -> addHamlet [HAMLET|\ @@ -69,9 +97,9 @@ intField = Field (x, _):_ -> Just $ fromInteger x [] -> Nothing -doubleField :: Monad monad => Field (GGWidget master monad ()) Double +doubleField :: Monad monad => Field (GGWidget master monad ()) FormMessage Double doubleField = Field - { fieldParse = maybe (Left "Invalid number") Right . readMay . unpack -- FIXME use Data.Text.Read + { fieldParse = \s -> maybe (Left $ MsgInvalidNumber s) Right . readMay $ unpack s -- FIXME use Data.Text.Read , fieldRender = pack . show , fieldView = \theId name val isReq -> addHamlet [HAMLET|\ @@ -79,7 +107,7 @@ doubleField = Field |] } -dayField :: Monad monad => Field (GGWidget master monad ()) Day +dayField :: Monad monad => Field (GGWidget master monad ()) FormMessage Day dayField = Field { fieldParse = parseDate . unpack , fieldRender = pack . show @@ -89,7 +117,7 @@ dayField = Field |] } -timeField :: Monad monad => Field (GGWidget master monad ()) TimeOfDay +timeField :: Monad monad => Field (GGWidget master monad ()) FormMessage TimeOfDay timeField = Field { fieldParse = parseTime . unpack , fieldRender = pack . show . roundFullSeconds @@ -104,7 +132,7 @@ timeField = Field where fullSec = fromInteger $ floor $ todSec tod -htmlField :: Monad monad => Field (GGWidget master monad ()) Html +htmlField :: Monad monad => Field (GGWidget master monad ()) FormMessage Html htmlField = Field { fieldParse = Right . preEscapedString . sanitizeBalance . unpack -- FIXME make changes to xss-sanitize , fieldRender = pack . renderHtml @@ -132,7 +160,7 @@ instance ToHtml Textarea where writeHtmlEscapedChar '\n' = writeByteString "
" writeHtmlEscapedChar c = B.writeHtmlEscapedChar c -textareaField :: Monad monad => Field (GGWidget master monad ()) Textarea +textareaField :: Monad monad => Field (GGWidget master monad ()) FormMessage Textarea textareaField = Field { fieldParse = Right . Textarea , fieldRender = unTextarea @@ -142,7 +170,7 @@ textareaField = Field |] } -hiddenField :: Monad monad => Field (GGWidget master monad ()) Text +hiddenField :: Monad monad => Field (GGWidget master monad ()) FormMessage Text hiddenField = Field { fieldParse = Right , fieldRender = id @@ -152,7 +180,7 @@ hiddenField = Field |] } -textField :: Monad monad => Field (GGWidget master monad ()) Text +textField :: Monad monad => Field (GGWidget master monad ()) FormMessage Text textField = Field { fieldParse = Right , fieldRender = id @@ -162,7 +190,7 @@ textField = Field |] } -passwordField :: Monad monad => Field (GGWidget master monad ()) Text +passwordField :: Monad monad => Field (GGWidget master monad ()) FormMessage Text passwordField = Field { fieldParse = Right , fieldRender = id @@ -177,8 +205,8 @@ readMay s = case reads s of (x, _):_ -> Just x [] -> Nothing -parseDate :: String -> Either Text Day -parseDate = maybe (Left "Invalid day, must be in YYYY-MM-DD format") Right +parseDate :: String -> Either FormMessage Day +parseDate = maybe (Left MsgInvalidDay) Right . readMay . replace '/' '-' -- | Replaces all instances of a value in a list by another value. @@ -186,7 +214,7 @@ parseDate = maybe (Left "Invalid day, must be in YYYY-MM-DD format") Right replace :: Eq a => a -> a -> [a] -> [a] replace x y = map (\z -> if z == x then y else z) -parseTime :: String -> Either Text TimeOfDay +parseTime :: String -> Either FormMessage TimeOfDay parseTime (h2:':':m1:m2:[]) = parseTimeHelper ('0', h2, m1, m2, '0', '0') parseTime (h1:h2:':':m1:m2:[]) = parseTimeHelper (h1, h2, m1, m2, '0', '0') parseTime (h1:h2:':':m1:m2:' ':'A':'M':[]) = @@ -196,25 +224,25 @@ parseTime (h1:h2:':':m1:m2:' ':'P':'M':[]) = in parseTimeHelper (h1', h2', m1, m2, '0', '0') parseTime (h1:h2:':':m1:m2:':':s1:s2:[]) = parseTimeHelper (h1, h2, m1, m2, s1, s2) -parseTime _ = Left "Invalid time, must be in HH:MM[:SS] format" +parseTime _ = Left MsgInvalidTimeFormat parseTimeHelper :: (Char, Char, Char, Char, Char, Char) - -> Either Text TimeOfDay + -> Either FormMessage TimeOfDay parseTimeHelper (h1, h2, m1, m2, s1, s2) - | h < 0 || h > 23 = Left $ pack $ "Invalid hour: " ++ show h - | m < 0 || m > 59 = Left $ pack $ "Invalid minute: " ++ show m - | s < 0 || s > 59 = Left $ pack $ "Invalid second: " ++ show s + | h < 0 || h > 23 = Left $ MsgInvalidHour $ pack [h1, h2] + | m < 0 || m > 59 = Left $ MsgInvalidMinute $ pack [m1, m2] + | s < 0 || s > 59 = Left $ MsgInvalidSecond $ pack [s1, s2] | otherwise = Right $ TimeOfDay h m s where - h = read [h1, h2] + h = read [h1, h2] -- FIXME isn't this a really bad idea? m = read [m1, m2] s = fromInteger $ read [s1, s2] -emailField :: Monad monad => Field (GGWidget master monad ()) Text +emailField :: Monad monad => Field (GGWidget master monad ()) FormMessage Text emailField = Field { fieldParse = \s -> if Email.isValid (unpack s) then Right s - else Left "Invalid e-mail address" + else Left $ MsgInvalidEmail s , fieldRender = id , fieldView = \theId name val isReq -> addHamlet [HAMLET|\ @@ -223,7 +251,7 @@ emailField = Field } type AutoFocus = Bool -searchField :: Monad monad => AutoFocus -> Field (GGWidget master monad ()) Text +searchField :: Monad monad => AutoFocus -> Field (GGWidget master monad ()) FormMessage Text searchField autoFocus = Field { fieldParse = Right , fieldRender = id @@ -240,10 +268,10 @@ searchField autoFocus = Field |] } -urlField :: Monad monad => Field (GGWidget master monad ()) Text +urlField :: Monad monad => Field (GGWidget master monad ()) FormMessage Text urlField = Field { fieldParse = \s -> case parseURI $ unpack s of - Nothing -> Left "Invalid URL" + Nothing -> Left $ MsgInvalidUrl s Just _ -> Right s , fieldRender = id , fieldView = \theId name val isReq -> addHtml @@ -251,3 +279,25 @@ urlField = Field |] } + +selectField :: (Eq a, Monad monad) => [(Text, a)] -> Field (GGWidget master monad ()) FormMessage a +selectField opts = Field -- FIXME won't work for optional yet + { fieldParse = \s -> + case Data.Text.Read.decimal s of + Right (a, "") -> + case lookup a pairs of + Nothing -> Left $ MsgInvalidEntry s + Just x -> Right $ snd x + _ -> Left $ MsgInvalidNumber s + , fieldRender = \a -> maybe "" (pack . show) $ lookup a rpairs + , fieldView = \theId name val isReq -> [WHAMLET| +|] @@ -168,14 +185,16 @@ runFormGet form = do case lookup key gets of Nothing -> Nothing Just _ -> Just (gets, []) - runFormGeneric (form fragment) env + langs <- languages + m <- getYesod + runFormGeneric (form fragment) m langs env -type FormRender master m a = - AForm ([FieldView (GGWidget master m ())] -> [FieldView (GGWidget master m ())]) m a +type FormRender master msg m a = + AForm ([FieldView (GGWidget master m ())] -> [FieldView (GGWidget master m ())]) msg m a -> Html - -> Form m (FormResult a, GGWidget master m ()) + -> Form msg m (FormResult a, GGWidget master m ()) -renderTable, renderDivs :: Monad m => FormRender master m a +renderTable, renderDivs :: Monad m => FormRender master msg m a renderTable aform fragment = do (res, views') <- aFormToForm aform let views = views' [] diff --git a/Yesod/Form/Input.hs b/Yesod/Form/Input.hs index f790d8b6..0fc34c5c 100644 --- a/Yesod/Form/Input.hs +++ b/Yesod/Form/Input.hs @@ -10,47 +10,52 @@ module Yesod.Form.Input import Yesod.Form.Types import Data.Text (Text, append) import Control.Applicative (Applicative (..)) -import Yesod.Handler (GHandler, GGHandler, invalidArgs, runRequestBody, getRequest) -import Yesod.Request (reqGetParams) +import Yesod.Handler (GHandler, GGHandler, invalidArgs, runRequestBody, getRequest, getYesod) +import Yesod.Request (reqGetParams, languages) import Data.Maybe (fromMaybe) import Control.Monad (liftM) import Yesod.Widget (GWidget) +import Yesod.Message (RenderMessage (..)) type DText = [Text] -> [Text] -newtype FormInput a = FormInput { unFormInput :: Env -> Either DText a } -instance Functor FormInput where - fmap a (FormInput f) = FormInput $ \e -> either Left (Right . a) $ f e -instance Applicative FormInput where - pure = FormInput . const . Right - (FormInput f) <*> (FormInput x) = FormInput $ \e -> - case (f e, x e) of +newtype FormInput master a = FormInput { unFormInput :: master -> [Text] -> Env -> Either DText a } +instance Functor (FormInput master) where + fmap a (FormInput f) = FormInput $ \c d e -> either Left (Right . a) $ f c d e +instance Applicative (FormInput master) where + pure = FormInput . const . const . const . Right + (FormInput f) <*> (FormInput x) = FormInput $ \c d e -> + case (f c d e, x c d e) of (Left a, Left b) -> Left $ a . b (Left a, _) -> Left a (_, Left b) -> Left b (Right a, Right b) -> Right $ a b -ireq :: Field (GWidget sub master ()) a -> Text -> FormInput a -ireq field name = FormInput $ \env -> +ireq :: RenderMessage master msg => Field (GWidget sub master ()) msg a -> Text -> FormInput master a +ireq field name = FormInput $ \m l env -> case lookup name env of Nothing -> Left $ (:) $ append "Input not found: " name -- TRANS - Just x -> either (Left . (:)) Right $ fieldParse field x + Just x -> either (Left . (:) . renderMessage m l) Right $ fieldParse field x -iopt :: Field (GWidget sub master ()) a -> Text -> FormInput (Maybe a) -iopt field name = FormInput $ \env -> +iopt :: RenderMessage master msg => Field (GWidget sub master ()) msg a -> Text -> FormInput master (Maybe a) +iopt field name = FormInput $ \m l env -> case fromMaybe "" $ lookup name env of "" -> Right Nothing - x -> either (Left . (:)) (Right . Just) $ fieldParse field x + x -> either (Left . (:) . renderMessage m l) (Right . Just) $ fieldParse field x -runInputGet :: Monad monad => FormInput a -> GGHandler sub master monad a +runInputGet :: Monad monad => FormInput master a -> GGHandler sub master monad a runInputGet (FormInput f) = do env <- liftM reqGetParams getRequest - case f env of + m <- getYesod + l <- languages + case f m l env of Left errs -> invalidArgs $ errs [] Right x -> return x -runInputPost :: FormInput a -> GHandler sub master a +runInputPost :: FormInput master a -> GHandler sub master a runInputPost (FormInput f) = do env <- liftM fst runRequestBody - case f env of + m <- getYesod + l <- languages + case f m l env of Left errs -> invalidArgs $ errs [] Right x -> return x diff --git a/Yesod/Form/Jquery.hs b/Yesod/Form/Jquery.hs index c8c1a6f0..3e169a76 100644 --- a/Yesod/Form/Jquery.hs +++ b/Yesod/Form/Jquery.hs @@ -63,10 +63,10 @@ class YesodJquery a where urlJqueryUiDateTimePicker :: a -> Either (Route a) Text urlJqueryUiDateTimePicker _ = Right "http://github.com/gregwebs/jquery.ui.datetimepicker/raw/master/jquery.ui.datetimepicker.js" -jqueryDayField :: (YesodJquery master) => JqueryDaySettings -> Field (GWidget sub master ()) Day +jqueryDayField :: (YesodJquery master) => JqueryDaySettings -> Field (GWidget sub master ()) FormMessage Day jqueryDayField jds = Field { fieldParse = maybe - (Left "Invalid day, must be in YYYY-MM-DD format") + (Left MsgInvalidDay) Right . readMay . unpack @@ -118,7 +118,7 @@ jqueryDayTimeUTCTime (UTCTime day utcTime) = let (h, apm) = if hour < 12 then (hour, "AM") else (hour - 12, "PM") in (show h) ++ ":" ++ (showLeadingZero minute) ++ " " ++ apm -jqueryDayTimeField :: YesodJquery master => Field (GWidget sub master ()) UTCTime +jqueryDayTimeField :: YesodJquery master => Field (GWidget sub master ()) FormMessage UTCTime jqueryDayTimeField = Field { fieldParse = parseUTCTime . unpack , fieldRender = pack . jqueryDayTimeUTCTime @@ -135,7 +135,7 @@ $(function(){$("##{theId}").datetimepicker({dateFormat : "yyyy/mm/dd h:MM TT"})} |] } -parseUTCTime :: String -> Either Text UTCTime +parseUTCTime :: String -> Either FormMessage UTCTime parseUTCTime s = let (dateS, timeS) = break isSpace (dropWhile isSpace s) dateE = parseDate dateS @@ -145,7 +145,7 @@ parseUTCTime s = ifRight (parseTime timeS) (UTCTime date . timeOfDayToTime) -jqueryAutocompleteField :: YesodJquery master => Route master -> Field (GWidget sub master ()) Text +jqueryAutocompleteField :: YesodJquery master => Route master -> Field (GWidget sub master ()) FormMessage Text jqueryAutocompleteField src = Field { fieldParse = Right , fieldRender = id diff --git a/Yesod/Form/Nic.hs b/Yesod/Form/Nic.hs index e98428b7..15554234 100644 --- a/Yesod/Form/Nic.hs +++ b/Yesod/Form/Nic.hs @@ -26,7 +26,7 @@ class YesodNic a where urlNicEdit :: a -> Either (Route a) Text urlNicEdit _ = Right "http://js.nicedit.com/nicEdit-latest.js" -nicHtmlField :: YesodNic master => Field (GWidget sub master ()) Html +nicHtmlField :: YesodNic master => Field (GWidget sub master ()) msg Html nicHtmlField = Field { fieldParse = Right . preEscapedString . sanitizeBalance . unpack -- FIXME , fieldRender = pack . renderHtml diff --git a/Yesod/Form/Types.hs b/Yesod/Form/Types.hs index ad0c5a58..389e8eaa 100644 --- a/Yesod/Form/Types.hs +++ b/Yesod/Form/Types.hs @@ -69,38 +69,38 @@ instance Show Ints where type Env = [(Text, Text)] -- FIXME use a Map type FileEnv = [(Text, FileInfo)] -type Form m a = RWST (Maybe (Env, FileEnv)) Enctype Ints m a +type Form master m a = RWST (Maybe (Env, FileEnv), master, [Text]) Enctype Ints m a -newtype AForm xml m a = AForm - { unAForm :: Maybe (Env, FileEnv) -> Ints -> m (FormResult a, xml, Ints, Enctype) +newtype AForm xml master m a = AForm + { unAForm :: (master, [Text]) -> Maybe (Env, FileEnv) -> Ints -> m (FormResult a, xml, Ints, Enctype) } -instance Monad m => Functor (AForm xml m) where +instance Monad m => Functor (AForm xml msg m) where fmap f (AForm a) = - AForm $ \x y -> liftM go $ a x y + AForm $ \x y z -> liftM go $ a x y z where go (w, x, y, z) = (fmap f w, x, y, z) -instance (Monad m, Monoid xml) => Applicative (AForm xml m) where - pure x = AForm $ const $ \ints -> return (FormSuccess x, mempty, ints, mempty) - (AForm f) <*> (AForm g) = AForm $ \env ints -> do - (a, b, ints', c) <- f env ints - (x, y, ints'', z) <- g env ints' +instance (Monad m, Monoid xml) => Applicative (AForm xml msg m) where + pure x = AForm $ const $ const $ \ints -> return (FormSuccess x, mempty, ints, mempty) + (AForm f) <*> (AForm g) = AForm $ \mr env ints -> do + (a, b, ints', c) <- f mr env ints + (x, y, ints'', z) <- g mr env ints' return (a <*> x, b `mappend` y, ints'', c `mappend` z) -instance (Monad m, Monoid xml, Monoid a) => Monoid (AForm xml m a) where +instance (Monad m, Monoid xml, Monoid a) => Monoid (AForm xml msg m a) where mempty = pure mempty mappend a b = mappend <$> a <*> b -instance Monoid xml => MonadTrans (AForm xml) where - lift mx = AForm $ const $ \ints -> do +instance Monoid xml => MonadTrans (AForm xml msg) where + lift mx = AForm $ const $ const $ \ints -> do x <- mx return (pure x, mempty, ints, mempty) -data FieldSettings = FieldSettings - { fsLabel :: Html -- FIXME do we need Text? - , fsTooltip :: Maybe Html +data FieldSettings msg = FieldSettings + { fsLabel :: msg + , fsTooltip :: Maybe msg , fsId :: Maybe Text , fsName :: Maybe Text } -instance IsString FieldSettings where +instance IsString a => IsString (FieldSettings a) where fromString s = FieldSettings (fromString s) Nothing Nothing Nothing data FieldView xml = FieldView @@ -112,8 +112,8 @@ data FieldView xml = FieldView , fvRequired :: Bool } -data Field xml a = Field - { fieldParse :: Text -> Either Text a -- FIXME probably want to make this more sophisticated, handle no form, no field +data Field xml msg a = Field + { fieldParse :: Text -> Either msg a -- FIXME probably want to make this more sophisticated, handle no form, no field , fieldRender :: a -> Text , fieldView :: Text -- ^ ID -> Text -- ^ name diff --git a/yesod-form.cabal b/yesod-form.cabal index e92ef7d9..6094278d 100644 --- a/yesod-form.cabal +++ b/yesod-form.cabal @@ -13,7 +13,7 @@ homepage: http://www.yesodweb.com/ library build-depends: base >= 4 && < 5 - , yesod-core >= 0.8.1 && < 0.9 + , yesod-core >= 0.8.2 && < 0.9 , time >= 1.1.4 && < 1.3 , hamlet >= 0.8.1 && < 0.9 , persistent >= 0.5 && < 0.6