elm-pages 3.0.0-beta.4 → 3.0.0-beta.41
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.
- package/README.md +10 -1
- package/adapter/netlify.js +207 -0
- package/codegen/{elm-pages-codegen.js → elm-pages-codegen.cjs} +2828 -2933
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmi +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmo +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateDataTest.elmo +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm.json +1 -1
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1447 -342
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +17004 -13817
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +4 -4
- package/generator/dead-code-review/elm.json +9 -7
- package/generator/dead-code-review/src/Pages/Review/DeadCodeEliminateData.elm +59 -10
- package/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm +52 -36
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Internal-RoutePattern.elmi +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Internal-RoutePattern.elmo +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmi +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmo +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm.json +1 -1
- package/generator/review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1447 -342
- package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +25025 -21739
- package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
- package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +4 -4
- package/generator/review/elm.json +10 -10
- package/generator/src/RouteBuilder.elm +121 -114
- package/generator/src/SharedTemplate.elm +8 -7
- package/generator/src/SiteConfig.elm +3 -2
- package/generator/src/basepath-middleware.js +3 -3
- package/generator/src/build.js +209 -92
- package/generator/src/cli.js +292 -88
- package/generator/src/codegen.js +29 -27
- package/generator/src/compatibility-key.js +3 -0
- package/generator/src/compile-elm.js +43 -26
- package/generator/src/config.js +39 -0
- package/generator/src/copy-dir.js +2 -2
- package/generator/src/dev-server.js +176 -138
- package/generator/src/dir-helpers.js +9 -26
- package/generator/src/elm-codegen.js +5 -4
- package/generator/src/elm-file-constants.js +2 -3
- package/generator/src/error-formatter.js +12 -11
- package/generator/src/file-helpers.js +3 -4
- package/generator/src/generate-template-module-connector.js +23 -23
- package/generator/src/init.js +9 -8
- package/generator/src/pre-render-html.js +39 -28
- package/generator/src/render-test.js +109 -0
- package/generator/src/render-worker.js +25 -28
- package/generator/src/render.js +321 -142
- package/generator/src/request-cache.js +265 -162
- package/generator/src/resolve-elm-module.js +64 -0
- package/generator/src/rewrite-client-elm-json.js +6 -5
- package/generator/src/rewrite-elm-json-help.js +56 -0
- package/generator/src/rewrite-elm-json.js +17 -7
- package/generator/src/route-codegen-helpers.js +16 -31
- package/generator/src/seo-renderer.js +12 -7
- package/generator/src/vite-utils.js +77 -0
- package/generator/static-code/elm-pages.js +10 -0
- package/generator/static-code/hmr.js +79 -13
- package/generator/template/app/Api.elm +6 -5
- package/generator/template/app/Effect.elm +123 -0
- package/generator/template/app/ErrorPage.elm +37 -6
- package/generator/template/app/Route/Index.elm +17 -10
- package/generator/template/app/Shared.elm +24 -47
- package/generator/template/app/Site.elm +19 -6
- package/generator/template/app/View.elm +1 -8
- package/generator/template/elm-tooling.json +0 -3
- package/generator/template/elm.json +32 -24
- package/generator/template/package.json +10 -4
- package/package.json +30 -27
- package/src/ApiRoute.elm +199 -61
- package/src/BackendTask/Custom.elm +325 -0
- package/src/BackendTask/Env.elm +90 -0
- package/src/{DataSource → BackendTask}/File.elm +171 -56
- package/src/{DataSource → BackendTask}/Glob.elm +136 -125
- package/src/BackendTask/Http.elm +679 -0
- package/src/{DataSource → BackendTask}/Internal/Glob.elm +1 -1
- package/src/BackendTask/Internal/Request.elm +69 -0
- package/src/BackendTask/Random.elm +79 -0
- package/src/BackendTask/Time.elm +47 -0
- package/src/BackendTask.elm +531 -0
- package/src/FatalError.elm +90 -0
- package/src/Head/Seo.elm +4 -4
- package/src/Head.elm +237 -7
- package/src/HtmlPrinter.elm +7 -3
- package/src/Internal/ApiRoute.elm +7 -5
- package/src/PageServerResponse.elm +6 -1
- package/src/Pages/ConcurrentSubmission.elm +127 -0
- package/src/Pages/Form.elm +340 -0
- package/src/Pages/FormData.elm +18 -0
- package/src/Pages/GeneratorProgramConfig.elm +15 -0
- package/src/Pages/Internal/FatalError.elm +5 -0
- package/src/Pages/Internal/Msg.elm +93 -0
- package/src/Pages/Internal/NotFoundReason.elm +4 -4
- package/src/Pages/Internal/Platform/Cli.elm +617 -768
- package/src/Pages/Internal/Platform/CompatibilityKey.elm +6 -0
- package/src/Pages/Internal/Platform/Effect.elm +1 -2
- package/src/Pages/Internal/Platform/GeneratorApplication.elm +379 -0
- package/src/Pages/Internal/Platform/StaticResponses.elm +65 -276
- package/src/Pages/Internal/Platform/ToJsPayload.elm +6 -9
- package/src/Pages/Internal/Platform.elm +359 -225
- package/src/Pages/Internal/ResponseSketch.elm +2 -2
- package/src/Pages/Internal/Script.elm +17 -0
- package/src/Pages/Internal/StaticHttpBody.elm +35 -1
- package/src/Pages/Manifest.elm +52 -11
- package/src/Pages/Navigation.elm +87 -0
- package/src/Pages/PageUrl.elm +26 -12
- package/src/Pages/ProgramConfig.elm +35 -23
- package/src/Pages/Script.elm +166 -0
- package/src/Pages/SiteConfig.elm +3 -2
- package/src/Pages/StaticHttp/Request.elm +2 -2
- package/src/Pages/StaticHttpRequest.elm +23 -99
- package/src/Pages/Url.elm +3 -3
- package/src/PagesMsg.elm +88 -0
- package/src/QueryParams.elm +21 -172
- package/src/RenderRequest.elm +7 -7
- package/src/RequestsAndPending.elm +37 -20
- package/src/Result/Extra.elm +26 -0
- package/src/Scaffold/Form.elm +569 -0
- package/src/Scaffold/Route.elm +1411 -0
- package/src/Server/Request.elm +74 -72
- package/src/Server/Session.elm +62 -42
- package/src/Server/SetCookie.elm +80 -32
- package/src/Stub.elm +53 -0
- package/src/Test/Html/Internal/ElmHtml/ToString.elm +8 -9
- package/src/{Path.elm → UrlPath.elm} +33 -36
- package/src/DataSource/Env.elm +0 -38
- package/src/DataSource/Http.elm +0 -446
- package/src/DataSource/Internal/Request.elm +0 -20
- package/src/DataSource/Port.elm +0 -90
- package/src/DataSource.elm +0 -538
- package/src/Form/Field.elm +0 -717
- package/src/Form/FieldStatus.elm +0 -36
- package/src/Form/FieldView.elm +0 -417
- package/src/Form/FormData.elm +0 -22
- package/src/Form/Validation.elm +0 -391
- package/src/Form/Value.elm +0 -118
- package/src/Form.elm +0 -1683
- package/src/FormDecoder.elm +0 -102
- package/src/Pages/FormState.elm +0 -256
- package/src/Pages/Generate.elm +0 -800
- package/src/Pages/Internal/Form.elm +0 -17
- package/src/Pages/Msg.elm +0 -79
- package/src/Pages/Transition.elm +0 -70
|
@@ -20,34 +20,29 @@ import BuildError exposing (BuildError)
|
|
|
20
20
|
import Bytes exposing (Bytes)
|
|
21
21
|
import Bytes.Decode
|
|
22
22
|
import Dict exposing (Dict)
|
|
23
|
-
import Form
|
|
24
|
-
import FormDecoder
|
|
23
|
+
import Form
|
|
25
24
|
import Html exposing (Html)
|
|
26
25
|
import Html.Attributes as Attr
|
|
27
26
|
import Http
|
|
28
27
|
import Json.Decode as Decode
|
|
29
28
|
import Json.Encode
|
|
29
|
+
import Pages.ConcurrentSubmission
|
|
30
30
|
import Pages.ContentCache as ContentCache
|
|
31
31
|
import Pages.Fetcher
|
|
32
32
|
import Pages.Flags
|
|
33
|
-
import Pages.
|
|
33
|
+
import Pages.Internal.Msg
|
|
34
34
|
import Pages.Internal.NotFoundReason exposing (NotFoundReason)
|
|
35
35
|
import Pages.Internal.ResponseSketch as ResponseSketch exposing (ResponseSketch)
|
|
36
36
|
import Pages.Internal.String as String
|
|
37
|
-
import Pages.
|
|
37
|
+
import Pages.Navigation
|
|
38
38
|
import Pages.ProgramConfig exposing (ProgramConfig)
|
|
39
39
|
import Pages.StaticHttpRequest as StaticHttpRequest
|
|
40
|
-
import
|
|
41
|
-
import Path exposing (Path)
|
|
40
|
+
import PagesMsg exposing (PagesMsg)
|
|
42
41
|
import QueryParams
|
|
43
42
|
import Task
|
|
44
43
|
import Time
|
|
45
44
|
import Url exposing (Url)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
type Transition
|
|
49
|
-
= Loading Int Path
|
|
50
|
-
| Submitting FormData
|
|
45
|
+
import UrlPath exposing (UrlPath)
|
|
51
46
|
|
|
52
47
|
|
|
53
48
|
{-| -}
|
|
@@ -58,7 +53,7 @@ type alias Program userModel userMsg pageData actionData sharedData errorPage =
|
|
|
58
53
|
mainView :
|
|
59
54
|
ProgramConfig userMsg userModel route pageData actionData sharedData effect (Msg userMsg pageData actionData sharedData errorPage) errorPage
|
|
60
55
|
-> Model userModel pageData actionData sharedData
|
|
61
|
-
-> { title : String, body : List (Html (
|
|
56
|
+
-> { title : String, body : List (Html (PagesMsg userMsg)) }
|
|
62
57
|
mainView config model =
|
|
63
58
|
case model.notFound of
|
|
64
59
|
Just info ->
|
|
@@ -81,7 +76,7 @@ mainView config model =
|
|
|
81
76
|
(config.view model.pageFormState
|
|
82
77
|
(model.inFlightFetchers |> toFetcherState)
|
|
83
78
|
(model.transition |> Maybe.map Tuple.second)
|
|
84
|
-
{ path = ContentCache.pathForUrl urls |>
|
|
79
|
+
{ path = ContentCache.pathForUrl urls |> UrlPath.join
|
|
85
80
|
, route = config.urlToRoute { currentUrl | path = model.currentPath }
|
|
86
81
|
}
|
|
87
82
|
Nothing
|
|
@@ -101,14 +96,14 @@ mainView config model =
|
|
|
101
96
|
|
|
102
97
|
urlsToPagePath :
|
|
103
98
|
{ currentUrl : Url, basePath : List String }
|
|
104
|
-
->
|
|
99
|
+
-> UrlPath
|
|
105
100
|
urlsToPagePath urls =
|
|
106
101
|
urls.currentUrl.path
|
|
107
102
|
|> String.chopForwardSlashes
|
|
108
103
|
|> String.split "/"
|
|
109
104
|
|> List.filter ((/=) "")
|
|
110
105
|
|> List.drop (List.length urls.basePath)
|
|
111
|
-
|>
|
|
106
|
+
|> UrlPath.join
|
|
112
107
|
|
|
113
108
|
|
|
114
109
|
{-| -}
|
|
@@ -150,7 +145,7 @@ type alias Flags =
|
|
|
150
145
|
|
|
151
146
|
type InitKind shared page actionData errorPage
|
|
152
147
|
= OkPage shared page (Maybe actionData)
|
|
153
|
-
| NotFound { reason : NotFoundReason, path :
|
|
148
|
+
| NotFound { reason : NotFoundReason, path : UrlPath }
|
|
154
149
|
|
|
155
150
|
|
|
156
151
|
{-| -}
|
|
@@ -204,7 +199,7 @@ init config flags url key =
|
|
|
204
199
|
, basePath = config.basePath
|
|
205
200
|
}
|
|
206
201
|
|
|
207
|
-
pagePath :
|
|
202
|
+
pagePath : UrlPath
|
|
208
203
|
pagePath =
|
|
209
204
|
urlsToPagePath urls
|
|
210
205
|
|
|
@@ -230,7 +225,7 @@ init config flags url key =
|
|
|
230
225
|
, host = url.host
|
|
231
226
|
, port_ = url.port_
|
|
232
227
|
, path = pagePath
|
|
233
|
-
, query = url.query |> Maybe.map QueryParams.fromString
|
|
228
|
+
, query = url.query |> Maybe.map QueryParams.fromString |> Maybe.withDefault Dict.empty
|
|
234
229
|
, fragment = url.fragment
|
|
235
230
|
}
|
|
236
231
|
}
|
|
@@ -274,7 +269,7 @@ init config flags url key =
|
|
|
274
269
|
, url = url
|
|
275
270
|
, currentPath = url.path
|
|
276
271
|
, pageData = Err "Not found"
|
|
277
|
-
, ariaNavigationAnnouncement = "
|
|
272
|
+
, ariaNavigationAnnouncement = "Page Not Found" -- TODO use error page title for announcement?
|
|
278
273
|
, userFlags = flags
|
|
279
274
|
, notFound = Just info
|
|
280
275
|
, transition = Nothing
|
|
@@ -313,16 +308,23 @@ init config flags url key =
|
|
|
313
308
|
type Msg userMsg pageData actionData sharedData errorPage
|
|
314
309
|
= LinkClicked Browser.UrlRequest
|
|
315
310
|
| UrlChanged Url
|
|
316
|
-
|
|
317
|
-
|
|
|
311
|
+
-- TODO rename to PagesMsg
|
|
312
|
+
| UserMsg (PagesMsg userMsg)
|
|
313
|
+
--| SetField { formId : String, name : String, value : String }
|
|
314
|
+
| FormMsg (Form.Msg (Msg userMsg pageData actionData sharedData errorPage))
|
|
318
315
|
| UpdateCacheAndUrlNew Bool Url (Maybe userMsg) (Result Http.Error ( Url, ResponseSketch pageData actionData sharedData ))
|
|
319
|
-
| FetcherComplete Bool String Int (Result Http.Error ( Maybe userMsg,
|
|
316
|
+
| FetcherComplete Bool String Int (Result Http.Error ( Maybe userMsg, ActionDataOrRedirect actionData ))
|
|
320
317
|
| FetcherStarted String Int FormData Time.Posix
|
|
321
318
|
| PageScrollComplete
|
|
322
319
|
| HotReloadCompleteNew Bytes
|
|
323
320
|
| ProcessFetchResponse Int (Result Http.Error ( Url, ResponseSketch pageData actionData sharedData )) (Result Http.Error ( Url, ResponseSketch pageData actionData sharedData ) -> Msg userMsg pageData actionData sharedData errorPage)
|
|
324
321
|
|
|
325
322
|
|
|
323
|
+
type ActionDataOrRedirect action
|
|
324
|
+
= ActionResponse (Maybe action)
|
|
325
|
+
| RedirectResponse String
|
|
326
|
+
|
|
327
|
+
|
|
326
328
|
{-| -}
|
|
327
329
|
type alias Model userModel pageData actionData sharedData =
|
|
328
330
|
{ key : Maybe Browser.Navigation.Key
|
|
@@ -337,12 +339,12 @@ type alias Model userModel pageData actionData sharedData =
|
|
|
337
339
|
, sharedData : sharedData
|
|
338
340
|
, actionData : Maybe actionData
|
|
339
341
|
}
|
|
340
|
-
, notFound : Maybe { reason : NotFoundReason, path :
|
|
342
|
+
, notFound : Maybe { reason : NotFoundReason, path : UrlPath }
|
|
341
343
|
, userFlags : Decode.Value
|
|
342
|
-
, transition : Maybe ( Int, Pages.
|
|
344
|
+
, transition : Maybe ( Int, Pages.Navigation.Navigation )
|
|
343
345
|
, nextTransitionKey : Int
|
|
344
|
-
, inFlightFetchers : Dict String ( Int, Pages.
|
|
345
|
-
, pageFormState :
|
|
346
|
+
, inFlightFetchers : Dict String ( Int, Pages.ConcurrentSubmission.ConcurrentSubmission actionData )
|
|
347
|
+
, pageFormState : Form.Model
|
|
346
348
|
, pendingRedirect : Bool
|
|
347
349
|
, pendingData : Maybe ( pageData, sharedData, Maybe actionData )
|
|
348
350
|
}
|
|
@@ -361,6 +363,7 @@ type Effect userMsg pageData actionData sharedData userEffect errorPage
|
|
|
361
363
|
| Batch (List (Effect userMsg pageData actionData sharedData userEffect errorPage))
|
|
362
364
|
| UserCmd userEffect
|
|
363
365
|
| CancelRequest Int
|
|
366
|
+
| RunCmd (Cmd (Msg userMsg pageData actionData sharedData errorPage))
|
|
364
367
|
|
|
365
368
|
|
|
366
369
|
{-| -}
|
|
@@ -371,6 +374,18 @@ update :
|
|
|
371
374
|
-> ( Model userModel pageData actionData sharedData, Effect userMsg pageData actionData sharedData userEffect errorPage )
|
|
372
375
|
update config appMsg model =
|
|
373
376
|
case appMsg of
|
|
377
|
+
FormMsg formMsg ->
|
|
378
|
+
let
|
|
379
|
+
-- TODO trigger formCmd
|
|
380
|
+
( newModel, formCmd ) =
|
|
381
|
+
Form.update formMsg model.pageFormState
|
|
382
|
+
in
|
|
383
|
+
( { model
|
|
384
|
+
| pageFormState = newModel
|
|
385
|
+
}
|
|
386
|
+
, RunCmd formCmd
|
|
387
|
+
)
|
|
388
|
+
|
|
374
389
|
LinkClicked urlRequest ->
|
|
375
390
|
case urlRequest of
|
|
376
391
|
Browser.Internal url ->
|
|
@@ -396,11 +411,6 @@ update config appMsg model =
|
|
|
396
411
|
, BrowserLoadUrl href
|
|
397
412
|
)
|
|
398
413
|
|
|
399
|
-
SetField info ->
|
|
400
|
-
( { model | pageFormState = Pages.FormState.setField info model.pageFormState }
|
|
401
|
-
, NoEffect
|
|
402
|
-
)
|
|
403
|
-
|
|
404
414
|
UrlChanged url ->
|
|
405
415
|
case model.pendingData of
|
|
406
416
|
Just ( newPageData, newSharedData, newActionData ) ->
|
|
@@ -414,7 +424,7 @@ update config appMsg model =
|
|
|
414
424
|
model
|
|
415
425
|
|
|
416
426
|
Nothing ->
|
|
417
|
-
if model.url.path == url.path then
|
|
427
|
+
if model.url.path == url.path && model.url.query == url.query then
|
|
418
428
|
( { model
|
|
419
429
|
| -- update the URL in case query params or fragment changed
|
|
420
430
|
url = url
|
|
@@ -423,46 +433,57 @@ update config appMsg model =
|
|
|
423
433
|
)
|
|
424
434
|
|
|
425
435
|
else
|
|
426
|
-
(
|
|
427
|
-
| url = url
|
|
428
|
-
}
|
|
436
|
+
( model
|
|
429
437
|
, NoEffect
|
|
430
438
|
)
|
|
431
439
|
-- TODO is it reasonable to always re-fetch route data if you re-navigate to the current route? Might be a good
|
|
432
440
|
-- parallel to the browser behavior
|
|
433
441
|
|> startNewGetLoad url (UpdateCacheAndUrlNew True url Nothing)
|
|
434
442
|
|
|
435
|
-
FetcherComplete
|
|
443
|
+
FetcherComplete _ fetcherKey _ userMsgResult ->
|
|
436
444
|
case userMsgResult of
|
|
437
|
-
Ok ( userMsg,
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
model
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
(
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
445
|
+
Ok ( userMsg, actionOrRedirect ) ->
|
|
446
|
+
case actionOrRedirect of
|
|
447
|
+
ActionResponse maybeFetcherDoneActionData ->
|
|
448
|
+
( { model
|
|
449
|
+
| inFlightFetchers =
|
|
450
|
+
model.inFlightFetchers
|
|
451
|
+
|> Dict.update fetcherKey
|
|
452
|
+
(Maybe.map
|
|
453
|
+
(\( transitionId, fetcherState ) ->
|
|
454
|
+
( transitionId
|
|
455
|
+
, { fetcherState
|
|
456
|
+
| status =
|
|
457
|
+
maybeFetcherDoneActionData
|
|
458
|
+
|> Maybe.map Pages.ConcurrentSubmission.Reloading
|
|
459
|
+
-- TODO remove this bad default, FetcherSubmitting is incorrect
|
|
460
|
+
|> Maybe.withDefault Pages.ConcurrentSubmission.Submitting
|
|
461
|
+
}
|
|
462
|
+
)
|
|
463
|
+
)
|
|
452
464
|
)
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
465
|
+
}
|
|
466
|
+
, NoEffect
|
|
467
|
+
)
|
|
468
|
+
|> (case userMsg of
|
|
469
|
+
Just justUserMsg ->
|
|
470
|
+
performUserMsg justUserMsg config
|
|
471
|
+
|
|
472
|
+
Nothing ->
|
|
473
|
+
identity
|
|
474
|
+
)
|
|
475
|
+
|> startNewGetLoad (currentUrlWithPath model.url.path model) (UpdateCacheAndUrlNew False model.url Nothing)
|
|
476
|
+
|
|
477
|
+
RedirectResponse redirectTo ->
|
|
478
|
+
( { model
|
|
479
|
+
| inFlightFetchers =
|
|
480
|
+
model.inFlightFetchers
|
|
481
|
+
|> Dict.remove fetcherKey
|
|
482
|
+
, pendingRedirect = True
|
|
483
|
+
}
|
|
484
|
+
, NoEffect
|
|
485
|
+
)
|
|
486
|
+
|> startNewGetLoad (currentUrlWithPath redirectTo model) (UpdateCacheAndUrlNew False model.url Nothing)
|
|
466
487
|
|
|
467
488
|
Err _ ->
|
|
468
489
|
-- TODO how to handle error?
|
|
@@ -480,74 +501,70 @@ update config appMsg model =
|
|
|
480
501
|
|
|
481
502
|
UserMsg userMsg_ ->
|
|
482
503
|
case userMsg_ of
|
|
483
|
-
Pages.Msg.UserMsg userMsg ->
|
|
504
|
+
Pages.Internal.Msg.UserMsg userMsg ->
|
|
484
505
|
( model, NoEffect )
|
|
485
506
|
|> performUserMsg userMsg config
|
|
486
507
|
|
|
487
|
-
Pages.Msg.Submit fields ->
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
,
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
( { model | nextTransitionKey = model.nextTransitionKey + 1 }
|
|
526
|
-
, SubmitFetcher fetcherKey model.nextTransitionKey fields
|
|
527
|
-
)
|
|
528
|
-
|> (case maybeUserMsg of
|
|
529
|
-
Just justUserMsg ->
|
|
530
|
-
performUserMsg justUserMsg config
|
|
508
|
+
Pages.Internal.Msg.Submit fields ->
|
|
509
|
+
if fields.valid then
|
|
510
|
+
let
|
|
511
|
+
payload : { fields : List ( String, String ), method : Form.Method, action : String, id : Maybe String }
|
|
512
|
+
payload =
|
|
513
|
+
{ fields = fields.fields
|
|
514
|
+
, method = fields.method
|
|
515
|
+
, action = fields.action
|
|
516
|
+
, id = Just fields.id
|
|
517
|
+
}
|
|
518
|
+
in
|
|
519
|
+
if fields.useFetcher then
|
|
520
|
+
( { model | nextTransitionKey = model.nextTransitionKey + 1 }
|
|
521
|
+
, SubmitFetcher fields.id model.nextTransitionKey payload
|
|
522
|
+
)
|
|
523
|
+
|> (case fields.msg of
|
|
524
|
+
Just justUserMsg ->
|
|
525
|
+
performUserMsg justUserMsg config
|
|
526
|
+
|
|
527
|
+
Nothing ->
|
|
528
|
+
identity
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
else
|
|
532
|
+
( { model
|
|
533
|
+
-- TODO should I setSubmitAttempted here, too?
|
|
534
|
+
| transition =
|
|
535
|
+
Just
|
|
536
|
+
( -- TODO remove hardcoded number
|
|
537
|
+
-1
|
|
538
|
+
, Pages.Navigation.Submitting payload
|
|
539
|
+
)
|
|
540
|
+
}
|
|
541
|
+
, Submit payload
|
|
542
|
+
)
|
|
543
|
+
|> (case fields.msg of
|
|
544
|
+
Just justUserMsg ->
|
|
545
|
+
performUserMsg justUserMsg config
|
|
531
546
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
547
|
+
Nothing ->
|
|
548
|
+
identity
|
|
549
|
+
)
|
|
535
550
|
|
|
536
551
|
else
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
model.pageFormState
|
|
540
|
-
|> Pages.FormState.setSubmitAttempted fetcherKey
|
|
541
|
-
}
|
|
542
|
-
, NoEffect
|
|
543
|
-
)
|
|
552
|
+
-- TODO should the user msg still be run if the form is invalid?
|
|
553
|
+
( model, NoEffect )
|
|
544
554
|
|
|
545
|
-
Pages.Msg.
|
|
555
|
+
Pages.Internal.Msg.FormMsg formMsg ->
|
|
546
556
|
-- TODO when init is called for a new page, also need to clear out client-side `pageFormState`
|
|
547
|
-
|
|
548
|
-
|
|
557
|
+
let
|
|
558
|
+
( formModel, formCmd ) =
|
|
559
|
+
Form.update formMsg model.pageFormState
|
|
560
|
+
in
|
|
561
|
+
( { model | pageFormState = formModel }
|
|
562
|
+
, RunCmd (Cmd.map UserMsg formCmd)
|
|
549
563
|
)
|
|
550
564
|
|
|
565
|
+
Pages.Internal.Msg.NoOp ->
|
|
566
|
+
( model, NoEffect )
|
|
567
|
+
|
|
551
568
|
UpdateCacheAndUrlNew scrollToTopWhenDone urlWithoutRedirectResolution maybeUserMsg updateResult ->
|
|
552
569
|
-- TODO remove all fetchers that are in the state `FetcherReloading` here -- I think that's the right logic?
|
|
553
570
|
case
|
|
@@ -605,27 +622,32 @@ update config appMsg model =
|
|
|
605
622
|
, actionData = newActionData
|
|
606
623
|
}
|
|
607
624
|
|
|
608
|
-
( userModel,
|
|
625
|
+
( userModel, userEffect ) =
|
|
609
626
|
-- TODO if urlWithoutRedirectResolution is different from the url with redirect resolution, then
|
|
610
627
|
-- instead of calling update, call pushUrl (I think?)
|
|
611
628
|
-- TODO include user Cmd
|
|
612
|
-
|
|
613
|
-
(
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
+
if stayingOnSamePath then
|
|
630
|
+
( previousPageData.userModel, NoEffect )
|
|
631
|
+
|
|
632
|
+
else
|
|
633
|
+
config.update model.pageFormState
|
|
634
|
+
(model.inFlightFetchers |> toFetcherState)
|
|
635
|
+
(model.transition |> Maybe.map Tuple.second)
|
|
636
|
+
newSharedData
|
|
637
|
+
newPageData
|
|
638
|
+
model.key
|
|
639
|
+
(config.onPageChange
|
|
640
|
+
{ protocol = model.url.protocol
|
|
641
|
+
, host = model.url.host
|
|
642
|
+
, port_ = model.url.port_
|
|
643
|
+
, path = urlPathToPath urlWithoutRedirectResolution
|
|
644
|
+
, query = urlWithoutRedirectResolution.query
|
|
645
|
+
, fragment = urlWithoutRedirectResolution.fragment
|
|
646
|
+
, metadata = config.urlToRoute urlWithoutRedirectResolution
|
|
647
|
+
}
|
|
648
|
+
)
|
|
649
|
+
previousPageData.userModel
|
|
650
|
+
|> Tuple.mapSecond UserCmd
|
|
629
651
|
|
|
630
652
|
updatedModel : Model userModel pageData actionData sharedData
|
|
631
653
|
updatedModel =
|
|
@@ -656,10 +678,13 @@ update config appMsg model =
|
|
|
656
678
|
, currentPath = newUrl.path
|
|
657
679
|
}
|
|
658
680
|
, if not stayingOnSamePath && scrollToTopWhenDone then
|
|
659
|
-
|
|
681
|
+
Batch
|
|
682
|
+
[ ScrollToTop
|
|
683
|
+
, userEffect
|
|
684
|
+
]
|
|
660
685
|
|
|
661
686
|
else
|
|
662
|
-
|
|
687
|
+
userEffect
|
|
663
688
|
)
|
|
664
689
|
|> (case maybeUserMsg of
|
|
665
690
|
Just userMsg ->
|
|
@@ -679,10 +704,10 @@ update config appMsg model =
|
|
|
679
704
|
Err _ ->
|
|
680
705
|
{-
|
|
681
706
|
When there is an error loading the content.dat, we are either
|
|
682
|
-
1) in the dev server, and should show the relevant
|
|
707
|
+
1) in the dev server, and should show the relevant BackendTask error for the page
|
|
683
708
|
we're navigating to. This could be done more cleanly, but it's simplest to just
|
|
684
709
|
do a fresh page load and use the code path for presenting an error for a fresh page.
|
|
685
|
-
2) In a production app. That means we had a successful build, so there were no
|
|
710
|
+
2) In a production app. That means we had a successful build, so there were no BackendTask failures,
|
|
686
711
|
so the app must be stale (unless it's in some unexpected state from a bug). In the future,
|
|
687
712
|
it probably makes sense to include some sort of hash of the app version we are fetching, match
|
|
688
713
|
it with the current version that's running, and perform this logic when we see there is a mismatch.
|
|
@@ -745,7 +770,86 @@ update config appMsg model =
|
|
|
745
770
|
_ ->
|
|
746
771
|
( model, NoEffect )
|
|
747
772
|
)
|
|
748
|
-
|> Result.withDefault
|
|
773
|
+
|> Result.withDefault
|
|
774
|
+
(let
|
|
775
|
+
pageDataResult : Maybe (InitKind sharedData pageData actionData errorPage)
|
|
776
|
+
pageDataResult =
|
|
777
|
+
case Bytes.Decode.decode config.decodeResponse pageDataBytes of
|
|
778
|
+
Just (ResponseSketch.RenderPage _ _) ->
|
|
779
|
+
Nothing
|
|
780
|
+
|
|
781
|
+
Just (ResponseSketch.HotUpdate pageData shared actionData) ->
|
|
782
|
+
OkPage shared pageData actionData
|
|
783
|
+
|> Just
|
|
784
|
+
|
|
785
|
+
Just (ResponseSketch.NotFound notFound) ->
|
|
786
|
+
NotFound notFound
|
|
787
|
+
|> Just
|
|
788
|
+
|
|
789
|
+
_ ->
|
|
790
|
+
Nothing
|
|
791
|
+
in
|
|
792
|
+
case pageDataResult of
|
|
793
|
+
Just (OkPage sharedData pageData actionData) ->
|
|
794
|
+
let
|
|
795
|
+
urls : { currentUrl : Url, basePath : List String }
|
|
796
|
+
urls =
|
|
797
|
+
{ currentUrl = model.url
|
|
798
|
+
, basePath = config.basePath
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
pagePath : UrlPath
|
|
802
|
+
pagePath =
|
|
803
|
+
urlsToPagePath urls
|
|
804
|
+
|
|
805
|
+
userFlags : Pages.Flags.Flags
|
|
806
|
+
userFlags =
|
|
807
|
+
model.userFlags
|
|
808
|
+
|> Decode.decodeValue
|
|
809
|
+
(Decode.field "userFlags" Decode.value)
|
|
810
|
+
|> Result.withDefault Json.Encode.null
|
|
811
|
+
|> Pages.Flags.BrowserFlags
|
|
812
|
+
|
|
813
|
+
( userModel, userCmd ) =
|
|
814
|
+
Just
|
|
815
|
+
{ path =
|
|
816
|
+
{ path = pagePath
|
|
817
|
+
, query = model.url.query
|
|
818
|
+
, fragment = model.url.fragment
|
|
819
|
+
}
|
|
820
|
+
, metadata = config.urlToRoute model.url
|
|
821
|
+
, pageUrl =
|
|
822
|
+
Just
|
|
823
|
+
{ protocol = model.url.protocol
|
|
824
|
+
, host = model.url.host
|
|
825
|
+
, port_ = model.url.port_
|
|
826
|
+
, path = pagePath
|
|
827
|
+
, query = model.url.query |> Maybe.map QueryParams.fromString |> Maybe.withDefault Dict.empty
|
|
828
|
+
, fragment = model.url.fragment
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
|> config.init userFlags sharedData pageData actionData
|
|
832
|
+
|
|
833
|
+
cmd : Effect userMsg pageData actionData sharedData userEffect errorPage
|
|
834
|
+
cmd =
|
|
835
|
+
UserCmd userCmd
|
|
836
|
+
in
|
|
837
|
+
( { model
|
|
838
|
+
| pageData =
|
|
839
|
+
Ok
|
|
840
|
+
{ userModel = userModel
|
|
841
|
+
, sharedData = sharedData
|
|
842
|
+
, pageData = pageData
|
|
843
|
+
, actionData = actionData
|
|
844
|
+
}
|
|
845
|
+
, notFound = Nothing
|
|
846
|
+
}
|
|
847
|
+
, cmd
|
|
848
|
+
)
|
|
849
|
+
|
|
850
|
+
_ ->
|
|
851
|
+
( model, NoEffect )
|
|
852
|
+
)
|
|
749
853
|
|
|
750
854
|
FetcherStarted fetcherKey transitionId fetcherData initiatedAt ->
|
|
751
855
|
( { model
|
|
@@ -754,7 +858,7 @@ update config appMsg model =
|
|
|
754
858
|
|> Dict.insert fetcherKey
|
|
755
859
|
( transitionId
|
|
756
860
|
, { payload = fetcherData
|
|
757
|
-
, status = Pages.
|
|
861
|
+
, status = Pages.ConcurrentSubmission.Submitting
|
|
758
862
|
, initiatedAt = initiatedAt
|
|
759
863
|
}
|
|
760
864
|
)
|
|
@@ -763,10 +867,10 @@ update config appMsg model =
|
|
|
763
867
|
)
|
|
764
868
|
|
|
765
869
|
|
|
766
|
-
toFetcherState : Dict String ( Int, Pages.
|
|
870
|
+
toFetcherState : Dict String ( Int, Pages.ConcurrentSubmission.ConcurrentSubmission actionData ) -> Dict String (Pages.ConcurrentSubmission.ConcurrentSubmission actionData)
|
|
767
871
|
toFetcherState inFlightFetchers =
|
|
768
872
|
inFlightFetchers
|
|
769
|
-
|> Dict.map (\_ (
|
|
873
|
+
|> Dict.map (\_ ( _, fetcherState ) -> fetcherState)
|
|
770
874
|
|
|
771
875
|
|
|
772
876
|
performUserMsg :
|
|
@@ -800,6 +904,9 @@ perform config model effect =
|
|
|
800
904
|
NoEffect ->
|
|
801
905
|
Cmd.none
|
|
802
906
|
|
|
907
|
+
RunCmd cmd ->
|
|
908
|
+
cmd
|
|
909
|
+
|
|
803
910
|
Batch effects ->
|
|
804
911
|
effects
|
|
805
912
|
|> List.map (perform config model)
|
|
@@ -828,10 +935,10 @@ perform config model effect =
|
|
|
828
935
|
|> Maybe.withDefault Cmd.none
|
|
829
936
|
|
|
830
937
|
FetchPageData transitionKey maybeRequestInfo url toMsg ->
|
|
831
|
-
fetchRouteData
|
|
938
|
+
fetchRouteData transitionKey toMsg config url maybeRequestInfo
|
|
832
939
|
|
|
833
940
|
Submit fields ->
|
|
834
|
-
if fields.method == Get then
|
|
941
|
+
if fields.method == Form.Get then
|
|
835
942
|
model.key
|
|
836
943
|
|> Maybe.map (\key -> Browser.Navigation.pushUrl key (appendFormQueryParams fields))
|
|
837
944
|
|> Maybe.withDefault Cmd.none
|
|
@@ -843,7 +950,7 @@ perform config model effect =
|
|
|
843
950
|
-- TODO add optional path parameter to Submit variant to allow submitting to other routes
|
|
844
951
|
model.url
|
|
845
952
|
in
|
|
846
|
-
fetchRouteData
|
|
953
|
+
fetchRouteData -1 (UpdateCacheAndUrlNew False model.url Nothing) config urlToSubmitTo (Just fields)
|
|
847
954
|
|
|
848
955
|
SubmitFetcher fetcherKey transitionId formData ->
|
|
849
956
|
startFetcher2 config False fetcherKey transitionId formData model
|
|
@@ -863,7 +970,7 @@ perform config model effect =
|
|
|
863
970
|
|> config.perform
|
|
864
971
|
{ fetchRouteData =
|
|
865
972
|
\fetchInfo ->
|
|
866
|
-
fetchRouteData
|
|
973
|
+
fetchRouteData
|
|
867
974
|
-1
|
|
868
975
|
(prepare fetchInfo.toMsg)
|
|
869
976
|
config
|
|
@@ -873,15 +980,19 @@ perform config model effect =
|
|
|
873
980
|
---- TODO map the Msg with the wrapper type (like in the PR branch)
|
|
874
981
|
, submit =
|
|
875
982
|
\fetchInfo ->
|
|
876
|
-
fetchRouteData
|
|
983
|
+
fetchRouteData -1 (prepare fetchInfo.toMsg) config (fetchInfo.values.action |> Url.fromString |> Maybe.withDefault model.url) (Just fetchInfo.values)
|
|
877
984
|
, runFetcher =
|
|
878
985
|
\(Pages.Fetcher.Fetcher options) ->
|
|
879
986
|
-- TODO need to get the fetcherId here
|
|
880
987
|
-- TODO need to increment and pass in the transitionId
|
|
881
988
|
startFetcher "TODO" -1 options model
|
|
882
|
-
, fromPageMsg = Pages.Msg.UserMsg >> UserMsg
|
|
989
|
+
, fromPageMsg = Pages.Internal.Msg.UserMsg >> UserMsg
|
|
883
990
|
, key = key
|
|
884
|
-
, setField =
|
|
991
|
+
, setField =
|
|
992
|
+
\_ ->
|
|
993
|
+
--Task.succeed (SetField info) |> Task.perform identity
|
|
994
|
+
-- TODO
|
|
995
|
+
Cmd.none
|
|
885
996
|
}
|
|
886
997
|
|
|
887
998
|
Nothing ->
|
|
@@ -896,21 +1007,12 @@ startFetcher fetcherKey transitionId options model =
|
|
|
896
1007
|
let
|
|
897
1008
|
encodedBody : String
|
|
898
1009
|
encodedBody =
|
|
899
|
-
|
|
900
|
-
{ fields = options.fields
|
|
901
|
-
|
|
902
|
-
-- TODO remove hardcoding
|
|
903
|
-
, action = ""
|
|
1010
|
+
encodeFormData options.fields
|
|
904
1011
|
|
|
905
|
-
|
|
906
|
-
, method = Post
|
|
907
|
-
, id = Nothing
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
formData : { method : Method, action : String, fields : List ( String, String ), id : Maybe String }
|
|
1012
|
+
formData : { method : Form.Method, action : String, fields : List ( String, String ), id : Maybe String }
|
|
911
1013
|
formData =
|
|
912
1014
|
{ -- TODO remove hardcoding
|
|
913
|
-
method = Get
|
|
1015
|
+
method = Form.Get
|
|
914
1016
|
|
|
915
1017
|
-- TODO pass FormData directly
|
|
916
1018
|
, action = options.url |> Maybe.withDefault model.url.path
|
|
@@ -927,10 +1029,10 @@ startFetcher fetcherKey transitionId options model =
|
|
|
927
1029
|
Http.expectBytesResponse (FetcherComplete False fetcherKey model.nextTransitionKey)
|
|
928
1030
|
(\bytes ->
|
|
929
1031
|
case bytes of
|
|
930
|
-
Http.GoodStatus_
|
|
1032
|
+
Http.GoodStatus_ _ bytesBody ->
|
|
931
1033
|
( options.decoder (Ok bytesBody)
|
|
932
1034
|
|> Just
|
|
933
|
-
, Nothing
|
|
1035
|
+
, ActionResponse Nothing
|
|
934
1036
|
)
|
|
935
1037
|
|> Ok
|
|
936
1038
|
|
|
@@ -943,13 +1045,13 @@ startFetcher fetcherKey transitionId options model =
|
|
|
943
1045
|
Http.NetworkError_ ->
|
|
944
1046
|
Err <| Http.NetworkError
|
|
945
1047
|
|
|
946
|
-
Http.BadStatus_ metadata
|
|
1048
|
+
Http.BadStatus_ metadata _ ->
|
|
947
1049
|
Err <| Http.BadStatus metadata.statusCode
|
|
948
1050
|
)
|
|
949
1051
|
, tracker = Nothing
|
|
950
1052
|
, body = Http.stringBody "application/x-www-form-urlencoded" encodedBody
|
|
951
1053
|
, headers = options.headers |> List.map (\( name, value ) -> Http.header name value)
|
|
952
|
-
, url = options.url |> Maybe.withDefault (
|
|
1054
|
+
, url = options.url |> Maybe.withDefault (UrlPath.join [ model.url.path, "content.dat" ] |> UrlPath.toAbsolute)
|
|
953
1055
|
, method = "POST"
|
|
954
1056
|
, timeout = Nothing
|
|
955
1057
|
}
|
|
@@ -968,13 +1070,13 @@ startFetcher2 config fromPageReload fetcherKey transitionId formData model =
|
|
|
968
1070
|
let
|
|
969
1071
|
encodedBody : String
|
|
970
1072
|
encodedBody =
|
|
971
|
-
|
|
1073
|
+
encodeFormData formData.fields
|
|
972
1074
|
in
|
|
973
1075
|
-- TODO make sure that `actionData` isn't updated in Model for fetchers
|
|
974
1076
|
Cmd.batch
|
|
975
1077
|
[ cancelStaleFetchers model
|
|
976
1078
|
, case Dict.get fetcherKey model.inFlightFetchers of
|
|
977
|
-
Just ( inFlightId,
|
|
1079
|
+
Just ( inFlightId, _ ) ->
|
|
978
1080
|
Http.cancel (String.fromInt inFlightId)
|
|
979
1081
|
|
|
980
1082
|
Nothing ->
|
|
@@ -985,22 +1087,26 @@ startFetcher2 config fromPageReload fetcherKey transitionId formData model =
|
|
|
985
1087
|
Http.expectBytesResponse (FetcherComplete fromPageReload fetcherKey model.nextTransitionKey)
|
|
986
1088
|
(\bytes ->
|
|
987
1089
|
case bytes of
|
|
988
|
-
Http.GoodStatus_
|
|
1090
|
+
Http.GoodStatus_ _ bytesBody ->
|
|
989
1091
|
let
|
|
990
|
-
decodedAction :
|
|
1092
|
+
decodedAction : ActionDataOrRedirect actionData
|
|
991
1093
|
decodedAction =
|
|
992
1094
|
case Bytes.Decode.decode config.decodeResponse bytesBody of
|
|
1095
|
+
-- @@@
|
|
1096
|
+
Just (ResponseSketch.Redirect redirectTo) ->
|
|
1097
|
+
RedirectResponse redirectTo
|
|
1098
|
+
|
|
993
1099
|
Just (ResponseSketch.RenderPage _ maybeAction) ->
|
|
994
|
-
maybeAction
|
|
1100
|
+
ActionResponse maybeAction
|
|
995
1101
|
|
|
996
|
-
Just (ResponseSketch.HotUpdate
|
|
997
|
-
maybeAction
|
|
1102
|
+
Just (ResponseSketch.HotUpdate _ _ maybeAction) ->
|
|
1103
|
+
ActionResponse maybeAction
|
|
998
1104
|
|
|
999
|
-
Just (ResponseSketch.NotFound
|
|
1000
|
-
Nothing
|
|
1105
|
+
Just (ResponseSketch.NotFound _) ->
|
|
1106
|
+
ActionResponse Nothing
|
|
1001
1107
|
|
|
1002
1108
|
_ ->
|
|
1003
|
-
Nothing
|
|
1109
|
+
ActionResponse Nothing
|
|
1004
1110
|
in
|
|
1005
1111
|
-- TODO maybe have an optional way to pass the bytes through?
|
|
1006
1112
|
Ok ( Nothing, decodedAction )
|
|
@@ -1014,7 +1120,7 @@ startFetcher2 config fromPageReload fetcherKey transitionId formData model =
|
|
|
1014
1120
|
Http.NetworkError_ ->
|
|
1015
1121
|
Err <| Http.NetworkError
|
|
1016
1122
|
|
|
1017
|
-
Http.BadStatus_ metadata
|
|
1123
|
+
Http.BadStatus_ metadata _ ->
|
|
1018
1124
|
Err <| Http.BadStatus metadata.statusCode
|
|
1019
1125
|
)
|
|
1020
1126
|
, tracker = Just (String.fromInt transitionId)
|
|
@@ -1024,8 +1130,8 @@ startFetcher2 config fromPageReload fetcherKey transitionId formData model =
|
|
|
1024
1130
|
, headers = []
|
|
1025
1131
|
|
|
1026
1132
|
-- TODO use formData.method to do either query params or POST body
|
|
1027
|
-
, url = formData.action |> Url.fromString |> Maybe.map (\{ path } ->
|
|
1028
|
-
, method = formData.method |>
|
|
1133
|
+
, url = formData.action |> Url.fromString |> Maybe.map (\{ path } -> UrlPath.join [ path, "content.dat" ] |> UrlPath.toAbsolute) |> Maybe.withDefault "/"
|
|
1134
|
+
, method = formData.method |> methodToString
|
|
1029
1135
|
, timeout = Nothing
|
|
1030
1136
|
}
|
|
1031
1137
|
]
|
|
@@ -1036,16 +1142,16 @@ cancelStaleFetchers model =
|
|
|
1036
1142
|
model.inFlightFetchers
|
|
1037
1143
|
|> Dict.toList
|
|
1038
1144
|
|> List.filterMap
|
|
1039
|
-
(\(
|
|
1145
|
+
(\( _, ( id, fetcher ) ) ->
|
|
1040
1146
|
case fetcher.status of
|
|
1041
|
-
Pages.
|
|
1147
|
+
Pages.ConcurrentSubmission.Reloading _ ->
|
|
1042
1148
|
Http.cancel (String.fromInt id)
|
|
1043
1149
|
|> Just
|
|
1044
1150
|
|
|
1045
|
-
Pages.
|
|
1151
|
+
Pages.ConcurrentSubmission.Submitting ->
|
|
1046
1152
|
Nothing
|
|
1047
1153
|
|
|
1048
|
-
Pages.
|
|
1154
|
+
Pages.ConcurrentSubmission.Complete _ ->
|
|
1049
1155
|
Nothing
|
|
1050
1156
|
)
|
|
1051
1157
|
|> Cmd.batch
|
|
@@ -1059,10 +1165,10 @@ appendFormQueryParams fields =
|
|
|
1059
1165
|
|> Maybe.withDefault "/"
|
|
1060
1166
|
)
|
|
1061
1167
|
++ (case fields.method of
|
|
1062
|
-
Get ->
|
|
1063
|
-
"?" ++
|
|
1168
|
+
Form.Get ->
|
|
1169
|
+
"?" ++ encodeFormData fields.fields
|
|
1064
1170
|
|
|
1065
|
-
Post ->
|
|
1171
|
+
Form.Post ->
|
|
1066
1172
|
""
|
|
1067
1173
|
)
|
|
1068
1174
|
|
|
@@ -1102,9 +1208,9 @@ application config =
|
|
|
1102
1208
|
in
|
|
1103
1209
|
Sub.batch
|
|
1104
1210
|
[ config.subscriptions (model.url |> config.urlToRoute)
|
|
1105
|
-
(urls.currentUrl |> config.urlToRoute |> config.routeToPath |>
|
|
1211
|
+
(urls.currentUrl |> config.urlToRoute |> config.routeToPath |> UrlPath.join)
|
|
1106
1212
|
pageData.userModel
|
|
1107
|
-
|> Sub.map (Pages.Msg.UserMsg >> UserMsg)
|
|
1213
|
+
|> Sub.map (Pages.Internal.Msg.UserMsg >> UserMsg)
|
|
1108
1214
|
, config.hotReloadData
|
|
1109
1215
|
|> Sub.map HotReloadCompleteNew
|
|
1110
1216
|
]
|
|
@@ -1151,20 +1257,19 @@ withUserMsg config userMsg ( model, effect ) =
|
|
|
1151
1257
|
( model, effect )
|
|
1152
1258
|
|
|
1153
1259
|
|
|
1154
|
-
urlPathToPath : Url ->
|
|
1260
|
+
urlPathToPath : Url -> UrlPath
|
|
1155
1261
|
urlPathToPath urls =
|
|
1156
|
-
urls.path |>
|
|
1262
|
+
urls.path |> UrlPath.fromString
|
|
1157
1263
|
|
|
1158
1264
|
|
|
1159
1265
|
fetchRouteData :
|
|
1160
|
-
|
|
1161
|
-
-> Int
|
|
1266
|
+
Int
|
|
1162
1267
|
-> (Result Http.Error ( Url, ResponseSketch pageData actionData sharedData ) -> Msg userMsg pageData actionData sharedData errorPage)
|
|
1163
1268
|
-> ProgramConfig userMsg userModel route pageData actionData sharedData effect (Msg userMsg pageData actionData sharedData errorPage) errorPage
|
|
1164
1269
|
-> Url
|
|
1165
1270
|
-> Maybe FormData
|
|
1166
1271
|
-> Cmd (Msg userMsg pageData actionData sharedData errorPage)
|
|
1167
|
-
fetchRouteData
|
|
1272
|
+
fetchRouteData transitionKey toMsg config url details =
|
|
1168
1273
|
{-
|
|
1169
1274
|
TODO:
|
|
1170
1275
|
- [X] `toMsg` needs a parameter for the callback Msg so it can pass it on if there is a Redirect response
|
|
@@ -1178,14 +1283,14 @@ fetchRouteData forPageDataReload transitionKey toMsg config url details =
|
|
|
1178
1283
|
|
|
1179
1284
|
-}
|
|
1180
1285
|
let
|
|
1181
|
-
formMethod : Method
|
|
1286
|
+
formMethod : Form.Method
|
|
1182
1287
|
formMethod =
|
|
1183
1288
|
details
|
|
1184
1289
|
|> Maybe.map .method
|
|
1185
|
-
|> Maybe.withDefault Get
|
|
1290
|
+
|> Maybe.withDefault Form.Get
|
|
1186
1291
|
in
|
|
1187
1292
|
Http.request
|
|
1188
|
-
{ method = details |> Maybe.map (.method >>
|
|
1293
|
+
{ method = details |> Maybe.map (.method >> methodToString) |> Maybe.withDefault "GET"
|
|
1189
1294
|
, headers = []
|
|
1190
1295
|
, url =
|
|
1191
1296
|
"/"
|
|
@@ -1203,34 +1308,34 @@ fetchRouteData forPageDataReload transitionKey toMsg config url details =
|
|
|
1203
1308
|
|> String.join "/"
|
|
1204
1309
|
)
|
|
1205
1310
|
++ (case formMethod of
|
|
1206
|
-
Post ->
|
|
1311
|
+
Form.Post ->
|
|
1207
1312
|
"/"
|
|
1208
1313
|
|
|
1209
|
-
Get ->
|
|
1314
|
+
Form.Get ->
|
|
1210
1315
|
details
|
|
1211
|
-
|> Maybe.map
|
|
1316
|
+
|> Maybe.map (.fields >> encodeFormData)
|
|
1212
1317
|
|> Maybe.map (\encoded -> "?" ++ encoded)
|
|
1213
1318
|
|> Maybe.withDefault ""
|
|
1214
1319
|
)
|
|
1215
1320
|
++ (case formMethod of
|
|
1216
1321
|
-- TODO extract this to something unit testable
|
|
1217
1322
|
-- TODO make states mutually exclusive for submissions and direct URL requests (shouldn't be possible to append two query param strings)
|
|
1218
|
-
Post ->
|
|
1323
|
+
Form.Post ->
|
|
1219
1324
|
""
|
|
1220
1325
|
|
|
1221
|
-
Get ->
|
|
1326
|
+
Form.Get ->
|
|
1222
1327
|
url.query
|
|
1223
1328
|
|> Maybe.map (\encoded -> "?" ++ encoded)
|
|
1224
1329
|
|> Maybe.withDefault ""
|
|
1225
1330
|
)
|
|
1226
1331
|
, body =
|
|
1227
1332
|
case formMethod of
|
|
1228
|
-
Post ->
|
|
1333
|
+
Form.Post ->
|
|
1229
1334
|
let
|
|
1230
1335
|
urlEncodedFields : Maybe String
|
|
1231
1336
|
urlEncodedFields =
|
|
1232
1337
|
details
|
|
1233
|
-
|> Maybe.map
|
|
1338
|
+
|> Maybe.map (.fields >> encodeFormData)
|
|
1234
1339
|
in
|
|
1235
1340
|
urlEncodedFields
|
|
1236
1341
|
|> Maybe.map (\encoded -> Http.stringBody "application/x-www-form-urlencoded" encoded)
|
|
@@ -1251,7 +1356,7 @@ fetchRouteData forPageDataReload transitionKey toMsg config url details =
|
|
|
1251
1356
|
Http.NetworkError_ ->
|
|
1252
1357
|
Err Http.NetworkError
|
|
1253
1358
|
|
|
1254
|
-
Http.BadStatus_
|
|
1359
|
+
Http.BadStatus_ _ body ->
|
|
1255
1360
|
body
|
|
1256
1361
|
|> Bytes.Decode.decode config.decodeResponse
|
|
1257
1362
|
|> Result.fromMaybe "Decoding error"
|
|
@@ -1303,7 +1408,7 @@ startNewGetLoad urlToGet toMsg ( model, effect ) =
|
|
|
1303
1408
|
cancelIfStale : Effect userMsg pageData actionData sharedData userEffect errorPage
|
|
1304
1409
|
cancelIfStale =
|
|
1305
1410
|
case model.transition of
|
|
1306
|
-
Just ( transitionKey, Pages.
|
|
1411
|
+
Just ( transitionKey, Pages.Navigation.Loading _ _ ) ->
|
|
1307
1412
|
CancelRequest transitionKey
|
|
1308
1413
|
|
|
1309
1414
|
_ ->
|
|
@@ -1314,22 +1419,22 @@ startNewGetLoad urlToGet toMsg ( model, effect ) =
|
|
|
1314
1419
|
, transition =
|
|
1315
1420
|
( model.nextTransitionKey
|
|
1316
1421
|
, case model.transition of
|
|
1317
|
-
Just (
|
|
1318
|
-
Pages.
|
|
1422
|
+
Just ( _, Pages.Navigation.LoadAfterSubmit submitData _ _ ) ->
|
|
1423
|
+
Pages.Navigation.LoadAfterSubmit
|
|
1319
1424
|
submitData
|
|
1320
|
-
(urlToGet.path |>
|
|
1321
|
-
Pages.
|
|
1425
|
+
(urlToGet.path |> UrlPath.fromString)
|
|
1426
|
+
Pages.Navigation.Load
|
|
1322
1427
|
|
|
1323
|
-
Just (
|
|
1324
|
-
Pages.
|
|
1428
|
+
Just ( _, Pages.Navigation.Submitting submitData ) ->
|
|
1429
|
+
Pages.Navigation.LoadAfterSubmit
|
|
1325
1430
|
submitData
|
|
1326
|
-
(urlToGet.path |>
|
|
1327
|
-
Pages.
|
|
1431
|
+
(urlToGet.path |> UrlPath.fromString)
|
|
1432
|
+
Pages.Navigation.Load
|
|
1328
1433
|
|
|
1329
1434
|
_ ->
|
|
1330
|
-
Pages.
|
|
1331
|
-
(urlToGet.path |>
|
|
1332
|
-
Pages.
|
|
1435
|
+
Pages.Navigation.Loading
|
|
1436
|
+
(urlToGet.path |> UrlPath.fromString)
|
|
1437
|
+
Pages.Navigation.Load
|
|
1333
1438
|
)
|
|
1334
1439
|
|> Just
|
|
1335
1440
|
}
|
|
@@ -1355,9 +1460,9 @@ clearLoadingFetchersAfterDataLoad completedTransitionId model =
|
|
|
1355
1460
|
-- TODO fetchers are never removed from the list. Need to decide how and when to remove them.
|
|
1356
1461
|
--(fetcherState.status /= Pages.Transition.FetcherReloading) || (transitionId > completedTransitionId)
|
|
1357
1462
|
case ( transitionId > completedTransitionId, fetcherState.status ) of
|
|
1358
|
-
( False, Pages.
|
|
1463
|
+
( False, Pages.ConcurrentSubmission.Reloading actionData ) ->
|
|
1359
1464
|
( transitionId
|
|
1360
|
-
, { fetcherState | status = Pages.
|
|
1465
|
+
, { fetcherState | status = Pages.ConcurrentSubmission.Complete actionData }
|
|
1361
1466
|
)
|
|
1362
1467
|
|
|
1363
1468
|
_ ->
|
|
@@ -1392,6 +1497,7 @@ loadDataAndUpdateUrl ( newPageData, newSharedData, newActionData ) maybeUserMsg
|
|
|
1392
1497
|
, actionData = newActionData
|
|
1393
1498
|
}
|
|
1394
1499
|
|
|
1500
|
+
-- TODO use userEffect here?
|
|
1395
1501
|
( userModel, _ ) =
|
|
1396
1502
|
-- TODO if urlWithoutRedirectResolution is different from the url with redirect resolution, then
|
|
1397
1503
|
-- instead of calling update, call pushUrl (I think?)
|
|
@@ -1467,10 +1573,10 @@ loadDataAndUpdateUrl ( newPageData, newSharedData, newActionData ) maybeUserMsg
|
|
|
1467
1573
|
Err _ ->
|
|
1468
1574
|
{-
|
|
1469
1575
|
When there is an error loading the content.dat, we are either
|
|
1470
|
-
1) in the dev server, and should show the relevant
|
|
1576
|
+
1) in the dev server, and should show the relevant BackendTask error for the page
|
|
1471
1577
|
we're navigating to. This could be done more cleanly, but it's simplest to just
|
|
1472
1578
|
do a fresh page load and use the code path for presenting an error for a fresh page.
|
|
1473
|
-
2) In a production app. That means we had a successful build, so there were no
|
|
1579
|
+
2) In a production app. That means we had a successful build, so there were no BackendTask failures,
|
|
1474
1580
|
so the app must be stale (unless it's in some unexpected state from a bug). In the future,
|
|
1475
1581
|
it probably makes sense to include some sort of hash of the app version we are fetching, match
|
|
1476
1582
|
it with the current version that's running, and perform this logic when we see there is a mismatch.
|
|
@@ -1483,3 +1589,31 @@ loadDataAndUpdateUrl ( newPageData, newSharedData, newActionData ) maybeUserMsg
|
|
|
1483
1589
|
|> Url.toString
|
|
1484
1590
|
|> BrowserLoadUrl
|
|
1485
1591
|
)
|
|
1592
|
+
|
|
1593
|
+
|
|
1594
|
+
methodToString : Form.Method -> String
|
|
1595
|
+
methodToString method =
|
|
1596
|
+
case method of
|
|
1597
|
+
Form.Get ->
|
|
1598
|
+
"GET"
|
|
1599
|
+
|
|
1600
|
+
Form.Post ->
|
|
1601
|
+
"POST"
|
|
1602
|
+
|
|
1603
|
+
|
|
1604
|
+
encodeFormData : List ( String, String ) -> String
|
|
1605
|
+
encodeFormData fields =
|
|
1606
|
+
fields
|
|
1607
|
+
|> List.map
|
|
1608
|
+
(\( name, value ) ->
|
|
1609
|
+
Url.percentEncode name ++ "=" ++ Url.percentEncode value
|
|
1610
|
+
)
|
|
1611
|
+
|> String.join "&"
|
|
1612
|
+
|
|
1613
|
+
|
|
1614
|
+
type alias FormData =
|
|
1615
|
+
{ fields : List ( String, String )
|
|
1616
|
+
, method : Form.Method
|
|
1617
|
+
, action : String
|
|
1618
|
+
, id : Maybe String
|
|
1619
|
+
}
|