elm-pages 3.0.0-beta.40 → 3.0.0-beta.42
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 +1 -1
- package/codegen/elm-pages-codegen.cjs +251 -285
- 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/js/node_runner.js +1 -1
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
- 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/js/node_runner.js +1 -1
- package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
- package/generator/src/RouteBuilder.elm +19 -60
- package/generator/src/SharedTemplate.elm +5 -5
- package/generator/src/compatibility-key.js +2 -2
- package/package.json +2 -2
- package/src/ApiRoute.elm +3 -31
- package/src/BackendTask.elm +18 -24
- package/src/FormData.elm +21 -1
- package/src/Head/Seo.elm +4 -4
- package/src/Internal/Request.elm +84 -4
- package/src/Pages/ConcurrentSubmission.elm +127 -0
- package/src/Pages/Form.elm +151 -40
- package/src/Pages/FormData.elm +19 -0
- package/src/Pages/Internal/NotFoundReason.elm +4 -4
- package/src/Pages/Internal/Platform/Cli.elm +30 -17
- package/src/Pages/Internal/Platform/CompatibilityKey.elm +1 -1
- package/src/Pages/Internal/Platform.elm +39 -38
- package/src/Pages/Internal/ResponseSketch.elm +2 -2
- package/src/Pages/Manifest.elm +23 -7
- package/src/Pages/Navigation.elm +85 -0
- package/src/Pages/PageUrl.elm +3 -3
- package/src/Pages/ProgramConfig.elm +13 -11
- package/src/Pages/Script.elm +64 -7
- package/src/Pages/Url.elm +3 -3
- package/src/PagesMsg.elm +9 -3
- package/src/RenderRequest.elm +7 -7
- package/src/Scaffold/Form.elm +28 -5
- package/src/Scaffold/Route.elm +82 -53
- package/src/Server/Request.elm +446 -952
- package/src/Server/Session.elm +141 -91
- package/src/Server/SetCookie.elm +71 -31
- package/src/{Path.elm → UrlPath.elm} +21 -21
- package/src/Pages/Transition.elm +0 -79
|
@@ -17,6 +17,7 @@ import Head exposing (Tag)
|
|
|
17
17
|
import Html exposing (Html)
|
|
18
18
|
import HtmlPrinter
|
|
19
19
|
import Internal.ApiRoute exposing (ApiRoute(..))
|
|
20
|
+
import Internal.Request
|
|
20
21
|
import Json.Decode as Decode
|
|
21
22
|
import Json.Encode
|
|
22
23
|
import PageServerResponse exposing (PageServerResponse)
|
|
@@ -32,11 +33,11 @@ import Pages.ProgramConfig exposing (ProgramConfig)
|
|
|
32
33
|
import Pages.SiteConfig exposing (SiteConfig)
|
|
33
34
|
import Pages.StaticHttp.Request
|
|
34
35
|
import PagesMsg exposing (PagesMsg)
|
|
35
|
-
import Path exposing (Path)
|
|
36
36
|
import RenderRequest exposing (RenderRequest)
|
|
37
37
|
import RequestsAndPending exposing (RequestsAndPending)
|
|
38
38
|
import TerminalText as Terminal
|
|
39
39
|
import Url exposing (Url)
|
|
40
|
+
import UrlPath exposing (UrlPath)
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
{-| -}
|
|
@@ -402,7 +403,7 @@ initLegacy site ((RenderRequest.SinglePage includeHtml singleRequest _) as rende
|
|
|
402
403
|
{ protocol = Url.Https
|
|
403
404
|
, host = site.canonicalUrl
|
|
404
405
|
, port_ = Nothing
|
|
405
|
-
, path = serverRequestPayload.path |>
|
|
406
|
+
, path = serverRequestPayload.path |> UrlPath.toRelative
|
|
406
407
|
, query = Nothing
|
|
407
408
|
, fragment = Nothing
|
|
408
409
|
}
|
|
@@ -422,7 +423,13 @@ initLegacy site ((RenderRequest.SinglePage includeHtml singleRequest _) as rende
|
|
|
422
423
|
--sendSinglePageProgress site model.allRawResponses config model payload
|
|
423
424
|
(case isAction of
|
|
424
425
|
Just _ ->
|
|
425
|
-
config.action
|
|
426
|
+
config.action
|
|
427
|
+
(RenderRequest.maybeRequestPayload renderRequest
|
|
428
|
+
|> Maybe.map Internal.Request.toRequest
|
|
429
|
+
|> Maybe.withDefault Internal.Request.fakeRequest
|
|
430
|
+
)
|
|
431
|
+
serverRequestPayload.frontmatter
|
|
432
|
+
|> BackendTask.map Just
|
|
426
433
|
|
|
427
434
|
Nothing ->
|
|
428
435
|
BackendTask.succeed Nothing
|
|
@@ -471,7 +478,7 @@ initLegacy site ((RenderRequest.SinglePage includeHtml singleRequest _) as rende
|
|
|
471
478
|
case pageData of
|
|
472
479
|
PageServerResponse.RenderPage responseInfo pageData_ ->
|
|
473
480
|
let
|
|
474
|
-
currentPage : { path :
|
|
481
|
+
currentPage : { path : UrlPath, route : route }
|
|
475
482
|
currentPage =
|
|
476
483
|
{ path = serverRequestPayload.path, route = urlToRoute config currentUrl }
|
|
477
484
|
|
|
@@ -565,7 +572,7 @@ initLegacy site ((RenderRequest.SinglePage includeHtml singleRequest _) as rende
|
|
|
565
572
|
-- TODO handle other cases besides redirects?
|
|
566
573
|
|> Maybe.withDefault byteEncodedPageData
|
|
567
574
|
|> (\encodedData ->
|
|
568
|
-
{ route = currentPage.path |>
|
|
575
|
+
{ route = currentPage.path |> UrlPath.toRelative
|
|
569
576
|
, contentJson = Dict.empty
|
|
570
577
|
, html = viewValue.body |> bodyToString
|
|
571
578
|
, errors = []
|
|
@@ -615,7 +622,7 @@ initLegacy site ((RenderRequest.SinglePage includeHtml singleRequest _) as rende
|
|
|
615
622
|
|
|
616
623
|
PageServerResponse.ErrorPage error record ->
|
|
617
624
|
let
|
|
618
|
-
currentPage : { path :
|
|
625
|
+
currentPage : { path : UrlPath, route : route }
|
|
619
626
|
currentPage =
|
|
620
627
|
{ path = serverRequestPayload.path, route = urlToRoute config currentUrl }
|
|
621
628
|
|
|
@@ -651,7 +658,7 @@ initLegacy site ((RenderRequest.SinglePage includeHtml singleRequest _) as rende
|
|
|
651
658
|
|> Bytes.Encode.encode
|
|
652
659
|
)
|
|
653
660
|
|> (\encodedData ->
|
|
654
|
-
{ route = currentPage.path |>
|
|
661
|
+
{ route = currentPage.path |> UrlPath.toRelative
|
|
655
662
|
, contentJson = Dict.empty
|
|
656
663
|
, html = viewValue.body |> bodyToString
|
|
657
664
|
, errors = []
|
|
@@ -674,7 +681,13 @@ initLegacy site ((RenderRequest.SinglePage includeHtml singleRequest _) as rende
|
|
|
674
681
|
in
|
|
675
682
|
renderedResult
|
|
676
683
|
)
|
|
677
|
-
(config.data
|
|
684
|
+
(config.data
|
|
685
|
+
(RenderRequest.maybeRequestPayload renderRequest
|
|
686
|
+
|> Maybe.map Internal.Request.toRequest
|
|
687
|
+
|> Maybe.withDefault Internal.Request.fakeRequest
|
|
688
|
+
)
|
|
689
|
+
serverRequestPayload.frontmatter
|
|
690
|
+
)
|
|
678
691
|
config.sharedData
|
|
679
692
|
globalHeadTags
|
|
680
693
|
)
|
|
@@ -743,7 +756,7 @@ initLegacy site ((RenderRequest.SinglePage includeHtml singleRequest _) as rende
|
|
|
743
756
|
)
|
|
744
757
|
|> Tuple.first
|
|
745
758
|
|
|
746
|
-
currentPage : { path :
|
|
759
|
+
currentPage : { path : UrlPath, route : route }
|
|
747
760
|
currentPage =
|
|
748
761
|
{ path = serverRequestPayload.path, route = urlToRoute config currentUrl }
|
|
749
762
|
|
|
@@ -752,7 +765,7 @@ initLegacy site ((RenderRequest.SinglePage includeHtml singleRequest _) as rende
|
|
|
752
765
|
(config.view Dict.empty Dict.empty Nothing currentPage Nothing justSharedData dataThing Nothing |> .view)
|
|
753
766
|
pageModel
|
|
754
767
|
in
|
|
755
|
-
{ route =
|
|
768
|
+
{ route = UrlPath.toAbsolute currentPage.path
|
|
756
769
|
, contentJson = Dict.empty
|
|
757
770
|
, html = viewValue.body |> bodyToString
|
|
758
771
|
, errors = []
|
|
@@ -797,7 +810,7 @@ initLegacy site ((RenderRequest.SinglePage includeHtml singleRequest _) as rende
|
|
|
797
810
|
-- TODO do I need sharedDataResult here?
|
|
798
811
|
Nothing
|
|
799
812
|
isDevServer
|
|
800
|
-
(
|
|
813
|
+
(UrlPath.fromString path)
|
|
801
814
|
NotFoundReason.NoMatchingRoute
|
|
802
815
|
--Err error ->
|
|
803
816
|
-- [ error ]
|
|
@@ -909,7 +922,7 @@ render404Page :
|
|
|
909
922
|
ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage
|
|
910
923
|
-> Maybe sharedData
|
|
911
924
|
-> Bool
|
|
912
|
-
->
|
|
925
|
+
-> UrlPath
|
|
913
926
|
-> NotFoundReason
|
|
914
927
|
-> Effect
|
|
915
928
|
render404Page config sharedData isDevServer path notFoundReason =
|
|
@@ -940,7 +953,7 @@ render404Page config sharedData isDevServer path notFoundReason =
|
|
|
940
953
|
pageData =
|
|
941
954
|
config.errorPageToData config.notFoundPage
|
|
942
955
|
|
|
943
|
-
pathAndRoute : { path :
|
|
956
|
+
pathAndRoute : { path : UrlPath, route : route }
|
|
944
957
|
pathAndRoute =
|
|
945
958
|
{ path = path, route = config.notFoundRoute }
|
|
946
959
|
|
|
@@ -958,7 +971,7 @@ render404Page config sharedData isDevServer path notFoundReason =
|
|
|
958
971
|
)
|
|
959
972
|
pageModel
|
|
960
973
|
in
|
|
961
|
-
{ route =
|
|
974
|
+
{ route = UrlPath.toAbsolute path
|
|
962
975
|
, contentJson = Dict.empty
|
|
963
976
|
, html = viewValue.body |> bodyToString
|
|
964
977
|
, errors = []
|
|
@@ -987,7 +1000,7 @@ render404Page config sharedData isDevServer path notFoundReason =
|
|
|
987
1000
|
}
|
|
988
1001
|
|> NotFoundReason.document config.pathPatterns
|
|
989
1002
|
in
|
|
990
|
-
{ route =
|
|
1003
|
+
{ route = UrlPath.toAbsolute path
|
|
991
1004
|
, contentJson = Dict.empty
|
|
992
1005
|
, html = bodyToString notFoundDocument.body
|
|
993
1006
|
, errors = []
|
|
@@ -1021,7 +1034,7 @@ urlToRoute config url =
|
|
|
1021
1034
|
|
|
1022
1035
|
toRedirectResponse :
|
|
1023
1036
|
ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage
|
|
1024
|
-
-> { b | path :
|
|
1037
|
+
-> { b | path : UrlPath }
|
|
1025
1038
|
-> RenderRequest.IncludeHtml
|
|
1026
1039
|
-> { c | headers : List ( String, String ), statusCode : Int }
|
|
1027
1040
|
-> { response | statusCode : Int, headers : List ( String, String ) }
|
|
@@ -1044,7 +1057,7 @@ toRedirectResponse config serverRequestPayload includeHtml serverResponse respon
|
|
|
1044
1057
|
|> Bytes.Encode.encode
|
|
1045
1058
|
)
|
|
1046
1059
|
in
|
|
1047
|
-
{ route = serverRequestPayload.path |>
|
|
1060
|
+
{ route = serverRequestPayload.path |> UrlPath.toRelative
|
|
1048
1061
|
, contentJson = Dict.empty
|
|
1049
1062
|
, html = "This is intentionally blank HTML"
|
|
1050
1063
|
, errors = []
|
|
@@ -26,6 +26,7 @@ import Html.Attributes as Attr
|
|
|
26
26
|
import Http
|
|
27
27
|
import Json.Decode as Decode
|
|
28
28
|
import Json.Encode
|
|
29
|
+
import Pages.ConcurrentSubmission
|
|
29
30
|
import Pages.ContentCache as ContentCache
|
|
30
31
|
import Pages.Fetcher
|
|
31
32
|
import Pages.Flags
|
|
@@ -33,15 +34,15 @@ import Pages.Internal.Msg
|
|
|
33
34
|
import Pages.Internal.NotFoundReason exposing (NotFoundReason)
|
|
34
35
|
import Pages.Internal.ResponseSketch as ResponseSketch exposing (ResponseSketch)
|
|
35
36
|
import Pages.Internal.String as String
|
|
37
|
+
import Pages.Navigation
|
|
36
38
|
import Pages.ProgramConfig exposing (ProgramConfig)
|
|
37
39
|
import Pages.StaticHttpRequest as StaticHttpRequest
|
|
38
|
-
import Pages.Transition
|
|
39
40
|
import PagesMsg exposing (PagesMsg)
|
|
40
|
-
import Path exposing (Path)
|
|
41
41
|
import QueryParams
|
|
42
42
|
import Task
|
|
43
43
|
import Time
|
|
44
44
|
import Url exposing (Url)
|
|
45
|
+
import UrlPath exposing (UrlPath)
|
|
45
46
|
|
|
46
47
|
|
|
47
48
|
{-| -}
|
|
@@ -75,7 +76,7 @@ mainView config model =
|
|
|
75
76
|
(config.view model.pageFormState
|
|
76
77
|
(model.inFlightFetchers |> toFetcherState)
|
|
77
78
|
(model.transition |> Maybe.map Tuple.second)
|
|
78
|
-
{ path = ContentCache.pathForUrl urls |>
|
|
79
|
+
{ path = ContentCache.pathForUrl urls |> UrlPath.join
|
|
79
80
|
, route = config.urlToRoute { currentUrl | path = model.currentPath }
|
|
80
81
|
}
|
|
81
82
|
Nothing
|
|
@@ -95,14 +96,14 @@ mainView config model =
|
|
|
95
96
|
|
|
96
97
|
urlsToPagePath :
|
|
97
98
|
{ currentUrl : Url, basePath : List String }
|
|
98
|
-
->
|
|
99
|
+
-> UrlPath
|
|
99
100
|
urlsToPagePath urls =
|
|
100
101
|
urls.currentUrl.path
|
|
101
102
|
|> String.chopForwardSlashes
|
|
102
103
|
|> String.split "/"
|
|
103
104
|
|> List.filter ((/=) "")
|
|
104
105
|
|> List.drop (List.length urls.basePath)
|
|
105
|
-
|>
|
|
106
|
+
|> UrlPath.join
|
|
106
107
|
|
|
107
108
|
|
|
108
109
|
{-| -}
|
|
@@ -144,7 +145,7 @@ type alias Flags =
|
|
|
144
145
|
|
|
145
146
|
type InitKind shared page actionData errorPage
|
|
146
147
|
= OkPage shared page (Maybe actionData)
|
|
147
|
-
| NotFound { reason : NotFoundReason, path :
|
|
148
|
+
| NotFound { reason : NotFoundReason, path : UrlPath }
|
|
148
149
|
|
|
149
150
|
|
|
150
151
|
{-| -}
|
|
@@ -198,7 +199,7 @@ init config flags url key =
|
|
|
198
199
|
, basePath = config.basePath
|
|
199
200
|
}
|
|
200
201
|
|
|
201
|
-
pagePath :
|
|
202
|
+
pagePath : UrlPath
|
|
202
203
|
pagePath =
|
|
203
204
|
urlsToPagePath urls
|
|
204
205
|
|
|
@@ -338,11 +339,11 @@ type alias Model userModel pageData actionData sharedData =
|
|
|
338
339
|
, sharedData : sharedData
|
|
339
340
|
, actionData : Maybe actionData
|
|
340
341
|
}
|
|
341
|
-
, notFound : Maybe { reason : NotFoundReason, path :
|
|
342
|
+
, notFound : Maybe { reason : NotFoundReason, path : UrlPath }
|
|
342
343
|
, userFlags : Decode.Value
|
|
343
|
-
, transition : Maybe ( Int, Pages.
|
|
344
|
+
, transition : Maybe ( Int, Pages.Navigation.Navigation )
|
|
344
345
|
, nextTransitionKey : Int
|
|
345
|
-
, inFlightFetchers : Dict String ( Int, Pages.
|
|
346
|
+
, inFlightFetchers : Dict String ( Int, Pages.ConcurrentSubmission.ConcurrentSubmission actionData )
|
|
346
347
|
, pageFormState : Form.Model
|
|
347
348
|
, pendingRedirect : Bool
|
|
348
349
|
, pendingData : Maybe ( pageData, sharedData, Maybe actionData )
|
|
@@ -454,9 +455,9 @@ update config appMsg model =
|
|
|
454
455
|
, { fetcherState
|
|
455
456
|
| status =
|
|
456
457
|
maybeFetcherDoneActionData
|
|
457
|
-
|> Maybe.map Pages.
|
|
458
|
+
|> Maybe.map Pages.ConcurrentSubmission.Reloading
|
|
458
459
|
-- TODO remove this bad default, FetcherSubmitting is incorrect
|
|
459
|
-
|> Maybe.withDefault Pages.
|
|
460
|
+
|> Maybe.withDefault Pages.ConcurrentSubmission.Submitting
|
|
460
461
|
}
|
|
461
462
|
)
|
|
462
463
|
)
|
|
@@ -534,7 +535,7 @@ update config appMsg model =
|
|
|
534
535
|
Just
|
|
535
536
|
( -- TODO remove hardcoded number
|
|
536
537
|
-1
|
|
537
|
-
, Pages.
|
|
538
|
+
, Pages.Navigation.Submitting payload
|
|
538
539
|
)
|
|
539
540
|
}
|
|
540
541
|
, Submit payload
|
|
@@ -797,7 +798,7 @@ update config appMsg model =
|
|
|
797
798
|
, basePath = config.basePath
|
|
798
799
|
}
|
|
799
800
|
|
|
800
|
-
pagePath :
|
|
801
|
+
pagePath : UrlPath
|
|
801
802
|
pagePath =
|
|
802
803
|
urlsToPagePath urls
|
|
803
804
|
|
|
@@ -857,7 +858,7 @@ update config appMsg model =
|
|
|
857
858
|
|> Dict.insert fetcherKey
|
|
858
859
|
( transitionId
|
|
859
860
|
, { payload = fetcherData
|
|
860
|
-
, status = Pages.
|
|
861
|
+
, status = Pages.ConcurrentSubmission.Submitting
|
|
861
862
|
, initiatedAt = initiatedAt
|
|
862
863
|
}
|
|
863
864
|
)
|
|
@@ -866,7 +867,7 @@ update config appMsg model =
|
|
|
866
867
|
)
|
|
867
868
|
|
|
868
869
|
|
|
869
|
-
toFetcherState : Dict String ( Int, Pages.
|
|
870
|
+
toFetcherState : Dict String ( Int, Pages.ConcurrentSubmission.ConcurrentSubmission actionData ) -> Dict String (Pages.ConcurrentSubmission.ConcurrentSubmission actionData)
|
|
870
871
|
toFetcherState inFlightFetchers =
|
|
871
872
|
inFlightFetchers
|
|
872
873
|
|> Dict.map (\_ ( _, fetcherState ) -> fetcherState)
|
|
@@ -1050,7 +1051,7 @@ startFetcher fetcherKey transitionId options model =
|
|
|
1050
1051
|
, tracker = Nothing
|
|
1051
1052
|
, body = Http.stringBody "application/x-www-form-urlencoded" encodedBody
|
|
1052
1053
|
, headers = options.headers |> List.map (\( name, value ) -> Http.header name value)
|
|
1053
|
-
, url = options.url |> Maybe.withDefault (
|
|
1054
|
+
, url = options.url |> Maybe.withDefault (UrlPath.join [ model.url.path, "content.dat" ] |> UrlPath.toAbsolute)
|
|
1054
1055
|
, method = "POST"
|
|
1055
1056
|
, timeout = Nothing
|
|
1056
1057
|
}
|
|
@@ -1129,7 +1130,7 @@ startFetcher2 config fromPageReload fetcherKey transitionId formData model =
|
|
|
1129
1130
|
, headers = []
|
|
1130
1131
|
|
|
1131
1132
|
-- TODO use formData.method to do either query params or POST body
|
|
1132
|
-
, url = formData.action |> Url.fromString |> Maybe.map (\{ path } ->
|
|
1133
|
+
, url = formData.action |> Url.fromString |> Maybe.map (\{ path } -> UrlPath.join [ path, "content.dat" ] |> UrlPath.toAbsolute) |> Maybe.withDefault "/"
|
|
1133
1134
|
, method = formData.method |> methodToString
|
|
1134
1135
|
, timeout = Nothing
|
|
1135
1136
|
}
|
|
@@ -1143,14 +1144,14 @@ cancelStaleFetchers model =
|
|
|
1143
1144
|
|> List.filterMap
|
|
1144
1145
|
(\( _, ( id, fetcher ) ) ->
|
|
1145
1146
|
case fetcher.status of
|
|
1146
|
-
Pages.
|
|
1147
|
+
Pages.ConcurrentSubmission.Reloading _ ->
|
|
1147
1148
|
Http.cancel (String.fromInt id)
|
|
1148
1149
|
|> Just
|
|
1149
1150
|
|
|
1150
|
-
Pages.
|
|
1151
|
+
Pages.ConcurrentSubmission.Submitting ->
|
|
1151
1152
|
Nothing
|
|
1152
1153
|
|
|
1153
|
-
Pages.
|
|
1154
|
+
Pages.ConcurrentSubmission.Complete _ ->
|
|
1154
1155
|
Nothing
|
|
1155
1156
|
)
|
|
1156
1157
|
|> Cmd.batch
|
|
@@ -1207,7 +1208,7 @@ application config =
|
|
|
1207
1208
|
in
|
|
1208
1209
|
Sub.batch
|
|
1209
1210
|
[ config.subscriptions (model.url |> config.urlToRoute)
|
|
1210
|
-
(urls.currentUrl |> config.urlToRoute |> config.routeToPath |>
|
|
1211
|
+
(urls.currentUrl |> config.urlToRoute |> config.routeToPath |> UrlPath.join)
|
|
1211
1212
|
pageData.userModel
|
|
1212
1213
|
|> Sub.map (Pages.Internal.Msg.UserMsg >> UserMsg)
|
|
1213
1214
|
, config.hotReloadData
|
|
@@ -1256,9 +1257,9 @@ withUserMsg config userMsg ( model, effect ) =
|
|
|
1256
1257
|
( model, effect )
|
|
1257
1258
|
|
|
1258
1259
|
|
|
1259
|
-
urlPathToPath : Url ->
|
|
1260
|
+
urlPathToPath : Url -> UrlPath
|
|
1260
1261
|
urlPathToPath urls =
|
|
1261
|
-
urls.path |>
|
|
1262
|
+
urls.path |> UrlPath.fromString
|
|
1262
1263
|
|
|
1263
1264
|
|
|
1264
1265
|
fetchRouteData :
|
|
@@ -1407,7 +1408,7 @@ startNewGetLoad urlToGet toMsg ( model, effect ) =
|
|
|
1407
1408
|
cancelIfStale : Effect userMsg pageData actionData sharedData userEffect errorPage
|
|
1408
1409
|
cancelIfStale =
|
|
1409
1410
|
case model.transition of
|
|
1410
|
-
Just ( transitionKey, Pages.
|
|
1411
|
+
Just ( transitionKey, Pages.Navigation.Loading _ _ ) ->
|
|
1411
1412
|
CancelRequest transitionKey
|
|
1412
1413
|
|
|
1413
1414
|
_ ->
|
|
@@ -1418,22 +1419,22 @@ startNewGetLoad urlToGet toMsg ( model, effect ) =
|
|
|
1418
1419
|
, transition =
|
|
1419
1420
|
( model.nextTransitionKey
|
|
1420
1421
|
, case model.transition of
|
|
1421
|
-
Just ( _, Pages.
|
|
1422
|
-
Pages.
|
|
1422
|
+
Just ( _, Pages.Navigation.LoadAfterSubmit submitData _ _ ) ->
|
|
1423
|
+
Pages.Navigation.LoadAfterSubmit
|
|
1423
1424
|
submitData
|
|
1424
|
-
(urlToGet.path |>
|
|
1425
|
-
Pages.
|
|
1425
|
+
(urlToGet.path |> UrlPath.fromString)
|
|
1426
|
+
Pages.Navigation.Load
|
|
1426
1427
|
|
|
1427
|
-
Just ( _, Pages.
|
|
1428
|
-
Pages.
|
|
1428
|
+
Just ( _, Pages.Navigation.Submitting submitData ) ->
|
|
1429
|
+
Pages.Navigation.LoadAfterSubmit
|
|
1429
1430
|
submitData
|
|
1430
|
-
(urlToGet.path |>
|
|
1431
|
-
Pages.
|
|
1431
|
+
(urlToGet.path |> UrlPath.fromString)
|
|
1432
|
+
Pages.Navigation.Load
|
|
1432
1433
|
|
|
1433
1434
|
_ ->
|
|
1434
|
-
Pages.
|
|
1435
|
-
(urlToGet.path |>
|
|
1436
|
-
Pages.
|
|
1435
|
+
Pages.Navigation.Loading
|
|
1436
|
+
(urlToGet.path |> UrlPath.fromString)
|
|
1437
|
+
Pages.Navigation.Load
|
|
1437
1438
|
)
|
|
1438
1439
|
|> Just
|
|
1439
1440
|
}
|
|
@@ -1459,9 +1460,9 @@ clearLoadingFetchersAfterDataLoad completedTransitionId model =
|
|
|
1459
1460
|
-- TODO fetchers are never removed from the list. Need to decide how and when to remove them.
|
|
1460
1461
|
--(fetcherState.status /= Pages.Transition.FetcherReloading) || (transitionId > completedTransitionId)
|
|
1461
1462
|
case ( transitionId > completedTransitionId, fetcherState.status ) of
|
|
1462
|
-
( False, Pages.
|
|
1463
|
+
( False, Pages.ConcurrentSubmission.Reloading actionData ) ->
|
|
1463
1464
|
( transitionId
|
|
1464
|
-
, { fetcherState | status = Pages.
|
|
1465
|
+
, { fetcherState | status = Pages.ConcurrentSubmission.Complete actionData }
|
|
1465
1466
|
)
|
|
1466
1467
|
|
|
1467
1468
|
_ ->
|
|
@@ -7,7 +7,7 @@ module Pages.Internal.ResponseSketch exposing (ResponseSketch(..))
|
|
|
7
7
|
-}
|
|
8
8
|
|
|
9
9
|
import Pages.Internal.NotFoundReason exposing (NotFoundReason)
|
|
10
|
-
import
|
|
10
|
+
import UrlPath exposing (UrlPath)
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
{-| -}
|
|
@@ -15,5 +15,5 @@ type ResponseSketch data action shared
|
|
|
15
15
|
= RenderPage data (Maybe action)
|
|
16
16
|
| HotUpdate data shared (Maybe action)
|
|
17
17
|
| Redirect String
|
|
18
|
-
| NotFound { reason : NotFoundReason, path :
|
|
18
|
+
| NotFound { reason : NotFoundReason, path : UrlPath }
|
|
19
19
|
| Action action
|
package/src/Pages/Manifest.elm
CHANGED
|
@@ -11,8 +11,8 @@ module Pages.Manifest exposing
|
|
|
11
11
|
{-| Represents the configuration of a
|
|
12
12
|
[web manifest file](https://developer.mozilla.org/en-US/docs/Web/Manifest).
|
|
13
13
|
|
|
14
|
-
You pass your `Pages.Manifest.Config` record into the `Pages.
|
|
15
|
-
|
|
14
|
+
You pass your `Pages.Manifest.Config` record into the `Pages.Manifest.generator`
|
|
15
|
+
in your `app/Api.elm` module to define a file generator that will build a `manifest.json` file as part of your build.
|
|
16
16
|
|
|
17
17
|
import Pages.Manifest as Manifest
|
|
18
18
|
import Pages.Manifest.Category
|
|
@@ -77,7 +77,7 @@ import LanguageTag.Language
|
|
|
77
77
|
import MimeType
|
|
78
78
|
import Pages.Manifest.Category as Category exposing (Category)
|
|
79
79
|
import Pages.Url
|
|
80
|
-
import
|
|
80
|
+
import UrlPath exposing (UrlPath)
|
|
81
81
|
|
|
82
82
|
|
|
83
83
|
|
|
@@ -114,7 +114,7 @@ type Orientation
|
|
|
114
114
|
init :
|
|
115
115
|
{ description : String
|
|
116
116
|
, name : String
|
|
117
|
-
, startUrl :
|
|
117
|
+
, startUrl : UrlPath
|
|
118
118
|
, icons : List Icon
|
|
119
119
|
}
|
|
120
120
|
-> Config
|
|
@@ -253,7 +253,7 @@ type alias Config =
|
|
|
253
253
|
, themeColor : Maybe Color
|
|
254
254
|
|
|
255
255
|
-- https://developer.mozilla.org/en-US/docs/Web/Manifest/start_url
|
|
256
|
-
, startUrl :
|
|
256
|
+
, startUrl : UrlPath
|
|
257
257
|
|
|
258
258
|
-- https://developer.mozilla.org/en-US/docs/Web/Manifest/short_name
|
|
259
259
|
, shortName : Maybe String
|
|
@@ -343,7 +343,23 @@ nonEmptyList list =
|
|
|
343
343
|
Just list
|
|
344
344
|
|
|
345
345
|
|
|
346
|
-
{-| A generator for Api.elm to include a manifest.json.
|
|
346
|
+
{-| A generator for `Api.elm` to include a manifest.json. The String argument is the canonical URL of the site.
|
|
347
|
+
|
|
348
|
+
module Api exposing (routes)
|
|
349
|
+
|
|
350
|
+
import ApiRoute
|
|
351
|
+
import Pages.Manifest
|
|
352
|
+
|
|
353
|
+
routes :
|
|
354
|
+
BackendTask FatalError (List Route)
|
|
355
|
+
-> (Maybe { indent : Int, newLines : Bool } -> Html Never -> String)
|
|
356
|
+
-> List (ApiRoute.ApiRoute ApiRoute.Response)
|
|
357
|
+
routes getStaticRoutes htmlToString =
|
|
358
|
+
[ Pages.Manifest.generator
|
|
359
|
+
Site.canonicalUrl
|
|
360
|
+
Manifest.config
|
|
361
|
+
]
|
|
362
|
+
|
|
347
363
|
-}
|
|
348
364
|
generator : String -> BackendTask FatalError Config -> ApiRoute.ApiRoute ApiRoute.Response
|
|
349
365
|
generator canonicalSiteUrl config =
|
|
@@ -430,7 +446,7 @@ toJson canonicalSiteUrl config =
|
|
|
430
446
|
|> Maybe.map Encode.string
|
|
431
447
|
)
|
|
432
448
|
, ( "start_url"
|
|
433
|
-
,
|
|
449
|
+
, UrlPath.toAbsolute config.startUrl
|
|
434
450
|
|> Encode.string
|
|
435
451
|
|> Just
|
|
436
452
|
)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
module Pages.Navigation exposing (Navigation(..), LoadingState(..))
|
|
2
|
+
|
|
3
|
+
{-| `elm-pages` maintains a single `Maybe Navigation` state which is accessible from your `Route` modules through `app.navigation`.
|
|
4
|
+
|
|
5
|
+
You can use it to show a loading indicator while a page is loading:
|
|
6
|
+
|
|
7
|
+
import Pages.Navigation as Navigation
|
|
8
|
+
|
|
9
|
+
pageLoadingIndicator app =
|
|
10
|
+
case app.navigation of
|
|
11
|
+
Just (Navigation.Loading path _) ->
|
|
12
|
+
Spinner.view
|
|
13
|
+
|
|
14
|
+
Nothing ->
|
|
15
|
+
emptyView
|
|
16
|
+
|
|
17
|
+
emptyView : Html msg
|
|
18
|
+
emptyView =
|
|
19
|
+
Html.text ""
|
|
20
|
+
|
|
21
|
+
You can also use it to derive Pending UI or Optimistic UI from a pending form submission:
|
|
22
|
+
|
|
23
|
+
import Form
|
|
24
|
+
import Form.Handler
|
|
25
|
+
import Pages.Navigation as Navigation
|
|
26
|
+
|
|
27
|
+
view app =
|
|
28
|
+
let
|
|
29
|
+
optimisticProduct : Maybe Product
|
|
30
|
+
optimisticProduct =
|
|
31
|
+
case app.navigation of
|
|
32
|
+
Just (Navigation.Submitting formData) ->
|
|
33
|
+
formHandler
|
|
34
|
+
|> Form.Handler.run formData
|
|
35
|
+
|> Form.toResult
|
|
36
|
+
|> Result.toMaybe
|
|
37
|
+
|
|
38
|
+
Just (Navigation.LoadAfterSubmit formData path _) ->
|
|
39
|
+
formHandler
|
|
40
|
+
|> Form.Handler.run formData
|
|
41
|
+
|> Form.toResult
|
|
42
|
+
|> Result.toMaybe
|
|
43
|
+
|
|
44
|
+
Nothing ->
|
|
45
|
+
Nothing
|
|
46
|
+
in
|
|
47
|
+
-- our `productsView` function could show a loading spinner (Pending UI),
|
|
48
|
+
-- or it could assume the product will be created successfully (Optimistic UI) and
|
|
49
|
+
-- display it as a regular product in the list
|
|
50
|
+
productsView optimisticProduct app.data.products
|
|
51
|
+
|
|
52
|
+
allForms : Form.Handler.Handler String Product
|
|
53
|
+
allForms =
|
|
54
|
+
Form.Handler.init identity productForm
|
|
55
|
+
|
|
56
|
+
editItemForm : Form.HtmlForm String Product input msg
|
|
57
|
+
editItemForm =
|
|
58
|
+
Debug.todo "Form definition here"
|
|
59
|
+
|
|
60
|
+
@docs Navigation, LoadingState
|
|
61
|
+
|
|
62
|
+
-}
|
|
63
|
+
|
|
64
|
+
import Pages.FormData exposing (FormData)
|
|
65
|
+
import UrlPath exposing (UrlPath)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
{-| Represents the global page navigation state of the app.
|
|
69
|
+
|
|
70
|
+
- `Loading` - navigating to a page, for example from a link click, or from a programmatic navigation with `Browser.Navigation.pushUrl`.
|
|
71
|
+
- `Submitting` - submitting a form using the default submission strategy (note that Forms rendered with the [`Pages.Form.withConcurrent`](Pages-Form#withConcurrent) Option have their state managed in `app.concurrentSubmissions` instead of `app.navigation`).
|
|
72
|
+
- `LoadAfterSubmit` - the state immediately after `Submitting` - allows you to continue using the `FormData` from a submission while a data reload or redirect is occurring.
|
|
73
|
+
|
|
74
|
+
-}
|
|
75
|
+
type Navigation
|
|
76
|
+
= Submitting FormData
|
|
77
|
+
| LoadAfterSubmit FormData UrlPath LoadingState
|
|
78
|
+
| Loading UrlPath LoadingState
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
{-| -}
|
|
82
|
+
type LoadingState
|
|
83
|
+
= Redirecting
|
|
84
|
+
| Load
|
|
85
|
+
| ActionRedirect
|
package/src/Pages/PageUrl.elm
CHANGED
|
@@ -13,9 +13,9 @@ the query params are parsed into a `Dict String (List String)`.
|
|
|
13
13
|
-}
|
|
14
14
|
|
|
15
15
|
import Dict exposing (Dict)
|
|
16
|
-
import Path exposing (Path)
|
|
17
16
|
import QueryParams
|
|
18
17
|
import Url
|
|
18
|
+
import UrlPath exposing (UrlPath)
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
{-| -}
|
|
@@ -23,7 +23,7 @@ type alias PageUrl =
|
|
|
23
23
|
{ protocol : Url.Protocol
|
|
24
24
|
, host : String
|
|
25
25
|
, port_ : Maybe Int
|
|
26
|
-
, path :
|
|
26
|
+
, path : UrlPath
|
|
27
27
|
, query : Dict String (List String)
|
|
28
28
|
, fragment : Maybe String
|
|
29
29
|
}
|
|
@@ -35,7 +35,7 @@ toUrl url =
|
|
|
35
35
|
{ protocol = url.protocol
|
|
36
36
|
, host = url.host
|
|
37
37
|
, port_ = url.port_
|
|
38
|
-
, path = url.path |>
|
|
38
|
+
, path = url.path |> UrlPath.toRelative
|
|
39
39
|
, query =
|
|
40
40
|
if url.query |> Dict.isEmpty then
|
|
41
41
|
Nothing
|