packages feed

simple-form 0.1 → 0.1.1

raw patch · 2 files changed

+171/−1 lines, 2 files

Files

+ SimpleForm/Digestive/Internal.hs view
@@ -0,0 +1,167 @@+{-# LANGUAGE GADTs #-}+-- | Torn from the internals of digestive-functors+module SimpleForm.Digestive.Internal (+	SimpleForm(..),+	SimpleFormEnv,+	input',+	getField,+	subView',+	fieldInputChoiceGroup'+) where++import Data.Monoid+import Control.Applicative+import Control.Monad+import Control.Monad.Fix+import Text.Blaze.Html (Html)+import Control.Monad.Trans.Reader+import Control.Monad.Trans.Writer+import Data.List (isPrefixOf)+import Data.Functor.Identity (Identity)+import Control.Arrow (second)+import Data.Text (Text)+import qualified Data.Text as T++import Text.Digestive.Form.Internal+import Text.Digestive.Form.Internal.Field+import Text.Digestive.Types+import Text.Digestive.View++import SimpleForm+import SimpleForm.Render++type SimpleFormEnv r = (Maybe r, View Html, (RenderOptions -> Html))++-- | The type of a form+newtype SimpleForm r a = SimpleForm (ReaderT (SimpleFormEnv r) (Writer Html) a)++instance Functor (SimpleForm r) where+	fmap = liftM++instance Applicative (SimpleForm r) where+	pure = return+	(<*>) = ap++instance Monad (SimpleForm r) where+	return = SimpleForm . return+	(SimpleForm x) >>= f = SimpleForm (x >>= (\v -> let SimpleForm r = f v in r))+	fail = SimpleForm . fail++instance MonadFix (SimpleForm r) where+	mfix f = SimpleForm (mfix $ unSimpleForm . f)+		where+		unSimpleForm (SimpleForm form) = form++instance (Monoid a) => Monoid (SimpleForm r a) where+	mempty = SimpleForm $ ReaderT (\_ -> tell mempty >> return mempty)+	(SimpleForm a) `mappend` (SimpleForm b) = SimpleForm $ ReaderT $ \env -> do+		a' <- runReaderT a env+		b' <- runReaderT b env+		return (a' `mappend` b')++input' ::+	Text              -- ^ Form element name+	-> (r -> Maybe a) -- ^ Get value from parsed data+	-> Widget a       -- ^ Widget to use (such as 'SimpleForm.wdef')+	-> InputOptions   -- ^ Other options+	-> SimpleFormEnv r+	-> Html+input' n sel w opt (env, view@(View {viewForm = form}), render) =+	render $ renderOptions+		(maybe Nothing sel env) unparsed (pathToText apth) w errors $+			opt {+				disabled = disabled opt || Disabled `elem` metadata+			}+	where+	apth = case absolutePath n view of+		(p:ps)+			| T.null p -> ps+			| otherwise -> p:ps+		_ -> []+	metadata = concatMap snd $ lookupFormMetadata [n] form+	errors = map snd $ filter ((==[n]) . fst) $ viewErrors view+	unparsed = getField [n] view++-- | Format form paths just like PHP/Rails+pathToText :: [Text] -> Text+pathToText [] = mempty+pathToText [p] = p+pathToText (p:ps) = mconcat (p : concatMap fragment ps)+	where+	fragment n = [+			T.singleton '[',+			n,+			T.singleton ']'+		]++getField :: Path -> View v -> Maybe Text+getField pth (View _ _ form input _ method) =+	queryField pth form (getField' method givenInput)+	where+	givenInput = lookupInput pth input++lookupInput :: Path -> [(Path, FormInput)] -> [FormInput]+lookupInput path = map snd . filter ((== path) . fst)++-- This function is why we need GADTs turned on :(+getField' ::+	Method		-- ^ Get/Post+	-> [FormInput]  -- ^ Given input+	-> Field v a	-- ^ Field+	-> Maybe Text   -- ^ Result+getField' _	_				 (Singleton _) = Nothing+getField' _	(TextInput x : _) (Text _)	  = Just x+getField' _	_				 (Text x)	  = Just x+getField' _	(TextInput x : _) (Choice _ _) = Just x+getField' _	_				 (Choice ls' x) =+	Just $ fst (concatMap snd ls' !! x)+getField' Get  _				 (Bool x)+	| x		 = Just (T.pack "on")+	| otherwise = Nothing+getField' Post (TextInput x : _) (Bool _)	  = Just x+getField' Post _				 (Bool _)	  = Nothing+getField' Post (FileInput x : _) File		  = Just (T.pack x)+getField' _	_				 File		  = Nothing++fieldInputChoiceGroup' ::+	Path+	-> View v+	-> [(Text, [(Text, v)])]+fieldInputChoiceGroup' path (View _ _ form input _ method) =+	map (second $ map (\(v,l,_) -> (v,l))) (queryField path form eval')+	where+	givenInput = lookupInput path input++	eval' :: Field v b -> [(Text, [(Text, v, Bool)])]+	eval' field = case field of+		Choice xs didx ->+			let idx = snd $ evalField method givenInput (Choice xs didx) in+				merge idx xs [0..]+		f -> error $ show path ++ ": expected (Choice _ _), " +++			"but got: (" ++ show f ++ ")"++merge ::+	Int+	-> [(Text, [(Text, (a, v))])]+	-> [Int]+	-> [(Text, [(Text, v, Bool)])]+merge _ [] _ = []+merge idx (g:gs) is = cur : merge idx gs b+	where+	(a,b) = splitAt (length $ snd g) is+	cur = (fst g, map (\(i, (k, (_, v))) -> (k, v, i == idx)) $ zip a (snd g))++subView' :: Path -> View v -> View v+subView' path (View name ctx form input errs method) =+	case lookupForm path form of+		[] -> View name (ctx ++ path) notFound (strip input) (strip errs) method+		(SomeForm f : _) -> View name (ctx ++ path) f (strip input) (strip errs) method+	where+	lpath	= length path++	strip :: [(Path, a)] -> [(Path, a)]+	strip xs = [(drop lpath p, x) | (p, x) <- xs, path `isPrefixOf` p]++	notFound :: FormTree Identity v Identity a+	notFound = error $ "Text.Digestive.View.subView: " +++		"No such subView: " ++ show path
simple-form.cabal view
@@ -1,5 +1,5 @@ name:            simple-form-version:         0.1+version:         0.1.1 cabal-version:   >= 1.8 license:         OtherLicense license-file:    COPYING@@ -30,6 +30,9 @@                 SimpleForm.Validation,                 SimpleForm.Render,                 SimpleForm.Render.XHTML5++        other-modules:+                SimpleForm.Digestive.Internal          build-depends:                 base == 4.*,