elm-pages 2.1.7 → 2.1.11

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 (75) hide show
  1. package/generator/review/elm.json +34 -0
  2. package/generator/review/src/ReviewConfig.elm +10 -0
  3. package/generator/src/basepath-middleware.js +15 -9
  4. package/generator/src/build.js +77 -4
  5. package/generator/src/cli.js +13 -9
  6. package/generator/src/compile-elm.js +43 -0
  7. package/generator/src/dev-server.js +63 -11
  8. package/generator/src/error-formatter.js +62 -9
  9. package/generator/src/generate-template-module-connector.js +17 -4
  10. package/generator/src/init.js +4 -0
  11. package/generator/src/pre-render-html.js +19 -12
  12. package/generator/src/render-worker.js +0 -1
  13. package/generator/src/render.js +1 -2
  14. package/generator/src/seo-renderer.js +21 -2
  15. package/generator/static-code/hmr.js +43 -6
  16. package/generator/template/elm.json +13 -5
  17. package/generator/template/package.json +3 -2
  18. package/package.json +14 -8
  19. package/src/ApiRoute.elm +178 -0
  20. package/src/AriaLiveAnnouncer.elm +36 -0
  21. package/src/BuildError.elm +60 -0
  22. package/src/DataSource/File.elm +288 -0
  23. package/src/DataSource/Glob.elm +1050 -0
  24. package/src/DataSource/Http.elm +467 -0
  25. package/src/DataSource/Internal/Glob.elm +74 -0
  26. package/src/DataSource/Port.elm +87 -0
  27. package/src/DataSource/ServerRequest.elm +60 -0
  28. package/src/DataSource.elm +801 -0
  29. package/src/Head/Seo.elm +516 -0
  30. package/src/Head/Twitter.elm +109 -0
  31. package/src/Head.elm +452 -0
  32. package/src/HtmlPrinter.elm +27 -0
  33. package/src/Internal/ApiRoute.elm +89 -0
  34. package/src/Internal/OptimizedDecoder.elm +18 -0
  35. package/src/KeepOrDiscard.elm +6 -0
  36. package/src/OptimizedDecoder/Pipeline.elm +335 -0
  37. package/src/OptimizedDecoder.elm +818 -0
  38. package/src/Pages/ContentCache.elm +248 -0
  39. package/src/Pages/Flags.elm +26 -0
  40. package/src/Pages/Http.elm +10 -0
  41. package/src/Pages/Internal/ApplicationType.elm +6 -0
  42. package/src/Pages/Internal/NotFoundReason.elm +256 -0
  43. package/src/Pages/Internal/Platform/Cli.elm +1015 -0
  44. package/src/Pages/Internal/Platform/Effect.elm +14 -0
  45. package/src/Pages/Internal/Platform/StaticResponses.elm +540 -0
  46. package/src/Pages/Internal/Platform/ToJsPayload.elm +138 -0
  47. package/src/Pages/Internal/Platform.elm +745 -0
  48. package/src/Pages/Internal/RoutePattern.elm +122 -0
  49. package/src/Pages/Internal/Router.elm +116 -0
  50. package/src/Pages/Internal/StaticHttpBody.elm +54 -0
  51. package/src/Pages/Internal/String.elm +39 -0
  52. package/src/Pages/Manifest/Category.elm +240 -0
  53. package/src/Pages/Manifest.elm +412 -0
  54. package/src/Pages/PageUrl.elm +38 -0
  55. package/src/Pages/ProgramConfig.elm +73 -0
  56. package/src/Pages/Review/NoContractViolations.elm +397 -0
  57. package/src/Pages/Secrets.elm +83 -0
  58. package/src/Pages/SiteConfig.elm +13 -0
  59. package/src/Pages/StaticHttp/Request.elm +42 -0
  60. package/src/Pages/StaticHttpRequest.elm +320 -0
  61. package/src/Pages/Url.elm +60 -0
  62. package/src/Path.elm +96 -0
  63. package/src/QueryParams.elm +216 -0
  64. package/src/RenderRequest.elm +163 -0
  65. package/src/RequestsAndPending.elm +20 -0
  66. package/src/Secrets.elm +111 -0
  67. package/src/SecretsDict.elm +45 -0
  68. package/src/StructuredData.elm +236 -0
  69. package/src/TerminalText.elm +242 -0
  70. package/src/Test/Html/Internal/ElmHtml/Constants.elm +53 -0
  71. package/src/Test/Html/Internal/ElmHtml/Helpers.elm +17 -0
  72. package/src/Test/Html/Internal/ElmHtml/InternalTypes.elm +529 -0
  73. package/src/Test/Html/Internal/ElmHtml/Markdown.elm +56 -0
  74. package/src/Test/Html/Internal/ElmHtml/ToString.elm +197 -0
  75. package/src/Test/Internal/KernelConstants.elm +34 -0
@@ -0,0 +1,745 @@
1
+ module Pages.Internal.Platform exposing (Flags, Model, Msg, Program, application)
2
+
3
+ {-| Exposed for internal use only (used in generated code).
4
+
5
+ @docs Flags, Model, Msg, Program, application
6
+
7
+ -}
8
+
9
+ import AriaLiveAnnouncer
10
+ import Browser
11
+ import Browser.Dom as Dom
12
+ import Browser.Navigation
13
+ import BuildError exposing (BuildError)
14
+ import Html exposing (Html)
15
+ import Html.Attributes as Attr
16
+ import Http
17
+ import Json.Decode as Decode
18
+ import Json.Encode
19
+ import Pages.ContentCache as ContentCache exposing (ContentCache, ContentJson, contentJsonDecoder)
20
+ import Pages.Flags
21
+ import Pages.Internal.ApplicationType as ApplicationType
22
+ import Pages.Internal.NotFoundReason
23
+ import Pages.Internal.String as String
24
+ import Pages.ProgramConfig exposing (ProgramConfig)
25
+ import Pages.StaticHttpRequest as StaticHttpRequest
26
+ import Path exposing (Path)
27
+ import QueryParams
28
+ import Task
29
+ import Url exposing (Url)
30
+
31
+
32
+ {-| -}
33
+ type alias Program userModel userMsg pageData sharedData =
34
+ Platform.Program Flags (Model userModel pageData sharedData) (Msg userMsg)
35
+
36
+
37
+ mainView :
38
+ ProgramConfig userMsg userModel route siteData pageData sharedData
39
+ -> Model userModel pageData sharedData
40
+ -> { title : String, body : Html userMsg }
41
+ mainView config model =
42
+ let
43
+ urls : { currentUrl : Url, basePath : List String }
44
+ urls =
45
+ { currentUrl = model.url
46
+ , basePath = config.basePath
47
+ }
48
+ in
49
+ case ContentCache.notFoundReason model.contentCache urls of
50
+ Just notFoundReason ->
51
+ Pages.Internal.NotFoundReason.document config.pathPatterns notFoundReason
52
+
53
+ Nothing ->
54
+ case model.pageData of
55
+ Ok pageData ->
56
+ (config.view
57
+ { path = ContentCache.pathForUrl urls |> Path.join
58
+ , route = config.urlToRoute model.url
59
+ }
60
+ Nothing
61
+ pageData.sharedData
62
+ pageData.pageData
63
+ |> .view
64
+ )
65
+ pageData.userModel
66
+
67
+ Err error ->
68
+ { title = "Page Data Error"
69
+ , body =
70
+ Html.div [] [ Html.text error ]
71
+ }
72
+
73
+
74
+ urlsToPagePath :
75
+ { currentUrl : Url, basePath : List String }
76
+ -> Path
77
+ urlsToPagePath urls =
78
+ urls.currentUrl.path
79
+ |> String.chopForwardSlashes
80
+ |> String.split "/"
81
+ |> List.filter ((/=) "")
82
+ |> List.drop (List.length urls.basePath)
83
+ |> Path.join
84
+
85
+
86
+ view :
87
+ ProgramConfig userMsg userModel route siteData pageData sharedData
88
+ -> Model userModel pageData sharedData
89
+ -> Browser.Document (Msg userMsg)
90
+ view config model =
91
+ let
92
+ { title, body } =
93
+ mainView config model
94
+ in
95
+ { title = title
96
+ , body =
97
+ [ onViewChangeElement model.url
98
+ , body |> Html.map UserMsg
99
+ , AriaLiveAnnouncer.view model.ariaNavigationAnnouncement
100
+ ]
101
+ }
102
+
103
+
104
+ onViewChangeElement : Url -> Html msg
105
+ onViewChangeElement currentUrl =
106
+ -- this is a hidden tag
107
+ -- it is used from the JS-side to reliably
108
+ -- check when Elm has changed pages
109
+ -- (and completed rendering the view)
110
+ Html.div
111
+ [ Attr.attribute "data-url" (Url.toString currentUrl)
112
+ , Attr.attribute "display" "none"
113
+ ]
114
+ []
115
+
116
+
117
+ {-| -}
118
+ type alias Flags =
119
+ Decode.Value
120
+
121
+
122
+ {-| -}
123
+ init :
124
+ ProgramConfig userMsg userModel route staticData pageData sharedData
125
+ -> Flags
126
+ -> Url
127
+ -> Browser.Navigation.Key
128
+ -> ( Model userModel pageData sharedData, Cmd (Msg userMsg) )
129
+ init config flags url key =
130
+ let
131
+ contentCache : ContentCache
132
+ contentCache =
133
+ ContentCache.init
134
+ (Maybe.map
135
+ (\cj ->
136
+ ( currentPath
137
+ , cj
138
+ )
139
+ )
140
+ contentJson
141
+ )
142
+
143
+ currentPath : List String
144
+ currentPath =
145
+ flags
146
+ |> Decode.decodeValue
147
+ (Decode.at [ "contentJson", "path" ]
148
+ (Decode.string
149
+ |> Decode.map Path.fromString
150
+ |> Decode.map Path.toSegments
151
+ )
152
+ )
153
+ |> Result.mapError Decode.errorToString
154
+ |> Result.toMaybe
155
+ |> Maybe.withDefault []
156
+
157
+ contentJson : Maybe ContentJson
158
+ contentJson =
159
+ flags
160
+ |> Decode.decodeValue (Decode.field "contentJson" contentJsonDecoder)
161
+ |> Result.toMaybe
162
+
163
+ urls : { currentUrl : Url, basePath : List String }
164
+ urls =
165
+ { currentUrl = url
166
+ , basePath = config.basePath
167
+ }
168
+ in
169
+ case contentJson |> Maybe.map .staticData of
170
+ Just justContentJson ->
171
+ let
172
+ pageDataResult : Result BuildError pageData
173
+ pageDataResult =
174
+ StaticHttpRequest.resolve ApplicationType.Browser
175
+ (config.data (config.urlToRoute url))
176
+ justContentJson
177
+ |> Result.mapError (StaticHttpRequest.toBuildError url.path)
178
+
179
+ sharedDataResult : Result BuildError sharedData
180
+ sharedDataResult =
181
+ StaticHttpRequest.resolve ApplicationType.Browser
182
+ config.sharedData
183
+ justContentJson
184
+ |> Result.mapError (StaticHttpRequest.toBuildError url.path)
185
+
186
+ pagePath : Path
187
+ pagePath =
188
+ urlsToPagePath urls
189
+ in
190
+ case Result.map2 Tuple.pair sharedDataResult pageDataResult of
191
+ Ok ( sharedData, pageData ) ->
192
+ let
193
+ userFlags : Pages.Flags.Flags
194
+ userFlags =
195
+ flags
196
+ |> Decode.decodeValue
197
+ (Decode.field "userFlags" Decode.value)
198
+ |> Result.withDefault Json.Encode.null
199
+ |> Pages.Flags.BrowserFlags
200
+
201
+ ( userModel, userCmd ) =
202
+ Just
203
+ { path =
204
+ { path = pagePath
205
+ , query = url.query
206
+ , fragment = url.fragment
207
+ }
208
+ , metadata = config.urlToRoute url
209
+ , pageUrl =
210
+ Just
211
+ { protocol = url.protocol
212
+ , host = url.host
213
+ , port_ = url.port_
214
+ , path = pagePath
215
+ , query = url.query |> Maybe.map QueryParams.fromString
216
+ , fragment = url.fragment
217
+ }
218
+ }
219
+ |> config.init userFlags sharedData pageData (Just key)
220
+
221
+ cmd : Cmd (Msg userMsg)
222
+ cmd =
223
+ [ userCmd
224
+ |> Cmd.map UserMsg
225
+ |> Just
226
+ , contentCache
227
+ |> ContentCache.lazyLoad urls
228
+ |> Task.attempt UpdateCache
229
+ |> Just
230
+ ]
231
+ |> List.filterMap identity
232
+ |> Cmd.batch
233
+
234
+ initialModel : Model userModel pageData sharedData
235
+ initialModel =
236
+ { key = key
237
+ , url = url
238
+ , contentCache = contentCache
239
+ , pageData =
240
+ Ok
241
+ { pageData = pageData
242
+ , sharedData = sharedData
243
+ , userModel = userModel
244
+ }
245
+ , ariaNavigationAnnouncement = ""
246
+ , userFlags = flags
247
+ }
248
+ in
249
+ ( { initialModel
250
+ | ariaNavigationAnnouncement = mainView config initialModel |> .title
251
+ }
252
+ , cmd
253
+ )
254
+
255
+ Err error ->
256
+ ( { key = key
257
+ , url = url
258
+ , contentCache = contentCache
259
+ , pageData = BuildError.errorToString error |> Err
260
+ , ariaNavigationAnnouncement = "Error"
261
+ , userFlags = flags
262
+ }
263
+ , Cmd.none
264
+ )
265
+
266
+ Nothing ->
267
+ ( { key = key
268
+ , url = url
269
+ , contentCache = contentCache
270
+ , pageData = Err "TODO"
271
+ , ariaNavigationAnnouncement = "Error"
272
+ , userFlags = flags
273
+ }
274
+ , Cmd.none
275
+ )
276
+
277
+
278
+ {-| -}
279
+ type Msg userMsg
280
+ = LinkClicked Browser.UrlRequest
281
+ | UrlChanged Url
282
+ | UserMsg userMsg
283
+ | UpdateCache (Result Http.Error ( Url, ContentJson, ContentCache ))
284
+ | UpdateCacheAndUrl Url (Result Http.Error ( Url, ContentJson, ContentCache ))
285
+ | PageScrollComplete
286
+ | HotReloadComplete ContentJson
287
+ | NoOp
288
+
289
+
290
+ {-| -}
291
+ type alias Model userModel pageData sharedData =
292
+ { key : Browser.Navigation.Key
293
+ , url : Url
294
+ , contentCache : ContentCache
295
+ , ariaNavigationAnnouncement : String
296
+ , pageData :
297
+ Result
298
+ String
299
+ { userModel : userModel
300
+ , pageData : pageData
301
+ , sharedData : sharedData
302
+ }
303
+ , userFlags : Decode.Value
304
+ }
305
+
306
+
307
+ {-| -}
308
+ update :
309
+ ProgramConfig userMsg userModel route siteData pageData sharedData
310
+ -> Msg userMsg
311
+ -> Model userModel pageData sharedData
312
+ -> ( Model userModel pageData sharedData, Cmd (Msg userMsg) )
313
+ update config appMsg model =
314
+ case appMsg of
315
+ LinkClicked urlRequest ->
316
+ case urlRequest of
317
+ Browser.Internal url ->
318
+ let
319
+ navigatingToSamePage : Bool
320
+ navigatingToSamePage =
321
+ (url.path == model.url.path) && (url /= model.url)
322
+ in
323
+ if navigatingToSamePage then
324
+ -- this is a workaround for an issue with anchor fragment navigation
325
+ -- see https://github.com/elm/browser/issues/39
326
+ ( model, Browser.Navigation.load (Url.toString url) )
327
+
328
+ else
329
+ ( model
330
+ , Browser.Navigation.pushUrl model.key (Url.toString url)
331
+ )
332
+
333
+ Browser.External href ->
334
+ ( model, Browser.Navigation.load href )
335
+
336
+ UrlChanged url ->
337
+ let
338
+ navigatingToSamePage : Bool
339
+ navigatingToSamePage =
340
+ (url.path == model.url.path) && (url /= model.url)
341
+
342
+ urls : { currentUrl : Url, basePath : List String }
343
+ urls =
344
+ { currentUrl = url
345
+ , basePath = config.basePath
346
+ }
347
+ in
348
+ if navigatingToSamePage then
349
+ -- this saves a few CPU cycles, but also
350
+ -- makes sure we don't send an UpdateCacheAndUrl
351
+ -- which scrolls to the top after page changes.
352
+ -- This is important because we may have just scrolled
353
+ -- to a specific page location for an anchor link.
354
+ model.pageData
355
+ |> Result.map
356
+ (\pageData ->
357
+ let
358
+ updatedPageData : Result String { userModel : userModel, sharedData : sharedData, pageData : pageData }
359
+ updatedPageData =
360
+ Ok
361
+ { userModel = userModel
362
+ , sharedData = pageData.sharedData
363
+ , pageData = pageData.pageData
364
+ }
365
+
366
+ ( userModel, userCmd ) =
367
+ config.update
368
+ pageData.sharedData
369
+ pageData.pageData
370
+ (Just model.key)
371
+ (config.onPageChange
372
+ { protocol = model.url.protocol
373
+ , host = model.url.host
374
+ , port_ = model.url.port_
375
+ , path = urlPathToPath config urls.currentUrl
376
+ , query = url.query
377
+ , fragment = url.fragment
378
+ , metadata = config.urlToRoute url
379
+ }
380
+ )
381
+ pageData.userModel
382
+ in
383
+ ( { model
384
+ | url = url
385
+ , pageData = updatedPageData
386
+ }
387
+ , Cmd.none
388
+ --Cmd.batch
389
+ -- [ userCmd |> Cmd.map UserMsg
390
+ -- , Task.perform (\_ -> PageScrollComplete) (Dom.setViewport 0 0)
391
+ -- ]
392
+ )
393
+ )
394
+ |> Result.withDefault ( model, Cmd.none )
395
+
396
+ else
397
+ ( model
398
+ , model.contentCache
399
+ |> ContentCache.lazyLoad urls
400
+ |> Task.attempt (UpdateCacheAndUrl url)
401
+ )
402
+
403
+ UserMsg userMsg ->
404
+ case model.pageData of
405
+ Ok pageData ->
406
+ let
407
+ ( userModel, userCmd ) =
408
+ config.update pageData.sharedData pageData.pageData (Just model.key) userMsg pageData.userModel
409
+
410
+ updatedPageData : Result error { userModel : userModel, pageData : pageData, sharedData : sharedData }
411
+ updatedPageData =
412
+ Ok { pageData | userModel = userModel }
413
+ in
414
+ ( { model | pageData = updatedPageData }, userCmd |> Cmd.map UserMsg )
415
+
416
+ Err error ->
417
+ ( model, Cmd.none )
418
+
419
+ UpdateCache cacheUpdateResult ->
420
+ case cacheUpdateResult of
421
+ -- TODO can there be race conditions here? Might need to set something in the model
422
+ -- to keep track of the last url change
423
+ Ok ( url, contentJson, updatedCache ) ->
424
+ ( { model | contentCache = updatedCache }
425
+ , Cmd.none
426
+ )
427
+
428
+ Err _ ->
429
+ -- TODO handle error
430
+ ( model, Cmd.none )
431
+
432
+ UpdateCacheAndUrl url cacheUpdateResult ->
433
+ case
434
+ Result.map2 Tuple.pair (cacheUpdateResult |> Result.mapError (\error -> "Http error")) model.pageData
435
+ of
436
+ -- TODO can there be race conditions here? Might need to set something in the model
437
+ -- to keep track of the last url change
438
+ Ok ( ( _, contentJson, updatedCache ), pageData ) ->
439
+ let
440
+ updatedPageData : Result String { userModel : userModel, sharedData : sharedData, pageData : pageData }
441
+ updatedPageData =
442
+ updatedPageStaticData
443
+ |> Result.map
444
+ (\pageStaticData ->
445
+ { userModel = userModel
446
+ , sharedData = pageData.sharedData
447
+ , pageData = pageStaticData
448
+ }
449
+ )
450
+
451
+ updatedPageStaticData : Result String pageData
452
+ updatedPageStaticData =
453
+ StaticHttpRequest.resolve ApplicationType.Browser
454
+ (config.data (config.urlToRoute url))
455
+ contentJson.staticData
456
+ |> Result.mapError
457
+ (\error ->
458
+ error
459
+ |> StaticHttpRequest.toBuildError ""
460
+ |> BuildError.errorToString
461
+ )
462
+
463
+ ( userModel, userCmd ) =
464
+ config.update
465
+ pageData.sharedData
466
+ (updatedPageStaticData |> Result.withDefault pageData.pageData)
467
+ (Just model.key)
468
+ (config.onPageChange
469
+ { protocol = model.url.protocol
470
+ , host = model.url.host
471
+ , port_ = model.url.port_
472
+ , path = url |> urlPathToPath config
473
+ , query = url.query
474
+ , fragment = url.fragment
475
+ , metadata = config.urlToRoute url
476
+ }
477
+ )
478
+ pageData.userModel
479
+
480
+ updatedModel : Model userModel pageData sharedData
481
+ updatedModel =
482
+ { model
483
+ | url = url
484
+ , contentCache = updatedCache
485
+ , pageData = updatedPageData
486
+ }
487
+ in
488
+ ( { updatedModel
489
+ | ariaNavigationAnnouncement = mainView config updatedModel |> .title
490
+ }
491
+ , Cmd.batch
492
+ [ userCmd |> Cmd.map UserMsg
493
+ , Task.perform (\_ -> PageScrollComplete) (Dom.setViewport 0 0)
494
+ ]
495
+ )
496
+
497
+ Err error ->
498
+ {-
499
+ When there is an error loading the content.json, we are either
500
+ 1) in the dev server, and should show the relevant DataSource error for the page
501
+ we're navigating to. This could be done more cleanly, but it's simplest to just
502
+ do a fresh page load and use the code path for presenting an error for a fresh page.
503
+ 2) In a production app. That means we had a successful build, so there were no DataSource failures,
504
+ so the app must be stale (unless it's in some unexpected state from a bug). In the future,
505
+ it probably makes sense to include some sort of hash of the app version we are fetching, match
506
+ it with the current version that's running, and perform this logic when we see there is a mismatch.
507
+ But for now, if there is any error we do a full page load (not a single-page navigation), which
508
+ gives us a fresh version of the app to make sure things are in sync.
509
+
510
+ -}
511
+ ( model
512
+ , url
513
+ |> Url.toString
514
+ |> Browser.Navigation.load
515
+ )
516
+
517
+ PageScrollComplete ->
518
+ ( model, Cmd.none )
519
+
520
+ HotReloadComplete contentJson ->
521
+ let
522
+ urls : { currentUrl : Url, basePath : List String }
523
+ urls =
524
+ { currentUrl = model.url
525
+ , basePath = config.basePath
526
+ }
527
+
528
+ pageDataResult : Result BuildError pageData
529
+ pageDataResult =
530
+ StaticHttpRequest.resolve ApplicationType.Browser
531
+ (config.data (config.urlToRoute model.url))
532
+ contentJson.staticData
533
+ |> Result.mapError (StaticHttpRequest.toBuildError model.url.path)
534
+
535
+ sharedDataResult : Result BuildError sharedData
536
+ sharedDataResult =
537
+ StaticHttpRequest.resolve ApplicationType.Browser
538
+ config.sharedData
539
+ contentJson.staticData
540
+ |> Result.mapError (StaticHttpRequest.toBuildError model.url.path)
541
+
542
+ from404ToNon404 : Bool
543
+ from404ToNon404 =
544
+ not contentJson.is404
545
+ && was404
546
+
547
+ was404 : Bool
548
+ was404 =
549
+ ContentCache.is404 model.contentCache urls
550
+ in
551
+ case Result.map2 Tuple.pair sharedDataResult pageDataResult of
552
+ Ok ( sharedData, pageData ) ->
553
+ let
554
+ updateResult : Maybe ( userModel, Cmd userMsg )
555
+ updateResult =
556
+ if from404ToNon404 then
557
+ case model.pageData of
558
+ Ok pageData_ ->
559
+ config.update
560
+ sharedData
561
+ pageData
562
+ (Just model.key)
563
+ (config.onPageChange
564
+ { protocol = model.url.protocol
565
+ , host = model.url.host
566
+ , port_ = model.url.port_
567
+ , path = model.url |> urlPathToPath config
568
+ , query = model.url.query
569
+ , fragment = model.url.fragment
570
+ , metadata = config.urlToRoute model.url
571
+ }
572
+ )
573
+ pageData_.userModel
574
+ |> Just
575
+
576
+ Err error ->
577
+ Nothing
578
+
579
+ else
580
+ Nothing
581
+ in
582
+ case updateResult of
583
+ Just ( userModel, userCmd ) ->
584
+ ( { model
585
+ | contentCache =
586
+ ContentCache.init
587
+ (Just
588
+ ( urls.currentUrl
589
+ |> config.urlToRoute
590
+ |> config.routeToPath
591
+ , contentJson
592
+ )
593
+ )
594
+ , pageData =
595
+ Ok
596
+ { pageData = pageData
597
+ , sharedData = sharedData
598
+ , userModel = userModel
599
+ }
600
+ }
601
+ , Cmd.batch
602
+ [ userCmd |> Cmd.map UserMsg
603
+ ]
604
+ )
605
+
606
+ Nothing ->
607
+ let
608
+ pagePath : Path
609
+ pagePath =
610
+ urlsToPagePath urls
611
+
612
+ userFlags : Pages.Flags.Flags
613
+ userFlags =
614
+ model.userFlags
615
+ |> Decode.decodeValue
616
+ (Decode.field "userFlags" Decode.value)
617
+ |> Result.withDefault Json.Encode.null
618
+ |> Pages.Flags.BrowserFlags
619
+
620
+ ( userModel, userCmd ) =
621
+ Just
622
+ { path =
623
+ { path = pagePath
624
+ , query = model.url.query
625
+ , fragment = model.url.fragment
626
+ }
627
+ , metadata = config.urlToRoute model.url
628
+ , pageUrl =
629
+ Just
630
+ { protocol = model.url.protocol
631
+ , host = model.url.host
632
+ , port_ = model.url.port_
633
+ , path = pagePath
634
+ , query = model.url.query |> Maybe.map QueryParams.fromString
635
+ , fragment = model.url.fragment
636
+ }
637
+ }
638
+ |> config.init userFlags sharedData pageData (Just model.key)
639
+ in
640
+ ( { model
641
+ | contentCache =
642
+ ContentCache.init
643
+ (Just
644
+ ( urls.currentUrl
645
+ |> config.urlToRoute
646
+ |> config.routeToPath
647
+ , contentJson
648
+ )
649
+ )
650
+ , pageData =
651
+ model.pageData
652
+ |> Result.map
653
+ (\previousPageData ->
654
+ { pageData = pageData
655
+ , sharedData = sharedData
656
+ , userModel = previousPageData.userModel
657
+ }
658
+ )
659
+ |> Result.withDefault
660
+ { pageData = pageData
661
+ , sharedData = sharedData
662
+ , userModel = userModel
663
+ }
664
+ |> Ok
665
+ }
666
+ , userCmd |> Cmd.map UserMsg
667
+ )
668
+
669
+ Err error ->
670
+ ( { model
671
+ | contentCache =
672
+ ContentCache.init
673
+ (Just
674
+ ( urls.currentUrl
675
+ |> config.urlToRoute
676
+ |> config.routeToPath
677
+ , contentJson
678
+ )
679
+ )
680
+ }
681
+ , Cmd.none
682
+ )
683
+
684
+ NoOp ->
685
+ ( model, Cmd.none )
686
+
687
+
688
+ {-| -}
689
+ application :
690
+ ProgramConfig userMsg userModel route staticData pageData sharedData
691
+ -> Platform.Program Flags (Model userModel pageData sharedData) (Msg userMsg)
692
+ application config =
693
+ Browser.application
694
+ { init =
695
+ \flags url key ->
696
+ init config flags url key
697
+ , view = view config
698
+ , update = update config
699
+ , subscriptions =
700
+ \model ->
701
+ let
702
+ urls : { currentUrl : Url }
703
+ urls =
704
+ { currentUrl = model.url }
705
+ in
706
+ case model.pageData of
707
+ Ok pageData ->
708
+ Sub.batch
709
+ [ config.subscriptions (model.url |> config.urlToRoute)
710
+ (urls.currentUrl |> config.urlToRoute |> config.routeToPath |> Path.join)
711
+ pageData.userModel
712
+ |> Sub.map UserMsg
713
+ , config.fromJsPort
714
+ |> Sub.map
715
+ (\decodeValue ->
716
+ case decodeValue |> Decode.decodeValue (Decode.field "contentJson" contentJsonDecoder) of
717
+ Ok contentJson ->
718
+ HotReloadComplete contentJson
719
+
720
+ Err _ ->
721
+ -- TODO should be no message here
722
+ NoOp
723
+ )
724
+ ]
725
+
726
+ Err _ ->
727
+ config.fromJsPort
728
+ |> Sub.map
729
+ (\decodeValue ->
730
+ case decodeValue |> Decode.decodeValue (Decode.field "contentJson" contentJsonDecoder) of
731
+ Ok contentJson ->
732
+ HotReloadComplete contentJson
733
+
734
+ Err _ ->
735
+ -- TODO should be no message here
736
+ NoOp
737
+ )
738
+ , onUrlChange = UrlChanged
739
+ , onUrlRequest = LinkClicked
740
+ }
741
+
742
+
743
+ urlPathToPath : ProgramConfig userMsg userModel route siteData pageData sharedData -> Url -> Path
744
+ urlPathToPath config urls =
745
+ urls.path |> Path.fromString