elm-pages 3.0.0-beta.32 → 3.0.0-beta.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +1 -1
  2. package/codegen/elm-pages-codegen.cjs +10 -78
  3. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  4. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  5. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
  6. package/generator/dead-code-review/elm.json +1 -1
  7. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  8. package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  9. package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
  10. package/generator/review/elm.json +1 -1
  11. package/generator/src/RouteBuilder.elm +2 -2
  12. package/generator/src/compatibility-key.js +2 -2
  13. package/generator/src/render.js +1 -0
  14. package/generator/src/request-cache.js +20 -6
  15. package/generator/static-code/elm-pages.js +10 -0
  16. package/package.json +3 -3
  17. package/src/BackendTask/Http.elm +8 -2
  18. package/src/Internal/Field.elm +19 -0
  19. package/src/Internal/Input.elm +81 -0
  20. package/src/Pages/Form.elm +229 -0
  21. package/src/Pages/Internal/Msg.elm +70 -61
  22. package/src/Pages/Internal/Platform/Cli.elm +423 -425
  23. package/src/Pages/Internal/Platform/CompatibilityKey.elm +1 -1
  24. package/src/Pages/Internal/Platform/GeneratorApplication.elm +1 -5
  25. package/src/Pages/Internal/Platform.elm +119 -100
  26. package/src/Pages/ProgramConfig.elm +12 -5
  27. package/src/Pages/StaticHttpRequest.elm +0 -1
  28. package/src/Pages/Transition.elm +9 -1
  29. package/src/PagesMsg.elm +0 -10
  30. package/src/RequestsAndPending.elm +31 -3
  31. package/src/Scaffold/Form.elm +9 -9
  32. package/src/Server/Request.elm +57 -61
  33. package/src/Form/Field.elm +0 -729
  34. package/src/Form/FieldStatus.elm +0 -36
  35. package/src/Form/FieldView.elm +0 -497
  36. package/src/Form/FormData.elm +0 -22
  37. package/src/Form/Validation.elm +0 -391
  38. package/src/Form/Value.elm +0 -118
  39. package/src/Form.elm +0 -1558
  40. package/src/FormDecoder.elm +0 -102
  41. package/src/Pages/FormState.elm +0 -257
  42. package/src/Pages/Internal/Form.elm +0 -37
package/src/Form.elm DELETED
@@ -1,1558 +0,0 @@
1
- module Form exposing
2
- ( Form, HtmlForm, StyledHtmlForm, DoneForm
3
- , Response
4
- , init
5
- , field, hiddenField, hiddenKind
6
- , Context
7
- , renderHtml, renderStyledHtml
8
- , withGetMethod, toDynamicFetcher
9
- , Errors, errorsForField
10
- , parse, runServerSide, runOneOfServerSide
11
- , ServerForms(..)
12
- , initCombined, combine, initCombinedServer, combineServer
13
- , dynamic
14
- , AppContext
15
- , toServerForm, withOnSubmit
16
- -- subGroup
17
- )
18
-
19
- {-| One of the core features of elm-pages is helping you manage form data end-to-end, including
20
-
21
- - Presenting the HTML form with its fields
22
- - Maintaining client-side form state
23
- - Showing validation errors on the client-side
24
- - Receiving a form submission on the server-side
25
- - Using the exact same client-side validations on the server-side
26
- - Letting you run server-only Validations with BackendTask's (things like checking for a unique username)
27
-
28
- Because elm-pages is a framework, it has its own internal Model and Msg's. That means you, the user,
29
- can offload some of the responsibility to elm-pages and build an interactive form with real-time
30
- client-side state and validation errors without wiring up your own Model and Msg's to manage that
31
- state. You define the source of truth for your form (how to parse it into data or errors), and
32
- elm-pages manages the state.
33
-
34
- Let's look at a sign-up form example.
35
-
36
-
37
- ### Step 1 - Define the Form
38
-
39
- What to look for:
40
-
41
- **The field declarations**
42
-
43
- Below the `Form.init` call you will find all of the form's fields declared with
44
-
45
- |> Form.field ...
46
-
47
- These are the form's field declarations.
48
-
49
- These fields each have individual validations. For example, `|> Field.required ...` means we'll get a validation
50
- error if that field is empty (similar for checking the minimum password length).
51
-
52
- There will be a corresponding parameter in the function we pass in to `Form.init` for every
53
- field declaration (in this example, `\email password passwordConfirmation -> ...`).
54
-
55
- **The `combine` validation**
56
-
57
- In addition to the validation errors that individual fields can have independently (like
58
- required fields or minimum password length), we can also do _dependent validations_.
59
-
60
- We use the [`Form.Validation`](Form-Validation) module to take each individual field and combine
61
- them into a type and/or errors.
62
-
63
- **The `view`**
64
-
65
- Totally customizable. Uses [`Form.FieldView`](Form-FieldView) to render all of the fields declared.
66
-
67
- import BackendTask exposing (BackendTask)
68
- import ErrorPage exposing (ErrorPage)
69
- import Form
70
- import Form.Field as Field
71
- import Form.FieldView as FieldView
72
- import Form.Validation as Validation
73
- import Html exposing (Html)
74
- import Html.Attributes as Attr
75
- import Route
76
- import Server.Request as Request
77
- import Server.Response exposing (Response)
78
-
79
- type alias NewUser =
80
- { email : String
81
- , password : String
82
- }
83
-
84
- signupForm : Form.HtmlForm String NewUser () Msg
85
- signupForm =
86
- Form.init
87
- (\email password passwordConfirmation ->
88
- { combine =
89
- Validation.succeed Login
90
- |> Validation.andMap email
91
- |> Validation.andMap
92
- (Validation.map2
93
- (\pass confirmation ->
94
- if pass == confirmation then
95
- Validation.succeed pass
96
-
97
- else
98
- passwordConfirmation
99
- |> Validation.fail
100
- "Must match password"
101
- )
102
- password
103
- passwordConfirmation
104
- |> Validation.andThen identity
105
- )
106
- , view =
107
- \info ->
108
- [ Html.label []
109
- [ fieldView info "Email" email
110
- , fieldView info "Password" password
111
- , fieldView info "Confirm Password" passwordConfirmation
112
- ]
113
- , Html.button []
114
- [ if info.isTransitioning then
115
- Html.text "Signing Up..."
116
-
117
- else
118
- Html.text "Sign Up"
119
- ]
120
- ]
121
- }
122
- )
123
- |> Form.field "email"
124
- (Field.text
125
- |> Field.required "Required"
126
- )
127
- |> Form.field "password"
128
- passwordField
129
- |> Form.field "passwordConfirmation"
130
- passwordField
131
-
132
- passwordField =
133
- Field.text
134
- |> Field.password
135
- |> Field.required "Required"
136
- |> Field.withClientValidation
137
- (\password ->
138
- ( Just password
139
- , if String.length password < 4 then
140
- [ "Must be at least 4 characters" ]
141
-
142
- else
143
- []
144
- )
145
- )
146
-
147
- fieldView :
148
- Form.Context String data
149
- -> String
150
- -> Validation.Field String parsed FieldView.Input
151
- -> Html msg
152
- fieldView formState label field =
153
- Html.div []
154
- [ Html.label []
155
- [ Html.text (label ++ " ")
156
- , field |> Form.FieldView.input []
157
- ]
158
- , (if formState.submitAttempted then
159
- formState.errors
160
- |> Form.errorsForField field
161
- |> List.map
162
- (\error ->
163
- Html.li [] [ Html.text error ]
164
- )
165
-
166
- else
167
- []
168
- )
169
- |> Html.ul [ Attr.style "color" "red" ]
170
- ]
171
-
172
-
173
- ### Step 2 - Render the Form's View
174
-
175
- view maybeUrl sharedModel app =
176
- { title = "Sign Up"
177
- , body =
178
- [ form
179
- |> Form.renderHtml "login" [] Nothing app ()
180
- ]
181
- }
182
-
183
-
184
- ### Step 3 - Handle Server-Side Form Submissions
185
-
186
- action : RouteParams -> Request.Parser (BackendTask (Response ActionData ErrorPage))
187
- action routeParams =
188
- Request.formData [ signupForm ]
189
- |> Request.map
190
- (\signupResult ->
191
- case signupResult of
192
- Ok newUser ->
193
- newUser
194
- |> myCreateUserBackendTask
195
- |> BackendTask.map
196
- (\() ->
197
- -- redirect to the home page
198
- -- after successful sign-up
199
- Route.redirectTo Route.Index
200
- )
201
-
202
- Err _ ->
203
- Route.redirectTo Route.Login
204
- |> BackendTask.succeed
205
- )
206
-
207
- myCreateUserBackendTask : BackendTask ()
208
- myCreateUserBackendTask =
209
- BackendTask.fail
210
- "TODO - make a database call to create a new user"
211
-
212
-
213
- ## Building a Form Parser
214
-
215
- @docs Form, HtmlForm, StyledHtmlForm, DoneForm
216
-
217
- @docs Response
218
-
219
- @docs init
220
-
221
-
222
- ## Adding Fields
223
-
224
- @docs field, hiddenField, hiddenKind
225
-
226
-
227
- ## View Functions
228
-
229
- @docs Context
230
-
231
-
232
- ## Rendering Forms
233
-
234
- @docs renderHtml, renderStyledHtml
235
-
236
- @docs withGetMethod, toDynamicFetcher
237
-
238
-
239
- ## Showing Errors
240
-
241
- @docs Errors, errorsForField
242
-
243
-
244
- ## Running Parsers
245
-
246
- @docs parse, runServerSide, runOneOfServerSide
247
-
248
-
249
- ## Combining Forms to Run on Server
250
-
251
- @docs ServerForms
252
-
253
- @docs initCombined, combine, initCombinedServer, combineServer
254
-
255
-
256
- ## Dynamic Fields
257
-
258
- @docs dynamic
259
-
260
- @docs AppContext
261
-
262
-
263
- ## Submission
264
-
265
- @docs toServerForm, withOnSubmit
266
-
267
- -}
268
-
269
- import BackendTask exposing (BackendTask)
270
- import Dict exposing (Dict)
271
- import FatalError exposing (FatalError)
272
- import Form.Field as Field exposing (Field(..))
273
- import Form.FieldStatus as FieldStatus exposing (FieldStatus)
274
- import Form.FieldView
275
- import Form.Validation exposing (Combined)
276
- import Html exposing (Html)
277
- import Html.Attributes as Attr
278
- import Html.Lazy
279
- import Html.Styled
280
- import Html.Styled.Attributes as StyledAttr
281
- import Html.Styled.Lazy
282
- import Pages.FormState as Form exposing (FormState)
283
- import Pages.Internal.Form exposing (Validation(..), unwrapResponse)
284
- import Pages.Internal.Msg
285
- import Pages.Transition exposing (Transition(..))
286
- import PagesMsg exposing (PagesMsg)
287
- import Path exposing (Path)
288
-
289
-
290
- {-| -}
291
- initFormState : FormState
292
- initFormState =
293
- { fields = Dict.empty
294
- , submitAttempted = False
295
- }
296
-
297
-
298
- {-| -}
299
- type alias Context error data =
300
- { errors : Errors error
301
- , isTransitioning : Bool
302
- , submitAttempted : Bool
303
- , data : data
304
- }
305
-
306
-
307
- {-| -}
308
- init : combineAndView -> Form String combineAndView data msg
309
- init combineAndView =
310
- Form
311
- { submitStrategy = TransitionStrategy
312
- , method = Post
313
- , onSubmit = Nothing
314
- }
315
- []
316
- (\_ _ ->
317
- { result = Dict.empty
318
- , combineAndView = combineAndView
319
- , isMatchCandidate = True
320
- }
321
- )
322
- (\_ -> [])
323
-
324
-
325
- {-| -}
326
- dynamic :
327
- (decider
328
- ->
329
- Form
330
- error
331
- { combine : Form.Validation.Validation error parsed named constraints1
332
- , view : subView
333
- }
334
- data
335
- msg
336
- )
337
- ->
338
- Form
339
- error
340
- --((decider -> Validation error parsed named) -> combined)
341
- ({ combine : decider -> Form.Validation.Validation error parsed named constraints1
342
- , view : decider -> subView
343
- }
344
- -> combineAndView
345
- )
346
- data
347
- msg
348
- ->
349
- Form
350
- error
351
- combineAndView
352
- data
353
- msg
354
- dynamic forms formBuilder =
355
- Form
356
- { submitStrategy = TransitionStrategy
357
- , method = Post
358
- , onSubmit = Nothing
359
- }
360
- []
361
- (\maybeData formState ->
362
- let
363
- toParser :
364
- decider
365
- ->
366
- { result : Dict String (List error)
367
- , isMatchCandidate : Bool
368
- , combineAndView : { combine : Validation error parsed named constraints1, view : subView }
369
- }
370
- toParser decider =
371
- case forms decider of
372
- Form _ _ parseFn _ ->
373
- -- TODO need to include hidden form fields from `definitions` (should they be automatically rendered? Does that mean the view type needs to be hardcoded?)
374
- parseFn maybeData formState
375
-
376
- myFn :
377
- { result : Dict String (List error)
378
- , isMatchCandidate : Bool
379
- , combineAndView : combineAndView
380
- }
381
- myFn =
382
- let
383
- newThing :
384
- { result : Dict String (List error)
385
- , isMatchCandidate : Bool
386
- , combineAndView : { combine : decider -> Validation error parsed named constraints1, view : decider -> subView } -> combineAndView
387
- }
388
- newThing =
389
- case formBuilder of
390
- Form _ _ parseFn _ ->
391
- parseFn maybeData formState
392
-
393
- arg : { combine : decider -> Validation error parsed named constraints1, view : decider -> subView }
394
- arg =
395
- { combine =
396
- toParser
397
- >> .combineAndView
398
- >> .combine
399
- , view =
400
- \decider ->
401
- decider
402
- |> toParser
403
- |> .combineAndView
404
- |> .view
405
- }
406
- in
407
- { result =
408
- newThing.result
409
- , combineAndView =
410
- newThing.combineAndView arg
411
- , isMatchCandidate = newThing.isMatchCandidate
412
- }
413
- in
414
- myFn
415
- )
416
- (\_ -> [])
417
-
418
-
419
-
420
- --{-| -}
421
- --subGroup :
422
- -- Form error ( Maybe parsed, Dict String (List error) ) data (Context error data -> subView)
423
- -- ->
424
- -- Form
425
- -- error
426
- -- ({ value : parsed } -> combined)
427
- -- data
428
- -- (Context error data -> (subView -> combinedView))
429
- -- -> Form error combined data (Context error data -> combinedView)
430
- --subGroup forms formBuilder =
431
- -- Form []
432
- -- (\maybeData formState ->
433
- -- let
434
- -- toParser : { result : ( Maybe ( Maybe parsed, Dict String (List error) ), Dict String (List error) ), view : Context error data -> subView }
435
- -- toParser =
436
- -- case forms of
437
- -- Form definitions parseFn toInitialValues ->
438
- -- -- TODO need to include hidden form fields from `definitions` (should they be automatically rendered? Does that mean the view type needs to be hardcoded?)
439
- -- parseFn maybeData formState
440
- --
441
- -- myFn :
442
- -- { result : ( Maybe combined, Dict String (List error) )
443
- -- , view : Context error data -> combinedView
444
- -- }
445
- -- myFn =
446
- -- let
447
- -- deciderToParsed : ( Maybe parsed, Dict String (List error) )
448
- -- deciderToParsed =
449
- -- toParser |> mergeResults
450
- --
451
- -- newThing : { result : ( Maybe ({ value : parsed } -> combined), Dict String (List error) ), view : Context error data -> subView -> combinedView }
452
- -- newThing =
453
- -- case formBuilder of
454
- -- Form definitions parseFn toInitialValues ->
455
- -- parseFn maybeData formState
456
- --
457
- -- anotherThing : Maybe combined
458
- -- anotherThing =
459
- -- Maybe.map2
460
- -- (\runFn parsed ->
461
- -- runFn { value = parsed }
462
- -- )
463
- -- (Tuple.first newThing.result)
464
- -- (deciderToParsed |> Tuple.first)
465
- -- in
466
- -- { result =
467
- -- ( anotherThing
468
- -- , mergeErrors (newThing.result |> Tuple.second)
469
- -- (deciderToParsed |> Tuple.second)
470
- -- )
471
- -- , view =
472
- -- \fieldErrors ->
473
- -- let
474
- -- something2 : subView
475
- -- something2 =
476
- -- fieldErrors
477
- -- |> (toParser
478
- -- |> .view
479
- -- )
480
- -- in
481
- -- newThing.view fieldErrors something2
482
- -- }
483
- -- in
484
- -- myFn
485
- -- )
486
- -- (\_ -> [])
487
-
488
-
489
- {-| Declare a visible field for the form.
490
-
491
- Use [`Form.Field`](Form-Field) to define the field and its validations.
492
-
493
- form =
494
- Form.init
495
- (\email ->
496
- { combine =
497
- Validation.succeed NewUser
498
- |> Validation.andMap email
499
- , view = \info -> [{- render fields -}]
500
- }
501
- )
502
- |> Form.field "email"
503
- (Field.text |> Field.required "Required")
504
-
505
- -}
506
- field :
507
- String
508
- -> Field error parsed data kind constraints
509
- -> Form error (Form.Validation.Field error parsed kind -> combineAndView) data msg
510
- -> Form error combineAndView data msg
511
- field name (Field fieldParser kind) (Form renderOptions definitions parseFn toInitialValues) =
512
- Form renderOptions
513
- (( name, RegularField )
514
- :: definitions
515
- )
516
- (\maybeData formState ->
517
- let
518
- ( maybeParsed, errors ) =
519
- -- @@@@@@ use code from here
520
- fieldParser.decode rawFieldValue
521
-
522
- ( rawFieldValue, fieldStatus ) =
523
- case formState.fields |> Dict.get name of
524
- Just info ->
525
- ( Just info.value, info.status )
526
-
527
- Nothing ->
528
- ( Maybe.map2 (|>) maybeData fieldParser.initialValue |> Maybe.andThen identity, FieldStatus.NotVisited )
529
-
530
- thing : Pages.Internal.Form.ViewField kind
531
- thing =
532
- { value = rawFieldValue
533
- , status = fieldStatus
534
- , kind = ( kind, fieldParser.properties )
535
- }
536
-
537
- parsedField : Form.Validation.Field error parsed kind
538
- parsedField =
539
- Pages.Internal.Form.Validation (Just thing) (Just name) ( maybeParsed, Dict.empty )
540
-
541
- myFn :
542
- { result : Dict String (List error)
543
- , combineAndView : Form.Validation.Field error parsed kind -> combineAndView
544
- , isMatchCandidate : Bool
545
- }
546
- ->
547
- { result : Dict String (List error)
548
- , combineAndView : combineAndView
549
- , isMatchCandidate : Bool
550
- }
551
- myFn soFar =
552
- let
553
- validationField : Form.Validation.Field error parsed kind
554
- validationField =
555
- parsedField
556
- in
557
- { result =
558
- soFar.result
559
- |> addErrorsInternal name errors
560
- , combineAndView =
561
- soFar.combineAndView validationField
562
- , isMatchCandidate = soFar.isMatchCandidate
563
- }
564
- in
565
- formState
566
- |> parseFn maybeData
567
- |> myFn
568
- )
569
- (\data ->
570
- case fieldParser.initialValue of
571
- Just toInitialValue ->
572
- ( name, toInitialValue data )
573
- :: toInitialValues data
574
-
575
- Nothing ->
576
- toInitialValues data
577
- )
578
-
579
-
580
- {-| Declare a hidden field for the form.
581
-
582
- Unlike [`field`](#field) declarations which are rendered using [`Form.FieldView`](Form-FieldView)
583
- functions, `hiddenField` inputs are automatically inserted into the form when you render it.
584
-
585
- You define the field's validations the same way as for `field`, with the
586
- [`Form.Field`](Form-Field) API.
587
-
588
- form =
589
- Form.init
590
- (\quantity productId ->
591
- { combine = {- combine fields -}
592
- , view = \info -> [{- render visible fields -}]
593
- }
594
- )
595
- |> Form.field "quantity"
596
- (Field.int |> Field.required "Required")
597
- |> Form.field "productId"
598
- (Field.text
599
- |> Field.required "Required"
600
- |> Field.withInitialValue (\product -> Form.Value.string product.id)
601
- )
602
-
603
- -}
604
- hiddenField :
605
- String
606
- -> Field error parsed data kind constraints
607
- -> Form error (Form.Validation.Field error parsed Form.FieldView.Hidden -> combineAndView) data msg
608
- -> Form error combineAndView data msg
609
- hiddenField name (Field fieldParser _) (Form options definitions parseFn toInitialValues) =
610
- Form options
611
- (( name, HiddenField )
612
- :: definitions
613
- )
614
- (\maybeData formState ->
615
- let
616
- ( maybeParsed, errors ) =
617
- fieldParser.decode rawFieldValue
618
-
619
- ( rawFieldValue, fieldStatus ) =
620
- case formState.fields |> Dict.get name of
621
- Just info ->
622
- ( Just info.value, info.status )
623
-
624
- Nothing ->
625
- ( Maybe.map2 (|>) maybeData fieldParser.initialValue |> Maybe.andThen identity, FieldStatus.NotVisited )
626
-
627
- thing : Pages.Internal.Form.ViewField Form.FieldView.Hidden
628
- thing =
629
- { value = rawFieldValue
630
- , status = fieldStatus
631
- , kind = ( Form.FieldView.Hidden, fieldParser.properties )
632
- }
633
-
634
- parsedField : Form.Validation.Field error parsed Form.FieldView.Hidden
635
- parsedField =
636
- Pages.Internal.Form.Validation (Just thing) (Just name) ( maybeParsed, Dict.empty )
637
-
638
- myFn :
639
- { result : Dict String (List error)
640
- , combineAndView : Form.Validation.Field error parsed Form.FieldView.Hidden -> combineAndView
641
- , isMatchCandidate : Bool
642
- }
643
- ->
644
- { result : Dict String (List error)
645
- , combineAndView : combineAndView
646
- , isMatchCandidate : Bool
647
- }
648
- myFn soFar =
649
- let
650
- validationField : Form.Validation.Field error parsed Form.FieldView.Hidden
651
- validationField =
652
- parsedField
653
- in
654
- { result =
655
- soFar.result
656
- |> addErrorsInternal name errors
657
- , combineAndView =
658
- soFar.combineAndView validationField
659
- , isMatchCandidate = soFar.isMatchCandidate
660
- }
661
- in
662
- formState
663
- |> parseFn maybeData
664
- |> myFn
665
- )
666
- (\data ->
667
- case fieldParser.initialValue of
668
- Just toInitialValue ->
669
- ( name, toInitialValue data )
670
- :: toInitialValues data
671
-
672
- Nothing ->
673
- toInitialValues data
674
- )
675
-
676
-
677
- {-| -}
678
- toServerForm :
679
- Form
680
- error
681
- { combine : Form.Validation.Validation error combined kind constraints
682
- , view : viewFn
683
- }
684
- data
685
- msg
686
- ->
687
- Form
688
- error
689
- { combine : Form.Validation.Validation error (BackendTask FatalError (Form.Validation.Validation error combined kind constraints)) kind constraints
690
- , view : viewFn
691
- }
692
- data
693
- msg
694
- toServerForm (Form options a b c) =
695
- let
696
- mappedB :
697
- Maybe data
698
- -> FormState
699
- ->
700
- { result : Dict String (List error)
701
- , isMatchCandidate : Bool
702
- , combineAndView :
703
- { combine : Form.Validation.Validation error (BackendTask FatalError (Form.Validation.Validation error combined kind constraints)) kind constraints
704
- , view : viewFn
705
- }
706
- }
707
- mappedB maybeData formState =
708
- b maybeData formState
709
- |> (\thing ->
710
- { result = thing.result
711
- , combineAndView =
712
- { combine =
713
- thing.combineAndView.combine
714
- |> BackendTask.succeed
715
- |> Form.Validation.succeed2
716
- , view = thing.combineAndView.view
717
- }
718
- , isMatchCandidate = thing.isMatchCandidate
719
- }
720
- )
721
- in
722
- Form options a mappedB c
723
-
724
-
725
- {-| -}
726
- hiddenKind :
727
- ( String, String )
728
- -> error
729
- -> Form error combineAndView data msg
730
- -> Form error combineAndView data msg
731
- hiddenKind ( name, value ) error_ (Form options definitions parseFn toInitialValues) =
732
- let
733
- (Field fieldParser _) =
734
- Field.exactValue value error_
735
- in
736
- Form options
737
- (( name, HiddenField )
738
- :: definitions
739
- )
740
- (\maybeData formState ->
741
- let
742
- ( decodedValue, errors ) =
743
- fieldParser.decode rawFieldValue
744
-
745
- rawFieldValue : Maybe String
746
- rawFieldValue =
747
- case formState.fields |> Dict.get name of
748
- Just info ->
749
- Just info.value
750
-
751
- Nothing ->
752
- Maybe.map2 (|>) maybeData fieldParser.initialValue
753
- |> Maybe.andThen identity
754
-
755
- myFn :
756
- { result : Dict String (List error)
757
- , isMatchCandidate : Bool
758
- , combineAndView : combineAndView
759
- }
760
- ->
761
- { result : Dict String (List error)
762
- , isMatchCandidate : Bool
763
- , combineAndView : combineAndView
764
- }
765
- myFn soFar =
766
- { result =
767
- soFar.result
768
- |> addErrorsInternal name errors
769
- , combineAndView = soFar.combineAndView
770
- , isMatchCandidate = soFar.isMatchCandidate && decodedValue == Just value
771
- }
772
- in
773
- formState
774
- |> parseFn maybeData
775
- |> myFn
776
- )
777
- (\data ->
778
- case fieldParser.initialValue of
779
- Just toInitialValue ->
780
- ( name, toInitialValue data )
781
- :: toInitialValues data
782
-
783
- Nothing ->
784
- toInitialValues data
785
- )
786
-
787
-
788
- {-| -}
789
- type Errors error
790
- = Errors (Dict String (List error))
791
-
792
-
793
- {-| -}
794
- errorsForField : Form.Validation.Field error parsed kind -> Errors error -> List error
795
- errorsForField field_ (Errors errorsDict) =
796
- errorsDict
797
- |> Dict.get (Form.Validation.fieldName field_)
798
- |> Maybe.withDefault []
799
-
800
-
801
- {-| -}
802
- type alias AppContext app actionData =
803
- { app
804
- | --, sharedData : Shared.Data
805
- --, routeParams : routeParams
806
- path : Path
807
- , action : Maybe actionData
808
-
809
- --, submit :
810
- -- { fields : List ( String, String ), headers : List ( String, String ) }
811
- -- -> Pages.Fetcher.Fetcher (Result Http.Error action)
812
- , transition : Maybe Transition
813
- , fetchers : Dict String (Pages.Transition.FetcherState (Maybe actionData))
814
- , pageFormState :
815
- Dict String { fields : Dict String { value : String, status : FieldStatus }, submitAttempted : Bool }
816
- }
817
-
818
-
819
- mergeResults :
820
- { a | result : ( Validation error parsed named constraints1, Dict String (List error) ) }
821
- -> Validation error parsed unnamed constraints2
822
- mergeResults parsed =
823
- case parsed.result of
824
- ( Pages.Internal.Form.Validation _ name ( parsedThing, combineErrors ), individualFieldErrors ) ->
825
- Pages.Internal.Form.Validation Nothing
826
- name
827
- ( parsedThing
828
- , mergeErrors combineErrors individualFieldErrors
829
- )
830
-
831
-
832
- mergeErrors : Dict comparable (List value) -> Dict comparable (List value) -> Dict comparable (List value)
833
- mergeErrors errors1 errors2 =
834
- Dict.merge
835
- (\key entries soFar ->
836
- soFar |> insertIfNonempty key entries
837
- )
838
- (\key entries1 entries2 soFar ->
839
- soFar |> insertIfNonempty key (entries1 ++ entries2)
840
- )
841
- (\key entries soFar ->
842
- soFar |> insertIfNonempty key entries
843
- )
844
- errors1
845
- errors2
846
- Dict.empty
847
-
848
-
849
- {-| -}
850
- parse :
851
- String
852
- -> AppContext app actionData
853
- -> data
854
- -> Form error { info | combine : Form.Validation.Validation error parsed named constraints } data msg
855
- -> ( Maybe parsed, Dict String (List error) )
856
- parse formId app data (Form _ _ parser _) =
857
- -- TODO Get transition context from `app` so you can check if the current form is being submitted
858
- -- TODO either as a transition or a fetcher? Should be easy enough to check for the `id` on either of those?
859
- let
860
- parsed :
861
- { result : Dict String (List error)
862
- , isMatchCandidate : Bool
863
- , combineAndView : { info | combine : Validation error parsed named constraints }
864
- }
865
- parsed =
866
- parser (Just data) thisFormState
867
-
868
- thisFormState : FormState
869
- thisFormState =
870
- app.pageFormState
871
- |> Dict.get formId
872
- |> Maybe.withDefault initFormState
873
- in
874
- { result = ( parsed.combineAndView.combine, parsed.result )
875
- }
876
- |> mergeResults
877
- |> unwrapValidation
878
-
879
-
880
- insertIfNonempty : comparable -> List value -> Dict comparable (List value) -> Dict comparable (List value)
881
- insertIfNonempty key values dict =
882
- if values |> List.isEmpty then
883
- dict
884
-
885
- else
886
- dict
887
- |> Dict.insert key values
888
-
889
-
890
- {-| -}
891
- runServerSide :
892
- List ( String, String )
893
- -> Form error (Form.Validation.Validation error parsed kind constraints) data msg
894
- -> ( Bool, ( Maybe parsed, Dict String (List error) ) )
895
- runServerSide rawFormData (Form _ _ parser _) =
896
- let
897
- parsed :
898
- { result : Dict String (List error)
899
- , isMatchCandidate : Bool
900
- , combineAndView : Validation error parsed kind constraints
901
- }
902
- parsed =
903
- parser Nothing thisFormState
904
-
905
- thisFormState : FormState
906
- thisFormState =
907
- { initFormState
908
- | fields =
909
- rawFormData
910
- |> List.map
911
- (Tuple.mapSecond
912
- (\value ->
913
- { value = value
914
- , status = FieldStatus.NotVisited
915
- }
916
- )
917
- )
918
- |> Dict.fromList
919
- }
920
- in
921
- ( parsed.isMatchCandidate
922
- , { result = ( parsed.combineAndView, parsed.result )
923
- }
924
- |> mergeResults
925
- |> unwrapValidation
926
- )
927
-
928
-
929
- unwrapValidation : Validation error parsed named constraints -> ( Maybe parsed, Dict String (List error) )
930
- unwrapValidation (Pages.Internal.Form.Validation _ _ ( maybeParsed, errors )) =
931
- ( maybeParsed, errors )
932
-
933
-
934
- {-| -}
935
- runOneOfServerSide :
936
- List ( String, String )
937
- -> ServerForms error parsed
938
- -> ( Maybe parsed, Dict String (List error) )
939
- runOneOfServerSide rawFormData forms =
940
- runOneOfServerSideHelp rawFormData Nothing forms
941
-
942
-
943
- {-| -}
944
- runOneOfServerSideHelp :
945
- List ( String, String )
946
- -> Maybe (List ( String, List error ))
947
- -> ServerForms error parsed
948
- -> ( Maybe parsed, Dict String (List error) )
949
- runOneOfServerSideHelp rawFormData firstFoundErrors (ServerForms parsers) =
950
- case parsers of
951
- firstParser :: remainingParsers ->
952
- let
953
- ( isMatchCandidate, thing1 ) =
954
- runServerSide rawFormData firstParser
955
-
956
- thing : ( Maybe parsed, List ( String, List error ) )
957
- thing =
958
- thing1
959
- |> Tuple.mapSecond
960
- (\errors ->
961
- errors
962
- |> Dict.toList
963
- |> List.filter (Tuple.second >> List.isEmpty >> not)
964
- )
965
- in
966
- case ( isMatchCandidate, thing ) of
967
- ( True, ( Just parsed, errors ) ) ->
968
- ( Just parsed, errors |> Dict.fromList )
969
-
970
- ( _, ( _, errors ) ) ->
971
- runOneOfServerSideHelp rawFormData
972
- (firstFoundErrors
973
- -- TODO is this logic what we want here? Might need to think through the semantics a bit more
974
- -- of which errors to parse into - could be the first errors, the last, or some other way of
975
- -- having higher precedence for deciding which form should be used
976
- |> Maybe.withDefault errors
977
- |> Just
978
- )
979
- (ServerForms remainingParsers)
980
-
981
- [] ->
982
- -- TODO need to pass errors
983
- ( Nothing, firstFoundErrors |> Maybe.withDefault [] |> Dict.fromList )
984
-
985
-
986
- {-| -}
987
- renderHtml :
988
- String
989
- -> List (Html.Attribute (PagesMsg msg))
990
- -> (actionData -> Maybe (Response error))
991
- -> AppContext app actionData
992
- -> input
993
- ->
994
- Form
995
- error
996
- { combine : Form.Validation.Validation error parsed named constraints
997
- , view : Context error input -> List (Html (PagesMsg msg))
998
- }
999
- input
1000
- msg
1001
- -> Html (PagesMsg msg)
1002
- renderHtml formId attrs accessResponse app data form =
1003
- Html.Lazy.lazy6 renderHelper formId attrs accessResponse app data form
1004
-
1005
-
1006
- {-| -}
1007
- toDynamicFetcher :
1008
- Form
1009
- error
1010
- { combine : Form.Validation.Validation error parsed field constraints
1011
- , view : Context error data -> view
1012
- }
1013
- data
1014
- userMsg
1015
- ->
1016
- Form
1017
- error
1018
- { combine : Form.Validation.Validation error parsed field constraints
1019
- , view : Context error data -> view
1020
- }
1021
- data
1022
- userMsg
1023
- toDynamicFetcher (Form renderOptions a b c) =
1024
- Form { renderOptions | submitStrategy = FetcherStrategy } a b c
1025
-
1026
-
1027
- {-| -}
1028
- withGetMethod : Form error combineAndView input userMsg -> Form error combineAndView input userMsg
1029
- withGetMethod (Form options a b c) =
1030
- Form { options | method = Get } a b c
1031
-
1032
-
1033
- {-| -}
1034
- withOnSubmit : ({ fields : List ( String, String ) } -> userMsg) -> Form error combineAndView input oldMsg -> Form error combineAndView input userMsg
1035
- withOnSubmit onSubmit (Form options a b c) =
1036
- Form
1037
- { onSubmit = Just onSubmit
1038
- , submitStrategy = options.submitStrategy
1039
- , method = options.method
1040
- }
1041
- a
1042
- b
1043
- c
1044
-
1045
-
1046
- {-| -}
1047
- renderStyledHtml :
1048
- String
1049
- -> List (Html.Styled.Attribute (PagesMsg msg))
1050
- -> (actionData -> Maybe (Response error))
1051
- -> AppContext app actionData
1052
- -> input
1053
- ->
1054
- Form
1055
- error
1056
- { combine : Form.Validation.Validation error parsed field constraints
1057
- , view : Context error input -> List (Html.Styled.Html (PagesMsg msg))
1058
- }
1059
- input
1060
- msg
1061
- -> Html.Styled.Html (PagesMsg msg)
1062
- renderStyledHtml formId attrs accessResponse app data form =
1063
- Html.Styled.Lazy.lazy6 renderStyledHelper formId attrs accessResponse app data form
1064
-
1065
-
1066
- {-| -}
1067
- type alias Response error =
1068
- Pages.Internal.Form.Response error
1069
-
1070
-
1071
- renderHelper :
1072
- String
1073
- -> List (Html.Attribute (PagesMsg msg))
1074
- -> (actionData -> Maybe (Response error))
1075
- -> AppContext app actionData
1076
- -> data
1077
- ->
1078
- Form
1079
- error
1080
- { combine : Form.Validation.Validation error parsed named constraints
1081
- , view : Context error data -> List (Html (PagesMsg msg))
1082
- }
1083
- data
1084
- msg
1085
- -> Html (PagesMsg msg)
1086
- renderHelper formId attrs accessResponse formState data ((Form options _ _ _) as form) =
1087
- -- TODO Get transition context from `app` so you can check if the current form is being submitted
1088
- -- TODO either as a transition or a fetcher? Should be easy enough to check for the `id` on either of those?
1089
- let
1090
- { hiddenInputs, children, isValid } =
1091
- helperValues formId toHiddenInput accessResponse formState data form
1092
-
1093
- toHiddenInput : List (Html.Attribute (PagesMsg msg)) -> Html (PagesMsg msg)
1094
- toHiddenInput hiddenAttrs =
1095
- Html.input hiddenAttrs []
1096
- in
1097
- Html.form
1098
- (Form.listeners formId
1099
- ++ [ Attr.method (methodToString options.method)
1100
- , Attr.novalidate True
1101
-
1102
- -- TODO provide a way to override the action so users can submit to other Routes
1103
- , Attr.action (Path.toAbsolute formState.path)
1104
- , case options.submitStrategy of
1105
- FetcherStrategy ->
1106
- Pages.Internal.Msg.fetcherOnSubmit options.onSubmit formId (\_ -> isValid)
1107
-
1108
- TransitionStrategy ->
1109
- Pages.Internal.Msg.submitIfValid options.onSubmit formId (\_ -> isValid)
1110
- ]
1111
- ++ attrs
1112
- )
1113
- (hiddenInputs ++ children)
1114
-
1115
-
1116
- renderStyledHelper :
1117
- String
1118
- -> List (Html.Styled.Attribute (PagesMsg msg))
1119
- -> (actionData -> Maybe (Response error))
1120
- -> AppContext app actionData
1121
- -> data
1122
- ->
1123
- Form
1124
- error
1125
- { combine : Form.Validation.Validation error parsed field constraints
1126
- , view : Context error data -> List (Html.Styled.Html (PagesMsg msg))
1127
- }
1128
- data
1129
- msg
1130
- -> Html.Styled.Html (PagesMsg msg)
1131
- renderStyledHelper formId attrs accessResponse formState data ((Form options _ _ _) as form) =
1132
- -- TODO Get transition context from `app` so you can check if the current form is being submitted
1133
- -- TODO either as a transition or a fetcher? Should be easy enough to check for the `id` on either of those?
1134
- let
1135
- { hiddenInputs, children, isValid } =
1136
- helperValues formId toHiddenInput accessResponse formState data form
1137
-
1138
- toHiddenInput : List (Html.Attribute (PagesMsg msg)) -> Html.Styled.Html (PagesMsg msg)
1139
- toHiddenInput hiddenAttrs =
1140
- Html.Styled.input (hiddenAttrs |> List.map StyledAttr.fromUnstyled) []
1141
- in
1142
- Html.Styled.form
1143
- ((Form.listeners formId |> List.map StyledAttr.fromUnstyled)
1144
- ++ [ StyledAttr.method (methodToString options.method)
1145
- , StyledAttr.novalidate True
1146
- , StyledAttr.action (Path.toAbsolute formState.path)
1147
- , case options.submitStrategy of
1148
- FetcherStrategy ->
1149
- StyledAttr.fromUnstyled <|
1150
- Pages.Internal.Msg.fetcherOnSubmit options.onSubmit formId (\_ -> isValid)
1151
-
1152
- TransitionStrategy ->
1153
- StyledAttr.fromUnstyled <|
1154
- Pages.Internal.Msg.submitIfValid options.onSubmit formId (\_ -> isValid)
1155
- ]
1156
- ++ attrs
1157
- )
1158
- (hiddenInputs ++ children)
1159
-
1160
-
1161
- helperValues :
1162
- String
1163
- -> (List (Html.Attribute (PagesMsg msg)) -> view)
1164
- -> (actionData -> Maybe (Response error))
1165
- -> AppContext app actionData
1166
- -> data
1167
- ->
1168
- Form
1169
- error
1170
- { combine : Form.Validation.Validation error parsed field constraints
1171
- , view : Context error data -> List view
1172
- }
1173
- data
1174
- msg
1175
- -> { hiddenInputs : List view, children : List view, isValid : Bool }
1176
- helperValues formId toHiddenInput accessResponse formState data (Form _ fieldDefinitions parser toInitialValues) =
1177
- let
1178
- initialValues : Dict String Form.FieldState
1179
- initialValues =
1180
- toInitialValues data
1181
- |> List.filterMap
1182
- (\( key, maybeValue ) ->
1183
- maybeValue
1184
- |> Maybe.map
1185
- (\value ->
1186
- ( key, { value = value, status = FieldStatus.NotVisited } )
1187
- )
1188
- )
1189
- |> Dict.fromList
1190
-
1191
- part2 : Dict String Form.FieldState
1192
- part2 =
1193
- formState.pageFormState
1194
- |> Dict.get formId
1195
- |> Maybe.withDefault
1196
- (formState.action
1197
- |> Maybe.andThen (accessResponse >> Maybe.map unwrapResponse)
1198
- |> Maybe.map
1199
- (\{ fields } ->
1200
- { fields =
1201
- fields
1202
- |> List.map (Tuple.mapSecond (\value -> { value = value, status = FieldStatus.NotVisited }))
1203
- |> Dict.fromList
1204
- , submitAttempted = True
1205
- }
1206
- )
1207
- |> Maybe.withDefault initFormState
1208
- )
1209
- |> .fields
1210
-
1211
- fullFormState : Dict String Form.FieldState
1212
- fullFormState =
1213
- initialValues
1214
- |> Dict.union part2
1215
-
1216
- parsed :
1217
- { result : ( Form.Validation.Validation error parsed field constraints, Dict String (List error) )
1218
- , isMatchCandidate : Bool
1219
- , view : Context error data -> List view
1220
- }
1221
- parsed =
1222
- { isMatchCandidate = parsed1.isMatchCandidate
1223
- , view = parsed1.combineAndView.view
1224
- , result = ( parsed1.combineAndView.combine, parsed1.result )
1225
- }
1226
-
1227
- parsed1 :
1228
- { result : Dict String (List error)
1229
- , isMatchCandidate : Bool
1230
- , combineAndView : { combine : Form.Validation.Validation error parsed field constraints, view : Context error data -> List view }
1231
- }
1232
- parsed1 =
1233
- parser (Just data) thisFormState
1234
-
1235
- withoutServerErrors : Form.Validation.Validation error parsed named constraints
1236
- withoutServerErrors =
1237
- parsed |> mergeResults
1238
-
1239
- withServerErrors : Form.Validation.Validation error parsed named constraints
1240
- withServerErrors =
1241
- mergeResults
1242
- { parsed
1243
- | result =
1244
- parsed.result
1245
- |> Tuple.mapSecond
1246
- (\errors1 ->
1247
- mergeErrors errors1
1248
- (formState.action
1249
- |> Maybe.andThen (accessResponse >> Maybe.map (unwrapResponse >> .errors))
1250
- |> Maybe.withDefault Dict.empty
1251
- )
1252
- )
1253
- }
1254
-
1255
- thisFormState : FormState
1256
- thisFormState =
1257
- formState.pageFormState
1258
- |> Dict.get formId
1259
- |> Maybe.withDefault
1260
- (formState.action
1261
- |> Maybe.andThen (accessResponse >> Maybe.map unwrapResponse)
1262
- |> Maybe.map
1263
- (\{ fields } ->
1264
- { fields =
1265
- fields
1266
- |> List.map (Tuple.mapSecond (\value -> { value = value, status = FieldStatus.NotVisited }))
1267
- |> Dict.fromList
1268
- , submitAttempted = True
1269
- }
1270
- )
1271
- |> Maybe.withDefault Form.init
1272
- )
1273
- |> (\state -> { state | fields = fullFormState })
1274
-
1275
- context : Context error data
1276
- context =
1277
- { errors =
1278
- withServerErrors
1279
- |> unwrapValidation
1280
- |> Tuple.second
1281
- |> Errors
1282
- , isTransitioning =
1283
- -- TODO instead of isTransitioning : Bool, it would be useful to get a custom type with the exact state
1284
- (case formState.fetchers |> Dict.get formId of
1285
- Just { status } ->
1286
- case status of
1287
- Pages.Transition.FetcherComplete _ ->
1288
- False
1289
-
1290
- Pages.Transition.FetcherSubmitting ->
1291
- True
1292
-
1293
- Pages.Transition.FetcherReloading _ ->
1294
- True
1295
-
1296
- Nothing ->
1297
- False
1298
- )
1299
- || (case formState.transition of
1300
- Just (Submitting formData) ->
1301
- formData.id == Just formId
1302
-
1303
- Just (LoadAfterSubmit submitData _ _) ->
1304
- submitData.id == Just formId
1305
-
1306
- Just (Loading _ _) ->
1307
- False
1308
-
1309
- Nothing ->
1310
- False
1311
- )
1312
- , submitAttempted = thisFormState.submitAttempted
1313
- , data = data
1314
- }
1315
-
1316
- children : List view
1317
- children =
1318
- parsed.view context
1319
-
1320
- hiddenInputs : List view
1321
- hiddenInputs =
1322
- fieldDefinitions
1323
- |> List.filterMap
1324
- (\( name, fieldDefinition ) ->
1325
- case fieldDefinition of
1326
- HiddenField ->
1327
- [ Attr.name name
1328
- , Attr.type_ "hidden"
1329
- , Attr.value
1330
- (initialValues
1331
- |> Dict.get name
1332
- |> Maybe.map .value
1333
- |> Maybe.withDefault ""
1334
- )
1335
- ]
1336
- |> toHiddenInput
1337
- |> Just
1338
-
1339
- RegularField ->
1340
- Nothing
1341
- )
1342
-
1343
- isValid : Bool
1344
- isValid =
1345
- case withoutServerErrors of
1346
- Validation _ _ ( Just _, errors ) ->
1347
- Dict.isEmpty errors
1348
-
1349
- _ ->
1350
- False
1351
- in
1352
- { hiddenInputs = hiddenInputs
1353
- , children = children
1354
- , isValid = isValid
1355
- }
1356
-
1357
-
1358
- {-| -}
1359
- type alias DoneForm error parsed data view msg =
1360
- Form
1361
- error
1362
- { combine : Combined error parsed
1363
- , view : Context error data -> view
1364
- }
1365
- data
1366
- msg
1367
-
1368
-
1369
- {-| -}
1370
- type alias HtmlForm error parsed input msg =
1371
- Form
1372
- error
1373
- { combine : Combined error parsed
1374
- , view : Context error input -> List (Html (PagesMsg msg))
1375
- }
1376
- input
1377
- msg
1378
-
1379
-
1380
- {-| -}
1381
- type ServerForms error parsed
1382
- = ServerForms
1383
- (List
1384
- (Form
1385
- error
1386
- (Combined error parsed)
1387
- Never
1388
- Never
1389
- )
1390
- )
1391
-
1392
-
1393
- {-| -}
1394
- initCombined :
1395
- (parsed -> combined)
1396
- ->
1397
- Form
1398
- error
1399
- { combineAndView
1400
- | combine : Form.Validation.Validation error parsed kind constraints
1401
- }
1402
- input
1403
- msg
1404
- -> ServerForms error combined
1405
- initCombined mapFn form =
1406
- ServerForms [ normalizeServerForm mapFn form ]
1407
-
1408
-
1409
- normalizeServerForm :
1410
- (parsed -> combined)
1411
- -> Form error { combineAndView | combine : Form.Validation.Validation error parsed kind constraints } input msg
1412
- -> Form error (Combined error combined) Never Never
1413
- normalizeServerForm mapFn (Form options _ parseFn _) =
1414
- Form
1415
- { onSubmit = Nothing
1416
- , submitStrategy = options.submitStrategy
1417
- , method = options.method
1418
- }
1419
- []
1420
- (\_ formState ->
1421
- let
1422
- parsed :
1423
- { result : Dict String (List error)
1424
- , isMatchCandidate : Bool
1425
- , combineAndView : { combineAndView | combine : Form.Validation.Validation error parsed kind constraints }
1426
- }
1427
- parsed =
1428
- parseFn Nothing formState
1429
- in
1430
- { result = parsed.result
1431
- , combineAndView = parsed.combineAndView.combine |> Form.Validation.mapWithNever mapFn
1432
- , isMatchCandidate = parsed.isMatchCandidate
1433
- }
1434
- )
1435
- (\_ -> [])
1436
-
1437
-
1438
- {-| -}
1439
- combine :
1440
- (parsed -> combined)
1441
- ->
1442
- Form
1443
- error
1444
- { combineAndView
1445
- | combine : Form.Validation.Validation error parsed kind constraints
1446
- }
1447
- input
1448
- msg
1449
- -> ServerForms error combined
1450
- -> ServerForms error combined
1451
- combine mapFn form (ServerForms serverForms) =
1452
- ServerForms (serverForms ++ [ normalizeServerForm mapFn form ])
1453
-
1454
-
1455
- {-| -}
1456
- initCombinedServer :
1457
- (parsed -> combined)
1458
- ->
1459
- Form
1460
- error
1461
- { combineAndView
1462
- | combine : Combined error (BackendTask backendTaskError (Form.Validation.Validation error parsed kind constraints))
1463
- }
1464
- input
1465
- msg
1466
- -> ServerForms error (BackendTask backendTaskError (Form.Validation.Validation error combined kind constraints))
1467
- initCombinedServer mapFn serverForms =
1468
- initCombined (BackendTask.map (Form.Validation.map mapFn)) serverForms
1469
-
1470
-
1471
- {-| -}
1472
- combineServer :
1473
- (parsed -> combined)
1474
- ->
1475
- Form
1476
- error
1477
- { combineAndView
1478
- | combine :
1479
- Combined error (BackendTask backendTaskError (Form.Validation.Validation error parsed kind constraints))
1480
- }
1481
- input
1482
- msg
1483
- -> ServerForms error (BackendTask backendTaskError (Form.Validation.Validation error combined kind constraints))
1484
- -> ServerForms error (BackendTask backendTaskError (Form.Validation.Validation error combined kind constraints))
1485
- combineServer mapFn a b =
1486
- combine (BackendTask.map (Form.Validation.map mapFn)) a b
1487
-
1488
-
1489
- {-| -}
1490
- type alias StyledHtmlForm error parsed data msg =
1491
- Form
1492
- error
1493
- { combine : Combined error parsed
1494
- , view : Context error data -> List (Html.Styled.Html (PagesMsg msg))
1495
- }
1496
- data
1497
- msg
1498
-
1499
-
1500
- {-| -}
1501
- type Form error combineAndView input userMsg
1502
- = Form
1503
- (RenderOptions userMsg)
1504
- (List ( String, FieldDefinition ))
1505
- (Maybe input
1506
- -> FormState
1507
- ->
1508
- { result : Dict String (List error)
1509
- , isMatchCandidate : Bool
1510
- , combineAndView : combineAndView
1511
- }
1512
- )
1513
- (input -> List ( String, Maybe String ))
1514
-
1515
-
1516
- type alias RenderOptions userMsg =
1517
- { submitStrategy : SubmitStrategy
1518
- , method : Method
1519
- , onSubmit : Maybe ({ fields : List ( String, String ) } -> userMsg)
1520
- }
1521
-
1522
-
1523
- {-| -}
1524
- type Method
1525
- = Post
1526
- | Get
1527
-
1528
-
1529
- methodToString : Method -> String
1530
- methodToString method =
1531
- case method of
1532
- Post ->
1533
- "POST"
1534
-
1535
- Get ->
1536
- "GET"
1537
-
1538
-
1539
- {-| -}
1540
- type SubmitStrategy
1541
- = FetcherStrategy
1542
- | TransitionStrategy
1543
-
1544
-
1545
- {-| -}
1546
- type FieldDefinition
1547
- = RegularField
1548
- | HiddenField
1549
-
1550
-
1551
- {-| -}
1552
- addErrorsInternal : String -> List error -> Dict String (List error) -> Dict String (List error)
1553
- addErrorsInternal name newErrors allErrors =
1554
- allErrors
1555
- |> Dict.update name
1556
- (\errors ->
1557
- Just (newErrors ++ (errors |> Maybe.withDefault []))
1558
- )