frame-0.1: src/Frame/State.lhs
> {-|
> The state contains mutable environmental variables such as posted form fields,
> field validators and the session
> -}
> module Frame.State (
> Vars (..),
> FrameState,
> FrameReader,
> get,
> put,
> gets,
> startState,
> setPost,
> getField,
> putFields,
> mergeFields,
> putField,
> delField,
> -- * Validators
> getValidator,
> putValidators,
> putValidator
> ) where
> import Prelude hiding (lookup)
> import Data.Map
> import qualified Control.Monad.State as S (gets, get, put)
> import Control.Monad.State hiding (gets, get, put)
> import Frame.Config
> import Frame.Types
> import Frame.Validation
> -- | The state record
> data Vars = Vars {
> fields :: Fields -- ^ Posted fields
> , validators :: Validators -- ^ Field validation functions
> , post :: Bool -- ^ Has a form been posted?
> , session :: Fields -- ^ Session fields
> , ajax :: Bool -- ^ Is this an AJAX request?
> }
> class (Monad m) => MonadStateGet s m | m -> s where
> -- | Provides get access to the state, mirroring Control.Monad.State.get
> get :: m s
> instance (Monad m) => MonadStateGet s (StateT s m) where
> get = S.get
> class (Monad m) => MonadStatePut s m | m -> s where
> -- | Provides get access to the state, mirroring Control.Monad.State.put
> put :: s -> m ()
> instance (Monad m) => MonadStatePut s (StateT s m) where
> put = S.put
> -- | Gets a specific component from the state, using the supplied projection function
> gets :: (MonadStateGet s m) => (s -> a) -- ^ State projection function
> -> m a -- ^ Projected component
> gets f = do
> s <- get
> return (f s)
> class (MonadStateGet Vars m, MonadStatePut Vars m) => FrameState m
> instance (MonadStateGet Vars m, MonadStatePut Vars m) => FrameState m
> class (MonadStateGet Vars m) => FrameReader m
> instance (MonadStateGet Vars m) => FrameReader m
> -- | A default empty start state
> startState :: Vars
> startState = Vars {fields = empty, validators = empty, post = False, session = empty, ajax = False}
> setPost :: FrameState m => Bool -> m ()
> setPost b = do
> v <- get
> put v {post=b}
> -- | Looks up a specific field in the state by the given field name
> getField :: FrameReader m => FieldName -- ^ FieldName to be looked up
> -> m (Maybe WrapperType) -- ^ The field (if found)
> getField fn = do
> fs <- gets fields
> return $ lookup fn fs
> -- | Deletes a specific field in the state by the given field name
> delField :: FrameState m
> => FieldName -- ^ FieldName to be deleted
> -> m ()
> delField fn = do
> fs <- gets fields
> v <- get
> put v {fields=delete fn fs}
> -- | Replaces the fields in the state
> putFields :: FrameState m => Fields -- ^ Fields to replace with
> -> m () -- ^ Nothing (but the modified state) is returned
> putFields fs = do
> v <- get
> put v {fields=fs}
> -- | Merges the given fields with the existing state (existing state fields are favoured)
> mergeFields :: FrameState m => Maybe Fields -- ^ Fields to merge
> -> m () -- ^ Nothing (but the modified state) is returned
> mergeFields Nothing = return ()
> mergeFields (Just fs') = do
> fs <- gets fields
> putFields $ union fs fs'
> -- | Associate a value with a FieldName in the state
> putField :: (FrameState m, FrameConfig m, Wrappable a)
> => FieldName -- ^ The FieldName of the field being updated
> -> a -- ^ The (wrappable) field to update state with
> -> m () -- ^ Nothing (but the modified state) is returned
> putField fn f = do
> db <- asks database
> fs <- gets fields
> v <- get
> put v {fields=insert fn (wrap db fn f) fs}
> -- | Look up validators functions for a particular field
> getValidator :: FrameReader m => FieldName -- ^ Validators to look up
> -> m (Maybe [WrapperType -> Maybe String]) -- ^ The validator functions (if found)
> getValidator fn = do
> vs <- gets validators
> return $ lookup fn vs
> -- | Replaces the Validators in the state
> putValidators :: FrameState m => Validators -- ^ Validators to replace with
> -> m () -- ^ Nothing (but the modified state) is returned
> putValidators vs = do
> v <- get
> put v {validators=vs}
> -- | Associate a set of validator functions with a FieldName in the state
> putValidator :: FrameState m => FieldName -- ^ The FieldName of the validator being updated
> -> [WrapperType -> Maybe String] -- ^ The validator functions to update state with
> -> m () -- ^ Nothing (but the modified state) is returned
> putValidator fn ms = do
> vs <- gets validators
> v <- get
> put v {validators=insert fn ms vs}