Safe Haskell | None |
---|---|
Language | Haskell2010 |
FlexTask.Generic.Form
Contents
Description
Generic Yesod
input form generation and related utility functions.
Synopsis
- list :: Alignment -> [FieldSettings FlexForm] -> FieldInfo
- 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]
- 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
- listWithoutLabels :: Alignment -> Int -> [(Text, Text)] -> FieldInfo
- repeatFieldInfo :: Alignment -> Int -> FieldInfo -> FieldInfo
- repeatBuilderOn :: Alignment -> (a -> FieldInfo) -> [a] -> 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]])
Documentation
Arguments
:: Alignment | |
-> [FieldSettings FlexForm] | FieldSettings of individual fields |
-> FieldInfo |
Create FieldInfo for a number of basic fields.
Their result will be handled as a list of values.
Use for lists of BaseForm fields like Int
, String
, Double
.
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>
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]] class="flex-form-div" ... for="flexident1" Choose one /label id="flexident1" ... value="1" First Option /option value="2" Second 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]]
class="flex-form-div"
...
for="flexident1"
Choose one
/label
id="flexident1" ... multiple
value="1" selected
First Option
/option
value="2" selected
Second Option
/option
value="3"
Third Option
/option
/select
...
/div
Instances
Generic MultipleChoiceSelection Source # | |||||
Defined in FlexTask.Generic.FormInternal Associated Types
Methods from :: MultipleChoiceSelection -> Rep MultipleChoiceSelection x # to :: Rep MultipleChoiceSelection x -> MultipleChoiceSelection # | |||||
Show MultipleChoiceSelection Source # | |||||
Defined in FlexTask.Generic.FormInternal Methods showsPrec :: Int -> MultipleChoiceSelection -> ShowS # show :: MultipleChoiceSelection -> String # showList :: [MultipleChoiceSelection] -> ShowS # | |||||
Formify MultipleChoiceSelection Source # | |||||
Defined in FlexTask.Generic.FormInternal 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.FormInternal Methods (==) :: MultipleChoiceSelection -> MultipleChoiceSelection -> Bool # (/=) :: MultipleChoiceSelection -> MultipleChoiceSelection -> Bool # | |||||
type Rep MultipleChoiceSelection Source # | |||||
Defined in FlexTask.Generic.FormInternal type Rep MultipleChoiceSelection = D1 ('MetaData "MultipleChoiceSelection" "FlexTask.Generic.FormInternal" "flex-tasks-0.1-FIJ46bsHvcADcfgfZQZUjI" '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 ""]] class="flex-form-div" ... for="flexident1" /label 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"]] class="flex-form-div" ... for="flexident1" Input comma separated sentences /label 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.FormInternal Methods showsPrec :: Int -> SingleInputList a -> ShowS # show :: SingleInputList a -> String # showList :: [SingleInputList a] -> ShowS # | |
Show a => BaseForm (SingleInputList a) Source # | |
Defined in FlexTask.Generic.FormInternal | |
Show a => Formify (SingleInputList a) Source # | |
Defined in FlexTask.Generic.FormInternal 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 | |
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.FormInternal Methods (==) :: SingleInputList a -> SingleInputList a -> Bool # (/=) :: SingleInputList a -> SingleInputList a -> Bool # |
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 # | |
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.FormInternal |
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.FormInternal Methods formifyImplementation :: Maybe MultipleChoiceSelection -> [[FieldInfo]] -> ([[FieldInfo]], Rendered [[Widget]]) Source # | |
Formify SingleChoiceSelection Source # | |
Defined in FlexTask.Generic.FormInternal Methods formifyImplementation :: Maybe SingleChoiceSelection -> [[FieldInfo]] -> ([[FieldInfo]], Rendered [[Widget]]) Source # | |
Formify Text Source # | |
Defined in FlexTask.Generic.FormInternal | |
Formify Textarea Source # | |
Defined in FlexTask.Generic.FormInternal | |
Formify String Source # | |
Defined in FlexTask.Generic.FormInternal | |
Formify Integer Source # | |
Defined in FlexTask.Generic.FormInternal | |
Formify Bool Source # | |
Defined in FlexTask.Generic.FormInternal | |
Formify Double Source # | |
Defined in FlexTask.Generic.FormInternal | |
Formify Int Source # | |
Defined in FlexTask.Generic.FormInternal | |
PathPiece a => Formify (Hidden a) Source # | |
Defined in FlexTask.Generic.FormInternal | |
Show a => Formify (SingleInputList a) Source # | |
Defined in FlexTask.Generic.FormInternal Methods formifyImplementation :: Maybe (SingleInputList a) -> [[FieldInfo]] -> ([[FieldInfo]], Rendered [[Widget]]) Source # | |
(BaseForm a, Formify a) => Formify (Maybe a) Source # | |
Defined in FlexTask.Generic.FormInternal | |
Formify [String] Source # | |
Defined in FlexTask.Generic.FormInternal | |
Formify (Maybe a) => Formify [Maybe a] Source # | |
Defined in FlexTask.Generic.FormInternal | |
(TypeError ('Text "Formify instances for nested lists are not supported." ':$$: 'Text "Please use a newtype or custom datatype instead.") :: Constraint) => Formify [[a]] Source # | |
Defined in FlexTask.Generic.Form | |
Formify a => Formify [a] Source # | |
Defined in FlexTask.Generic.FormInternal | |
(Formify a, Formify b) => Formify (a, b) Source # | |
Defined in FlexTask.Generic.FormInternal | |
(Formify a, Formify b, Formify c) => Formify (a, b, c) Source # | |
Defined in FlexTask.Generic.FormInternal | |
(Formify a, Formify b, Formify c, Formify d) => Formify (a, b, c, d) Source # | |
Defined in FlexTask.Generic.FormInternal | |
(Formify a, Formify b, Formify c, Formify d, Formify e) => Formify (a, b, c, d, e) Source # | |
Defined in FlexTask.Generic.FormInternal | |
(Formify a, Formify b, Formify c, Formify d, Formify e, Formify f) => Formify (a, b, c, d, e, f) Source # | |
Defined in FlexTask.Generic.FormInternal |
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" ... type="text" ... value="Hallo" class="helloInput"> ... </div> <div class="flex-form-div"> ... <input id="flexident2" ... type="text" ... value="Hello" class="helloInput"> ... </div> <div class="flex-form-div"> ... <input id="flexident3" ... type="text" ... value="Hola" class="helloInput"> ... </div> <div class="flex-form-div"> ... <input id="flexident4" ... 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.
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.
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 list containing exact copies the specified field. The results of the copies will be handled as a list of values. Use to render lists of dropdown or button fields with identical labels.
Arguments
:: Alignment | |
-> (a -> FieldInfo) | FieldInfo builder to use |
-> [a] | List of values to use builder on |
-> FieldInfo |
Create FieldInfo for a number of arbitrary fields. Takes the builder to repeatedly use for each field and a list of values to use it on. Their result will be handled as a list of values. Use to render lists of dropdown or button fields with different labels.
single :: FieldSettings FlexForm -> FieldInfo Source #
Create FieldInfo for a standalone field.
See formify
for example use.
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>