Added multiple select fields to yesod and to demo.

This commit is contained in:
DavidM 2011-06-20 20:42:34 -04:00
parent 64e2082049
commit dc1a532225
3 changed files with 35 additions and 1 deletions

View File

@ -17,6 +17,7 @@ module Yesod.Form.Fields
, emailField , emailField
, searchField , searchField
, selectField , selectField
, multiSelectField
, AutoFocus , AutoFocus
, urlField , urlField
, doubleField , doubleField
@ -40,6 +41,9 @@ import Network.URI (parseURI)
import Database.Persist (PersistField) import Database.Persist (PersistField)
import Text.HTML.SanitizeXSS (sanitizeBalance) import Text.HTML.SanitizeXSS (sanitizeBalance)
import Control.Monad (when, unless) import Control.Monad (when, unless)
import Data.List (intersect, nub)
import Data.Either (rights)
import Data.Maybe (catMaybes)
import qualified Blaze.ByteString.Builder.Html.Utf8 as B import qualified Blaze.ByteString.Builder.Html.Utf8 as B
import Blaze.ByteString.Builder (writeByteString, toLazyByteString) import Blaze.ByteString.Builder (writeByteString, toLazyByteString)
@ -315,6 +319,11 @@ selectField = selectFieldHelper
(\_theId _name isSel -> [WHAMLET|<option value=none :isSel:selected>_{MsgSelectNone}|]) (\_theId _name isSel -> [WHAMLET|<option value=none :isSel:selected>_{MsgSelectNone}|])
(\_theId _name value isSel text -> addHtml [HTML|<option value=#{value} :isSel:selected>#{text}|]) (\_theId _name value isSel text -> addHtml [HTML|<option value=#{value} :isSel:selected>#{text}|])
multiSelectField :: (Show a, Eq a, Monad monad, RenderMessage master FormMessage) => [(Text, a)] -> Field (GGWidget master (GGHandler sub master monad) ()) FormMessage [a]
multiSelectField = multiSelectFieldHelper
(\theId name inside -> [WHAMLET|<select ##{theId} multiple name=#{name}>^{inside}|])
(\_theId _name value isSel text -> addHtml [HTML|<option value=#{value} :isSel:selected>#{text}|])
radioField :: (Eq a, Monad monad, RenderMessage master FormMessage) => [(Text, a)] -> Field (GGWidget master (GGHandler sub master monad) ()) FormMessage a radioField :: (Eq a, Monad monad, RenderMessage master FormMessage) => [(Text, a)] -> Field (GGWidget master (GGHandler sub master monad) ()) FormMessage a
radioField = selectFieldHelper radioField = selectFieldHelper
(\theId _name inside -> [WHAMLET|<div ##{theId}>^{inside}|]) (\theId _name inside -> [WHAMLET|<div ##{theId}>^{inside}|])
@ -354,6 +363,28 @@ boolField = Field
"no" -> Right $ Just False "no" -> Right $ Just False
t -> Left $ MsgInvalidBool t t -> Left $ MsgInvalidBool t
multiSelectFieldHelper :: (Show a, Eq a, Monad monad)
=> (Text -> Text -> GGWidget master monad () -> GGWidget master monad ())
-> (Text -> Text -> Text -> Bool -> Text -> GGWidget master monad ())
-> [(Text, a)] -> Field (GGWidget master monad ()) FormMessage [a]
multiSelectFieldHelper outside inside opts = Field
{ fieldParse = selectParser
, fieldView = \theId name vals _ ->
outside theId name $ do
flip mapM_ pairs $ \pair -> inside
theId
name
(pack $ show $ fst pair)
((fst pair) `elem` (maybe [] selectedVals vals))
(fst $ snd pair)
}
where
pairs = zip [1 :: Int ..] opts -- FIXME use IntMap
rpairs = zip (map snd opts) [1 :: Int ..]
selectedVals vals = map snd $ filter (\y -> fst y `elem` vals) rpairs
selectParser [] = Right Nothing
selectParser xs | not $ null (["", "none"] `intersect` xs) = Right Nothing
| otherwise = (Right . Just . map snd . catMaybes . map (\y -> lookup y pairs) . nub . map fst . rights . map Data.Text.Read.decimal) xs
selectFieldHelper :: (Eq a, Monad monad) selectFieldHelper :: (Eq a, Monad monad)
=> (Text -> Text -> GGWidget master monad () -> GGWidget master monad ()) => (Text -> Text -> GGWidget master monad () -> GGWidget master monad ())

View File

@ -103,6 +103,7 @@ mhelper :: (Monad m, RenderMessage master msg, RenderMessage master msg2)
-> (a -> FormResult b) -- ^ on success -> (a -> FormResult b) -- ^ on success
-> Bool -- ^ is it required? -> Bool -- ^ is it required?
-> Form master (GGHandler sub master m) (FormResult b, FieldView xml) -> Form master (GGHandler sub master m) (FormResult b, FieldView xml)
mhelper Field {..} FieldSettings {..} mdef onMissing onFound isReq = do mhelper Field {..} FieldSettings {..} mdef onMissing onFound isReq = do
mp <- askParams mp <- askParams
name <- maybe newFormIdent return fsName name <- maybe newFormIdent return fsName

View File

@ -12,12 +12,14 @@ data Fruit = Apple | Banana | Pear
fruits :: [(Text, Fruit)] fruits :: [(Text, Fruit)]
fruits = map (\x -> (pack $ show x, x)) [minBound..maxBound] fruits = map (\x -> (pack $ show x, x)) [minBound..maxBound]
myForm = fixType $ runFormGet $ renderDivs $ pure (,,,,,,) myForm = fixType $ runFormGet $ renderDivs $ pure (,,,,,,,,)
<*> areq boolField "Bool field" Nothing <*> areq boolField "Bool field" Nothing
<*> aopt boolField "Opt bool field" Nothing <*> aopt boolField "Opt bool field" Nothing
<*> areq textField "Text field" Nothing <*> areq textField "Text field" Nothing
<*> areq (selectField fruits) "Select field" Nothing <*> areq (selectField fruits) "Select field" Nothing
<*> aopt (selectField fruits) "Opt select field" Nothing <*> aopt (selectField fruits) "Opt select field" Nothing
<*> areq (multiSelectField fruits) "Multi select field" Nothing
<*> aopt (multiSelectField fruits) "Opt multi select field" Nothing
<*> aopt intField "Opt int field" Nothing <*> aopt intField "Opt int field" Nothing
<*> aopt (radioField fruits) "Opt radio" Nothing <*> aopt (radioField fruits) "Opt radio" Nothing