From 0fbed68915844ee2f2f4bd074b7ac03d06729fa9 Mon Sep 17 00:00:00 2001 From: SJost Date: Wed, 27 Feb 2019 14:23:56 +0100 Subject: [PATCH] wrapForm created, not used everywhere yet --- src/Handler/Admin.hs | 14 +- src/Handler/Utils/Form.hs | 1 + src/Utils.hs | 20 +-- src/Utils/Form.hs | 195 ++++++++++++++++----------- src/Utils/Route.hs | 27 ++++ templates/widgets/aform/aform.hamlet | 23 ++++ templates/widgets/form/form.hamlet | 35 ++--- templates/widgets/form/form.julius | 4 +- 8 files changed, 191 insertions(+), 128 deletions(-) create mode 100644 src/Utils/Route.hs create mode 100644 templates/widgets/aform/aform.hamlet diff --git a/src/Handler/Admin.hs b/src/Handler/Admin.hs index 501cc97b9..fe20fcd4e 100644 --- a/src/Handler/Admin.hs +++ b/src/Handler/Admin.hs @@ -55,13 +55,14 @@ emailTestForm = (,) SelFormatTime -> t makeDemoForm :: Int -> Form (Int,Bool,Double) -makeDemoForm n = identifyForm "adminTestForm" $ \html -> do -- Important: used identForm instead! +makeDemoForm n = identForm FIDAdminDemo $ \html -> do -- Important: used identForm instead! (result, widget) <- flip (renderAForm FormStandard) html $ (,,) <$> areq (minIntField n "Zahl") (fromString $ "Ganzzahl > " ++ show n) Nothing <* aformSection MsgFormBehaviour <*> areq checkBoxField "Muss nächste Zahl größer sein?" (Just True) <*> areq doubleField "Fliesskommazahl" Nothing - <* submitButton + -- NO LONGER DESIRED IN AFORMS: + -- <* submitButton return $ case result of FormSuccess fsres | errorMsgs <- validateResult fsres @@ -103,7 +104,6 @@ postAdminTestR = do let demoFormAction (_i,_b,_d) = addMessage Info "All ok." ((demoResult, formWidget),formEnctype) <- runFormPost $ makeDemoForm 7 formResult demoResult demoFormAction - let actionUrl = AdminTestR let showDemoResult = [whamlet| $maybe (i,b,d) <- formResult' demoResult Received values: @@ -133,7 +133,13 @@ postAdminTestR = do $(widgetFile "adminTest") [whamlet|

Formular Demonstration|] - $(widgetFile "formPage") + wrapForm formWidget FormSettings + { formMethod = methodPost + , formAction = SomeRoute $ AdminTestR :#: FIDAdminDemo + , formEncoding = formEnctype + , formSubmit = FormSubmit + , formAnchor = Just FIDAdminDemo + } showDemoResult diff --git a/src/Handler/Utils/Form.hs b/src/Handler/Utils/Form.hs index 2a568432e..5c04eef05 100644 --- a/src/Handler/Utils/Form.hs +++ b/src/Handler/Utils/Form.hs @@ -45,6 +45,7 @@ import Utils.Lens import Data.Aeson (eitherDecodeStrict') import Data.Aeson.Text (encodeToLazyText) + ---------------------------- -- Buttons (new version ) -- ---------------------------- diff --git a/src/Utils.hs b/src/Utils.hs index a523c723b..20e33348f 100644 --- a/src/Utils.hs +++ b/src/Utils.hs @@ -22,6 +22,7 @@ import Utils.DB as Utils import Utils.TH as Utils import Utils.DateTime as Utils import Utils.PathPiece as Utils +import Utils.Route as Utils import Utils.Message as Utils import Utils.Lang as Utils import Control.Lens as Utils (none) @@ -103,25 +104,6 @@ unsupportedAuthPredicate = do |] -class RedirectUrl site url => HasRoute site url where - urlRoute :: url -> Route site - -instance HasRoute site (Route site) where - urlRoute = id -instance (key ~ Text, val ~ Text) => HasRoute site (Route site, Map key val) where - urlRoute = view _1 -instance (key ~ Text, val ~ Text) => HasRoute site (Route site, [(key, val)]) where - urlRoute = view _1 -instance (HasRoute site a, PathPiece b) => HasRoute site (Fragment a b) where - urlRoute (a :#: _) = urlRoute a - -data SomeRoute site = forall url. HasRoute site url => SomeRoute url - -instance RedirectUrl site (SomeRoute site) where - toTextUrl (SomeRoute url) = toTextUrl url -instance HasRoute site (SomeRoute site) where - urlRoute (SomeRoute url) = urlRoute url - -- | A @Widget@ for any site; no language interpolation, etc. type WidgetSiteless = forall site. forall m. (MonadIO m, MonadThrow m, MonadBaseControl IO m) diff --git a/src/Utils/Form.hs b/src/Utils/Form.hs index 8c53501f8..094397029 100644 --- a/src/Utils/Form.hs +++ b/src/Utils/Form.hs @@ -29,52 +29,11 @@ import Data.UUID import Utils.Message import Utils.PathPiece +import Utils.Route import Data.Proxy -------------------- --- Form Renderer -- -------------------- --- | Use this type to pass information to the form template -data FormLayout = FormStandard | FormDBTableFilter | FormDBTablePagesize - -renderAForm :: Monad m => FormLayout -> FormRender m a -renderAForm formLayout aform fragment = do - (res, ($ []) -> fieldViews) <- aFormToForm aform - let widget = $(widgetFile "widgets/form/form") - return (res, widget) - --- | special id to identify form section headers, see 'aformSection' and 'formSection' --- currently only treated by form generation through 'renderAForm' -idFormSectionNoinput :: Text -idFormSectionNoinput = "form-section-noinput" - --- | Generates a form having just a form-section-header and no input title. --- Currently only correctly rendered by 'renderAForm' and mforms using 'widget/form.hamlet' --- Usage: --- @ --- (,) <$ formSection MsgInt --- <*> areq intField "int here" Nothing --- <* formSection MsgDouble --- <*> areq doubleField "double there " Nothing --- <* submitButton --- @ --- If tooltips or other attributes are required, see 'formSection\'' instead. -aformSection :: (MonadHandler m, site ~ HandlerSite m, RenderMessage site msg) => msg -> AForm m () -aformSection = formToAForm . fmap (second pure) . formSection - -formSection :: (MonadHandler m, site ~ HandlerSite m, RenderMessage site msg) => msg -> MForm m (FormResult (), FieldView site) -- TODO: WIP, delete -formSection formSectionTitle = do - mr <- getMessageRender - return (FormSuccess (), FieldView - { fvLabel = toHtml $ mr formSectionTitle - , fvTooltip = Nothing - , fvId = idFormSectionNoinput - , fvErrors = Nothing - , fvRequired = False - , fvInput = mempty - }) -------------------- @@ -188,45 +147,7 @@ inputReadonly = addAttr "readonly" "" addAutosubmit :: FieldSettings site -> FieldSettings site addAutosubmit = addAttr "data-autosubmit" "" ------------------------------------------------- --- Unique Form Identifiers to avoid accidents -- ------------------------------------------------- -data FormIdentifier - = FIDcourse - | FIDsheet - | FIDsubmission - | FIDsettings - | FIDcorrectors - | FIDcorrectorTable - | FIDcorrection - | FIDcorrectionsUpload - | FIDcorrectionUpload - | FIDSystemMessageAdd - | FIDSystemMessageTable - | FIDSystemMessageModify - | FIDSystemMessageModifyTranslation UUID - | FIDSystemMessageAddTranslation - | FIDDBTableFilter - | FIDDBTablePagesize - | FIDDelete - deriving (Eq, Ord, Read, Show) - -instance PathPiece FormIdentifier where - fromPathPiece = readFromPathPiece - toPathPiece = showToPathPiece - - -identForm :: (Monad m, PathPiece ident) - => ident -- ^ Form identification - -> (Html -> MForm m (FormResult a, WidgetT (HandlerSite m) IO ())) - -> (Html -> MForm m (FormResult a, WidgetT (HandlerSite m) IO ())) -identForm = identifyForm . toPathPiece - -{- Hinweise zur Erinnerung: - - identForm primär, wenn es mehr als ein Formular pro Handler gibt - - nur einmal pro makeForm reicht --} ---------------------------- -- Buttons (new version ) -- @@ -426,6 +347,120 @@ optionsFinite = do } return . mkOptionList $ mkOption <$> universeF + + +------------------------------------------------ +-- Unique Form Identifiers to avoid accidents -- +------------------------------------------------ + +data FormIdentifier + = FIDcourse + | FIDsheet + | FIDsubmission + | FIDsettings + | FIDcorrectors + | FIDcorrectorTable + | FIDcorrection + | FIDcorrectionsUpload + | FIDcorrectionUpload + | FIDSystemMessageAdd + | FIDSystemMessageTable + | FIDSystemMessageModify + | FIDSystemMessageModifyTranslation UUID + | FIDSystemMessageAddTranslation + | FIDDBTableFilter + | FIDDBTablePagesize + | FIDDelete + | FIDAdminDemo + deriving (Eq, Ord, Read, Show) + +instance PathPiece FormIdentifier where + fromPathPiece = readFromPathPiece + toPathPiece = showToPathPiece + + +identForm :: (Monad m, PathPiece ident) + => ident -- ^ Form identification + -> (Html -> MForm m (FormResult a, WidgetT (HandlerSite m) IO ())) + -> (Html -> MForm m (FormResult a, WidgetT (HandlerSite m) IO ())) +identForm = identifyForm . toPathPiece + +{- Hinweise zur Erinnerung: + - identForm primär, wenn es mehr als ein Formular pro Handler gibt + - nur einmal pro makeForm reicht +-} + + + +----------- +-- Forms -- +----------- + +data FormSubmitType = FormNoSubmit | FormSubmit | FormDualSubmit + deriving (Eq, Ord, Enum, Read, Show, Typeable, Generic) + +data FormSettings site = FormSettings + { formMethod :: Method + , formAction :: SomeRoute site + , formEncoding :: Enctype + , formSubmit :: FormSubmitType + , formAnchor :: Maybe FormIdentifier + } + +wrapForm :: (Button site ButtonSubmit) => WidgetT site IO () -> FormSettings site -> WidgetT site IO () +wrapForm formWidget FormSettings{..} = do + formId <- maybe newIdent (return . toPathPiece) formAnchor + formActionUrl <- toTextUrl formAction + $(widgetFile "widgets/form/form") + + +------------------- +-- Form Renderer -- +------------------- + +-- | Use this type to pass information to the form template +data FormLayout = FormStandard | FormDBTableFilter | FormDBTablePagesize + +renderAForm :: Monad m => FormLayout -> FormRender m a +renderAForm formLayout aform fragment = do + (res, ($ []) -> fieldViews) <- aFormToForm aform + let widget = $(widgetFile "widgets/aform/aform") + return (res, widget) + + +-- | special id to identify form section headers, see 'aformSection' and 'formSection' +-- currently only treated by form generation through 'renderAForm' +idFormSectionNoinput :: Text +idFormSectionNoinput = "form-section-noinput" + +-- | Generates a form having just a form-section-header and no input title. +-- Currently only correctly rendered by 'renderAForm' and mforms using 'widget/form.hamlet' +-- Usage: +-- @ +-- (,) <$ formSection MsgInt +-- <*> areq intField "int here" Nothing +-- <* formSection MsgDouble +-- <*> areq doubleField "double there " Nothing +-- <* submitButton +-- @ +-- If tooltips or other attributes are required, see 'formSection\'' instead. +aformSection :: (MonadHandler m, site ~ HandlerSite m, RenderMessage site msg) => msg -> AForm m () +aformSection = formToAForm . fmap (second pure) . formSection + +formSection :: (MonadHandler m, site ~ HandlerSite m, RenderMessage site msg) => msg -> MForm m (FormResult (), FieldView site) -- TODO: WIP, delete +formSection formSectionTitle = do + mr <- getMessageRender + return (FormSuccess (), FieldView + { fvLabel = toHtml $ mr formSectionTitle + , fvTooltip = Nothing + , fvId = idFormSectionNoinput + , fvErrors = Nothing + , fvRequired = False + , fvInput = mempty + }) + + + ------------------- -- Special Forms -- ------------------- diff --git a/src/Utils/Route.hs b/src/Utils/Route.hs new file mode 100644 index 000000000..a62e57cb1 --- /dev/null +++ b/src/Utils/Route.hs @@ -0,0 +1,27 @@ +module Utils.Route where + +import Control.Lens +import ClassyPrelude.Yesod -- hiding (foldlM) + + +class RedirectUrl site url => HasRoute site url where + urlRoute :: url -> Route site + +instance HasRoute site (Route site) where + urlRoute = id +-- | for GET-Parameters +instance (key ~ Text, val ~ Text) => HasRoute site (Route site, Map key val) where + urlRoute = view _1 +-- | for GET-Parameters +instance (key ~ Text, val ~ Text) => HasRoute site (Route site, [(key, val)]) where + urlRoute = view _1 +-- | for PageAnchors, implemented through Fragments +instance (HasRoute site a, PathPiece b) => HasRoute site (Fragment a b) where + urlRoute (a :#: _) = urlRoute a + +data SomeRoute site = forall url. HasRoute site url => SomeRoute url + +instance RedirectUrl site (SomeRoute site) where + toTextUrl (SomeRoute url) = toTextUrl url +instance HasRoute site (SomeRoute site) where + urlRoute (SomeRoute url) = urlRoute url diff --git a/templates/widgets/aform/aform.hamlet b/templates/widgets/aform/aform.hamlet new file mode 100644 index 000000000..87f40532c --- /dev/null +++ b/templates/widgets/aform/aform.hamlet @@ -0,0 +1,23 @@ +$newline never +#{fragment} +$case formLayout + $of FormDBTablePagesize + $forall view <- fieldViews +