-- | Functions to construct common forms
--
module Text.Digestive.Common
( input
, inputString
, inputRead
, inputBool
, inputChoice
, label
, errors
, childErrors
) where
import Control.Applicative ((<$>))
import Control.Monad (mplus)
import Data.Monoid (Monoid, mconcat)
import Data.Maybe (fromMaybe)
import Text.Digestive.Types
import Text.Digestive.Result
import Text.Digestive.Transform
input :: (Monad m, Functor m)
=> (Bool -> Maybe String -> d -> s) -- ^ Get the viewed result
-> (Maybe String -> FormRange -> Result e a) -- ^ Get the returned result
-> (FormId -> s -> v) -- ^ View constructor
-> d -- ^ Default value
-> Form m String e v a -- ^ Resulting form
input toView toResult createView defaultInput = Form $ do
isInput <- isFormInput
inp <- getFormInput
id' <- getFormId
range <- getFormRange
let view' = toView isInput inp defaultInput
result' = toResult inp range
return (View (const $ createView id' view'), result')
inputString :: (Monad m, Functor m)
=> (FormId -> Maybe String -> v) -- ^ View constructor
-> Maybe String -- ^ Default value
-> Form m String e v String -- ^ Resulting form
inputString = input toView toResult
where
toView = const mplus
toResult = const . Ok . fromMaybe ""
inputRead :: (Monad m, Functor m, Read a, Show a)
=> (FormId -> Maybe String -> v) -- ^ View constructor
-> e -- ^ Error when no read
-> Maybe a -- ^ Default input
-> Form m String e v a -- ^ Resulting form
inputRead cons' error' def = inputString cons' (fmap show def)
`transform` transformRead error'
inputBool :: (Monad m, Functor m)
=> (FormId -> Bool -> v) -- ^ View constructor
-> Bool -- ^ Default input
-> Form m String e v Bool -- ^ Resulting form
inputBool = input toView toResult
where
toView isInput inp def = if isInput then readBool inp else def
toResult inp _ = Ok $ readBool inp
readBool (Just x) = not (null x)
readBool Nothing = False
inputChoice :: (Monad m, Functor m, Monoid v, Eq a)
=> (FormId -> String -> Bool -> a -> v) -- ^ Choice constructor
-> a -- ^ Default option
-> [a] -- ^ Choices
-> Form m String e v a -- ^ Resulting form
inputChoice toView defaultInput choices = Form $ do
inputKey <- fromMaybe "" <$> getFormInput
id' <- getFormId
let -- Find the actual input, based on the key, or use the default input
inp = fromMaybe defaultInput $ lookup inputKey $ zip (ids id') choices
-- Apply the toView' function to all choices
view' = mconcat $ zipWith (toView' id' inp) (ids id') choices
return (View (const view'), Ok inp)
where
ids id' = map (((show id' ++ "-") ++) . show) [1 .. length choices]
toView' id' inp key x = toView id' key (inp == x) x
label :: Monad m
=> (FormId -> v)
-> Form m i e v ()
label f = Form $ do
id' <- getFormId
return (View (const $ f id'), Ok ())
errors :: Monad m
=> ([e] -> v)
-> Form m i e v ()
errors f = Form $ do
range <- getFormRange
return (View (f . retainErrors range), Ok ())
childErrors :: Monad m
=> ([e] -> v)
-> Form m i e v ()
childErrors f = Form $ do
range <- getFormRange
return (View (f . retainChildErrors range), Ok ())