Safe Haskell | None |
---|---|
Language | Haskell2010 |
FlexTask.Generic.Form
Description
Generic Yesod
input form generation and related utility functions.
Synopsis
- data Alignment
- data FieldInfo
- data SingleChoiceSelection
- data MultipleChoiceSelection
- newtype Hidden a = Hidden {
- getHidden :: a
- newtype SingleInputList a = SingleInputList {
- getList :: [a]
- class BaseForm a where
- class Formify a where
- formify :: Formify a => Maybe a -> [[FieldInfo]] -> Rendered Widget
- formifyComponents :: Formify a => Maybe a -> [[FieldInfo]] -> Rendered [[Widget]]
- formifyComponentsFlat :: Formify a => Maybe a -> [FieldInfo] -> Rendered [Widget]
- getAnswer :: SingleChoiceSelection -> Maybe Int
- getAnswers :: MultipleChoiceSelection -> [Int]
- multipleChoiceAnswer :: [Int] -> MultipleChoiceSelection
- multipleChoiceEmpty :: MultipleChoiceSelection
- singleChoiceAnswer :: Int -> SingleChoiceSelection
- singleChoiceEmpty :: SingleChoiceSelection
- buttons :: Alignment -> FieldSettings FlexForm -> [SomeMessage FlexForm] -> FieldInfo
- buttonsEnum :: (Bounded a, Enum a) => Alignment -> FieldSettings FlexForm -> (a -> SomeMessage FlexForm) -> FieldInfo
- dropdown :: FieldSettings FlexForm -> [SomeMessage FlexForm] -> FieldInfo
- dropdownEnum :: (Bounded a, Enum a) => FieldSettings FlexForm -> (a -> SomeMessage FlexForm) -> FieldInfo
- list :: Alignment -> [FieldSettings FlexForm] -> FieldInfo
- listWithoutLabels :: Alignment -> Int -> [(Text, Text)] -> FieldInfo
- single :: FieldSettings FlexForm -> FieldInfo
- formifyInstanceBasicField :: BaseForm a => Maybe a -> [[FieldInfo]] -> ([[FieldInfo]], [[Rendered Widget]])
- formifyInstanceOptionalField :: BaseForm a => Maybe (Maybe a) -> [[FieldInfo]] -> ([[FieldInfo]], [[Rendered Widget]])
- formifyInstanceSingleChoice :: (Bounded a, Enum a, Eq a) => Maybe a -> [[FieldInfo]] -> ([[FieldInfo]], [[Rendered Widget]])
- formifyInstanceMultiChoice :: (Bounded a, Enum a, Eq a) => Maybe [a] -> [[FieldInfo]] -> ([[FieldInfo]], [[Rendered Widget]])
Data Types
Inner alignment of input field elements.
Constructors
Horizontal | |
Vertical |
Data type representing a prebuilt input field.
This type is used to determine the structure of a generated form.
The form is represented by a [[FieldInfo]]
type value.
Each FieldInfo value is an individual form element.
Inner lists represent the rows of the form.
All FieldInfo values in an inner list are rendered besides each other.
Inner lists are rendered below each other.
Examples
Input
[[single "field1", single "field2"]]
Renders as:
field1 field2
Input
[[single "field1"], [single "field2"]]
Renders as:
field1 field2
Caution: Not all horizontal alignments work as one would expect.
If an element uses inner Alignment
parameters,
then the next form will only be rendered besides the last form component of the former.
Input
[[listWithoutLabels Vertical 2 []],[listWithoutLabels Vertical 2 []]]
will not result in
list11 list21 list12 list22
but instead in
list11 list12 list21 list22
data SingleChoiceSelection Source #
Generic single choice answer type. Use if both of the following is true:
- You want an input that presents multiple answer choices, but only allows a single selection.
- There's no specific data type associated with this selection.
Example
>>>
let labels = ["First Option", "Second Option", "Third Option"]
>>>
printWidget "en" $ formify (Just $ singleChoiceAnswer 3) [[dropdown "Choose one" labels]]
<div class="flex-form-div"> ... <label for="flexident1"> Choose one </label> <select id="flexident1" ...> <option value="1"> First Option </option> <option value="2"> Second Option </option> <option value="3" selected> Third Option </option> </select> ... </div>
Instances
data MultipleChoiceSelection Source #
Same as SingleChoiceSelection
, but for multiple choice input.
Use if both of the following is true:
- You want an input that presents multiple answer choices and allows selecting any number of them.
- There's no specific data type associated with this selection.
Example
>>>
let labels = ["First Option", "Second Option", "Third Option"]
>>>
printWidget "en" $ formify (Just $ multipleChoiceAnswer [1,2]) [[dropdown "Choose one" labels]]
<div class="flex-form-div"> ... <label for="flexident1"> Choose one </label> <select id="flexident1" ... multiple> <option value="1" selected> First Option </option> <option value="2" selected> Second Option </option> <option value="3"> Third Option </option> </select> ... </div>
Instances
Generic MultipleChoiceSelection Source # | |||||
Defined in FlexTask.Generic.Form Associated Types
Methods from :: MultipleChoiceSelection -> Rep MultipleChoiceSelection x # to :: Rep MultipleChoiceSelection x -> MultipleChoiceSelection # | |||||
Show MultipleChoiceSelection Source # | |||||
Defined in FlexTask.Generic.Form Methods showsPrec :: Int -> MultipleChoiceSelection -> ShowS # show :: MultipleChoiceSelection -> String # showList :: [MultipleChoiceSelection] -> ShowS # | |||||
Formify MultipleChoiceSelection Source # | |||||
Defined in FlexTask.Generic.Form Methods formifyImplementation :: Maybe MultipleChoiceSelection -> [[FieldInfo]] -> ([[FieldInfo]], [[Rendered Widget]]) Source # | |||||
Parse MultipleChoiceSelection Source # | |||||
Defined in FlexTask.Generic.ParseInternal Methods | |||||
Eq MultipleChoiceSelection Source # | |||||
Defined in FlexTask.Generic.Form Methods (==) :: MultipleChoiceSelection -> MultipleChoiceSelection -> Bool # (/=) :: MultipleChoiceSelection -> MultipleChoiceSelection -> Bool # | |||||
type Rep MultipleChoiceSelection Source # | |||||
Defined in FlexTask.Generic.Form type Rep MultipleChoiceSelection = D1 ('MetaData "MultipleChoiceSelection" "FlexTask.Generic.Form" "flex-tasks-0.1-9xUOiHEuYqQBURteUggsib" 'True) (C1 ('MetaCons "MultipleChoiceSelection" 'PrefixI 'True) (S1 ('MetaSel ('Just "getAnswers") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 [Int]))) |
Wrapper type for generating hidden fields.
This can be used to transfer static information through the form to parsing. Note that the generated field still has a label. If the label is not left blank, then it will be displayed as normal.
Example
>>>
printWidget "en" $ formify (Just $ Hidden 3) [[single ""]]
<div class="flex-form-div"> ... <label for="flexident1"> </label> <input type="hidden" id="flexident1" ... value="3"> ... </div>
newtype SingleInputList a Source #
Wrapper type for lists. Use for a single field list input. Normally, lists are interpreted as multiple fields instead.
Example
>>>
printWidget "en" $ formify (Nothing @(SingleInputList String)) [[single "Input comma separated sentences"]]
<div class="flex-form-div"> ... <label for="flexident1"> Input comma separated sentences </label> <input id="flexident1" ... type="text" ...> ... </div>
Note that this does not actually enforce any kind of input syntax.
The generated input itself is a simple text field.
The comma separation is checked only when parsing with the matching formParser
.
Constructors
SingleInputList | |
Fields
|
Instances
Show a => Show (SingleInputList a) Source # | |
Defined in FlexTask.Generic.Form Methods showsPrec :: Int -> SingleInputList a -> ShowS # show :: SingleInputList a -> String # showList :: [SingleInputList a] -> ShowS # | |
Show a => BaseForm (SingleInputList a) Source # | |
Defined in FlexTask.Generic.Form Methods baseForm :: Field Handler (SingleInputList a) Source # | |
Show a => Formify (SingleInputList a) Source # | |
Defined in FlexTask.Generic.Form Methods formifyImplementation :: Maybe (SingleInputList a) -> [[FieldInfo]] -> ([[FieldInfo]], [[Rendered Widget]]) Source # | |
Parse (SingleInputList Text) Source # | |
Defined in FlexTask.Generic.ParseInternal Methods | |
Parse (SingleInputList Textarea) Source # | |
Defined in FlexTask.Generic.ParseInternal Methods formParser :: Parser (SingleInputList Textarea) Source # | |
Parse (SingleInputList String) Source # | |
Defined in FlexTask.Generic.ParseInternal Methods | |
Parse (SingleInputList Integer) Source # | |
Defined in FlexTask.Generic.ParseInternal Methods | |
Parse (SingleInputList Bool) Source # | |
Defined in FlexTask.Generic.ParseInternal Methods | |
Parse (SingleInputList Double) Source # | |
Defined in FlexTask.Generic.ParseInternal Methods | |
Parse (SingleInputList Int) Source # | |
Defined in FlexTask.Generic.ParseInternal Methods | |
Eq a => Eq (SingleInputList a) Source # | |
Defined in FlexTask.Generic.Form Methods (==) :: SingleInputList a -> SingleInputList a -> Bool # (/=) :: SingleInputList a -> SingleInputList a -> Bool # |
Type Classes
class BaseForm a where Source #
Members have a basic Yesod field representing Html input fields.
A BaseForm
instance of type a
is needed for generically producing forms
for [a]
and Maybe a
types.
An instance can be given manually with the Field
constructor
or using the convertField
function on an existing Field
.
Example
>>>
instance BaseForm MyCoolType where baseForm = convertField toCool fromCool basisField
Instances
BaseForm Text Source # | |
BaseForm Textarea Source # | |
Defined in FlexTask.Generic.Form | |
BaseForm String Source # | |
BaseForm Integer Source # | |
BaseForm Bool Source # | |
BaseForm Double Source # | |
BaseForm Int Source # | |
PathPiece a => BaseForm (Hidden a) Source # | |
Show a => BaseForm (SingleInputList a) Source # | |
Defined in FlexTask.Generic.Form Methods baseForm :: Field Handler (SingleInputList a) Source # |
class Formify a where Source #
Class for generic generation of Html input forms for a given type. Bodyless instances can be declared for any type instancing Generic. Exception: Types with multiple constructors. Use utility functions for those or provide your own instance.
Minimal complete definition
Nothing
Methods
formifyImplementation Source #
Arguments
:: Maybe a | Optional default value for form. |
-> [[FieldInfo]] | Structure and type of form. |
-> ([[FieldInfo]], [[Rendered Widget]]) | remaining form structure and completed sub-renders. |
Instances
Formify MultipleChoiceSelection Source # | |
Defined in FlexTask.Generic.Form Methods formifyImplementation :: Maybe MultipleChoiceSelection -> [[FieldInfo]] -> ([[FieldInfo]], [[Rendered Widget]]) Source # | |
Formify SingleChoiceSelection Source # | |
Defined in FlexTask.Generic.Form Methods formifyImplementation :: Maybe SingleChoiceSelection -> [[FieldInfo]] -> ([[FieldInfo]], [[Rendered Widget]]) Source # | |
Formify Text Source # | |
Defined in FlexTask.Generic.Form | |
Formify Textarea Source # | |
Defined in FlexTask.Generic.Form | |
Formify String Source # | |
Defined in FlexTask.Generic.Form | |
Formify Integer Source # | |
Defined in FlexTask.Generic.Form | |
Formify Bool Source # | |
Defined in FlexTask.Generic.Form | |
Formify Double Source # | |
Defined in FlexTask.Generic.Form | |
Formify Int Source # | |
Defined in FlexTask.Generic.Form | |
PathPiece a => Formify (Hidden a) Source # | |
Defined in FlexTask.Generic.Form | |
Show a => Formify (SingleInputList a) Source # | |
Defined in FlexTask.Generic.Form Methods formifyImplementation :: Maybe (SingleInputList a) -> [[FieldInfo]] -> ([[FieldInfo]], [[Rendered Widget]]) Source # | |
(BaseForm a, Formify a) => Formify (Maybe a) Source # | |
Defined in FlexTask.Generic.Form | |
Formify (Maybe a) => Formify [Maybe a] Source # | |
Defined in FlexTask.Generic.Form | |
(BaseForm a, Formify a) => Formify [a] Source # | |
Defined in FlexTask.Generic.Form | |
(Formify a, Formify b) => Formify (a, b) Source # | |
Defined in FlexTask.Generic.Form | |
(Formify a, Formify b, Formify c) => Formify (a, b, c) Source # | |
Defined in FlexTask.Generic.Form | |
(Formify a, Formify b, Formify c, Formify d) => Formify (a, b, c, d) Source # | |
Defined in FlexTask.Generic.Form | |
(Formify a, Formify b, Formify c, Formify d, Formify e) => Formify (a, b, c, d, e) Source # | |
Defined in FlexTask.Generic.Form | |
(Formify a, Formify b, Formify c, Formify d, Formify e, Formify f) => Formify (a, b, c, d, e, f) Source # | |
Defined in FlexTask.Generic.Form |
Arguments
:: Formify a | |
=> Maybe a | Optional default value for form. |
-> [[FieldInfo]] | Structure of form. |
-> Rendered Widget | Rendered form. |
This is the main way to build generic forms.
Use in conjunction with FieldInfo
builders to generate a form.
Will fail if remaining FieldInfo
structure is not empty,
indicating the form is faulty.
Examples
Renders an input field with type=number attribute, no default value and label Age.
>>>
printWidget "en" $ formify (Nothing @Int) [[single "Age"]]
<div class="flex-form-div"> ... <label for="flexident1"> Age </label> <input id="flexident1" name="flex1" type="number" step="1" required="" value=""> ... </div>
Renders a series of four input fields, each for the type String and organized vertically beneath each other. They are prefilled with the values given above, are assigned the Css class "helloInput" and have no labels attached to them.
>>>
let defaults = ["Hallo", "Hello", "Hola", "Ciao"]
>>>
printWidget "en" $ formify (Just defaults) [[listWithoutLabels Vertical 4 [("class","helloInput")]]]
<div class="flex-form-div"> ... <input id="flexident1" name="flex1" type="text" ... value="Hallo" class="helloInput"> ... </div> <div class="flex-form-div"> ... <input id="flexident2" name="flex1" type="text" ... value="Hello" class="helloInput"> ... </div> <div class="flex-form-div"> ... <input id="flexident3" name="flex1" type="text" ... value="Hola" class="helloInput"> ... </div> <div class="flex-form-div"> ... <input id="flexident4" name="flex1" type="text" ... value="Ciao" class="helloInput"> ... </div>
Renders a radio button field with the given title and option labels attached. No option is selected when the form is loaded.
>>>
let labels = ["this one", "or rather that one", "I just cannot decide"]
>>>
printWidget "en" $ formify (Nothing @SingleChoiceSelection) [[buttons Vertical "Make your choice" labels]]
<div class="flex-form-div"> ... <label for="flexident1"> Make your choice </label> ... <label for="flexident1-1"> <div> <input id="flexident1-1" type="radio" ... value="1" ...> this one </div> </label> ... <label for="flexident1-2"> <div> <input id="flexident1-2" type="radio" ... value="2" ...> or rather that one </div> </label> ... <label for="flexident1-3"> <div> <input id="flexident1-3" type="radio" ... value="3" ...> I just cannot decide </div> </label> ... </div>
formifyComponentsFlat :: Formify a => Maybe a -> [FieldInfo] -> Rendered [Widget] Source #
like formifyComponents
, but takes a simple list of FieldInfo
values.
The sub-renders will also be returned as a flat list without any additional structure.
Anonymous Enum Type Builders and Accessors.
getAnswer :: SingleChoiceSelection -> Maybe Int Source #
Retrieve the selected option. Nothing
if none.
getAnswers :: MultipleChoiceSelection -> [Int] Source #
Retrieve the list of selected options. []
if none.
multipleChoiceAnswer :: [Int] -> MultipleChoiceSelection Source #
Value with given list of options selected. The order of list elements is inconsequential.
multipleChoiceEmpty :: MultipleChoiceSelection Source #
Value with no options selected.
singleChoiceAnswer :: Int -> SingleChoiceSelection Source #
Value with given number option selected.
singleChoiceEmpty :: SingleChoiceSelection Source #
Value with no option selected.
Field Builders
Arguments
:: Alignment | |
-> FieldSettings FlexForm | FieldSettings for option input |
-> [SomeMessage FlexForm] | Option labels |
-> FieldInfo |
Create FieldInfo for a button field.
Will turn into either radio buttons or checkboxes
depending on the form type.
Use with SingleChoiceSelection
or MultipleChoiceSelection
.
Do not use with custom enum types.
Use buttonsEnum
instead.
See SingleChoiceSelection
, MultipleChoiceSelection
for example use.
Arguments
:: (Bounded a, Enum a) | |
=> Alignment | |
-> FieldSettings FlexForm | FieldSettings for option input |
-> (a -> SomeMessage FlexForm) | Function from enum type values to labels. |
-> FieldInfo |
Same as buttons
, but using an explicit enum type.
Use this with custom enum types to automatically create labels
for all constructors according to the given showing scheme.
See formifyInstanceSingleChoice
, formifyInstanceMultiChoice
for example use.
Arguments
:: FieldSettings FlexForm | FieldSettings for select input |
-> [SomeMessage FlexForm] | Option labels |
-> FieldInfo |
Create FieldInfo for a dropdown menu field.
Will turn into either single or multiple selection field
depending on the form type.
Use with SingleChoiceSelection
or MultipleChoiceSelection
.
Do not use with custom enum types.
Use dropdownEnum
instead.
See SingleChoiceSelection
, MultipleChoiceSelection
for example use.
Arguments
:: (Bounded a, Enum a) | |
=> FieldSettings FlexForm | FieldSettings for select input |
-> (a -> SomeMessage FlexForm) | Function from enum type values to labels. |
-> FieldInfo |
Same as dropdown
, but using an explicit enum type.
Use this with custom enum types to automatically create labels
for all constructors according to the given showing scheme.
See formifyInstanceSingleChoice
, formifyInstanceMultiChoice
for example use.
Create FieldInfo for a number of fields. Their result will be handled as a list of values. The length of the list is equal to the amount of labels provided.
Example
>>>
let labels = ["Input 1", "Input 2", "Input 3"]
>>>
printWidget "en" $ formify (Nothing @[Double]) [[list Horizontal labels]]
<div class="flex-form-div"> ... <label for="flexident1"> Input 1 </label> <input id="flexident1" ... type="number" step="any" ...> ... <label for="flexident2"> Input 2 </label> <input id="flexident2" ... type="number" step="any" ...> ... <label for="flexident3"> Input 3 </label> <input id="flexident3" ... type="number" step="any" ...> ... </div>
single :: FieldSettings FlexForm -> FieldInfo Source #
Create FieldInfo for a standalone field.
See formify
for example use.
Formify Convenience Functions
formifyInstanceBasicField :: BaseForm a => Maybe a -> [[FieldInfo]] -> ([[FieldInfo]], [[Rendered Widget]]) Source #
Premade formifyImplementation
for types with BaseForm
instances.
Use within manual instances of Formify
.
Example
>>>
instance BaseForm MyCoolType where baseForm = convertField toCool fromCool basisField
>>>
instance Formify MyCoolType where formifyImplementation = formifyInstanceBasicField
formifyInstanceOptionalField :: BaseForm a => Maybe (Maybe a) -> [[FieldInfo]] -> ([[FieldInfo]], [[Rendered Widget]]) Source #
Same as formifyInstanceBasicField
, but for optional fields with Maybe
wrapping.
Example
>>>
instance BaseForm MyCoolType where baseForm = convertField toCool fromCool basisField
>>>
instance Formify (Maybe MyCoolType) where formifyImplementation = formifyInstanceOptionalField
formifyInstanceSingleChoice :: (Bounded a, Enum a, Eq a) => Maybe a -> [[FieldInfo]] -> ([[FieldInfo]], [[Rendered Widget]]) Source #
Premade formifyImplementation
for "single choice" forms of enum types.
Use within manual instances of Formify
.
Intended for use with types such as
data MyType = One | Two | Three deriving (Bounded, Enum, Eq, Show)
that cannot use a bodyless Formify
instance.
Examples
>>>
instance Formify MyType where formifyImplementation = formifyInstanceSingleChoice
>>>
printWidget "en" $ formify (Just Two) [[buttonsEnum Horizontal "Choose one" (showToUniversalLabel @MyType)]]
... <div class="flex-form-div"> ... <label for="flexident1"> Choose one </label> ... <label for="flexident1-1"> <input id="flexident1-1" type="radio" ... value="1" ...> One </label> <label for="flexident1-2"> <input id="flexident1-2" type="radio" ... value="2" checked ...> Two </label> <label for="flexident1-3"> <input id="flexident1-3" type="radio" ... value="3" ...> Three </label> ... </div>
>>>
printWidget "en" $ formify (Just Two) [[dropdownEnum "Choose one" (showToUniversalLabel @MyType)]]
<div class="flex-form-div"> ... <label for="flexident1"> Choose one </label> <select id="flexident1" ...> <option value="1"> One </option> <option value="2" selected> Two </option> <option value="3"> Three </option> </select> ... </div>
formifyInstanceMultiChoice :: (Bounded a, Enum a, Eq a) => Maybe [a] -> [[FieldInfo]] -> ([[FieldInfo]], [[Rendered Widget]]) Source #
Same as formifyInstanceSingleChoice
, but for multiple choice.
This means the rendered input form will accept any number of inputs, resulting in a list of values.
Possible builders to use with instances are buttonsEnum
(checkboxes) and dropdownEnum
(select list).
Examples
>>>
instance Formify [MyType] where formifyImplementation = formifyInstanceMultiChoice
>>>
printWidget "en" $ formify (Just [Two,Three]) [[buttonsEnum Horizontal "Choose" (showToUniversalLabel @MyType)]]
<div class="flex-form-div"> ... <label for="flexident1"> Choose </label> ... ... <label> <input type="checkbox" ... value="1"> One </label> <label> <input type="checkbox" ... value="2" checked> Two </label> <label> <input type="checkbox" ... value="3" checked> Three </label> ... </div>
>>>
printWidget "en" $ formify (Just [Two,Three]) [[dropdownEnum "Choose some" (showToUniversalLabel @MyType)]]
<div class="flex-form-div"> ... <label for="flexident1"> Choose some </label> <select id="flexident1" ... multiple> <option value="1"> One </option> <option value="2" selected> Two </option> <option value="3" selected> Three </option> </select> ... </div>