elm-pages 3.0.0-beta.3 → 3.0.0-beta.30
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/codegen/{elm-pages-codegen.js → elm-pages-codegen.cjs} +2864 -2589
- 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 +1327 -122
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +15295 -13271
- 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 +8 -6
- 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/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 +1327 -122
- package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +14621 -12637
- 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 +8 -8
- package/generator/src/RouteBuilder.elm +113 -107
- package/generator/src/SharedTemplate.elm +3 -2
- package/generator/src/SiteConfig.elm +3 -2
- package/generator/src/basepath-middleware.js +3 -3
- package/generator/src/build.js +123 -87
- package/generator/src/cli.js +256 -77
- package/generator/src/codegen.js +29 -27
- package/generator/src/compatibility-key.js +3 -0
- package/generator/src/compile-elm.js +25 -25
- package/generator/src/config.js +39 -0
- package/generator/src/copy-dir.js +2 -2
- package/generator/src/dev-server.js +150 -133
- 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 -22
- 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 +322 -142
- package/generator/src/request-cache.js +252 -163
- package/generator/src/rewrite-client-elm-json.js +5 -5
- package/generator/src/rewrite-elm-json.js +7 -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/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 +34 -25
- package/generator/template/package.json +10 -4
- package/package.json +23 -22
- 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 +128 -43
- package/src/{DataSource → BackendTask}/Glob.elm +136 -125
- package/src/BackendTask/Http.elm +673 -0
- package/src/{DataSource → BackendTask}/Internal/Glob.elm +1 -1
- package/src/BackendTask/Internal/Request.elm +28 -0
- package/src/BackendTask/Random.elm +79 -0
- package/src/BackendTask/Time.elm +47 -0
- package/src/BackendTask.elm +537 -0
- package/src/FatalError.elm +89 -0
- package/src/Form/Field.elm +21 -9
- package/src/Form/FieldView.elm +94 -14
- package/src/Form.elm +275 -400
- 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/FormState.elm +6 -5
- package/src/Pages/GeneratorProgramConfig.elm +15 -0
- package/src/Pages/Internal/FatalError.elm +5 -0
- package/src/Pages/Internal/Form.elm +21 -1
- package/src/Pages/{Msg.elm → Internal/Msg.elm} +26 -16
- package/src/Pages/Internal/Platform/Cli.elm +507 -763
- 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 +373 -0
- package/src/Pages/Internal/Platform/StaticResponses.elm +73 -270
- package/src/Pages/Internal/Platform/ToJsPayload.elm +4 -7
- package/src/Pages/Internal/Platform.elm +215 -102
- package/src/Pages/Internal/Script.elm +17 -0
- package/src/Pages/Internal/StaticHttpBody.elm +35 -1
- package/src/Pages/Manifest.elm +29 -4
- package/src/Pages/PageUrl.elm +23 -9
- package/src/Pages/ProgramConfig.elm +14 -10
- package/src/Pages/Script.elm +109 -0
- package/src/Pages/SiteConfig.elm +3 -2
- package/src/Pages/StaticHttp/Request.elm +2 -2
- package/src/Pages/StaticHttpRequest.elm +23 -98
- package/src/PagesMsg.elm +92 -0
- package/src/Path.elm +16 -19
- package/src/QueryParams.elm +21 -172
- package/src/RequestsAndPending.elm +8 -19
- package/src/Result/Extra.elm +26 -0
- package/src/Scaffold/Form.elm +484 -0
- package/src/Scaffold/Route.elm +1376 -0
- package/src/Server/Request.elm +43 -37
- package/src/Server/Session.elm +34 -34
- package/src/Server/SetCookie.elm +1 -1
- package/src/Test/Html/Internal/ElmHtml/ToString.elm +8 -9
- 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/Pages/Generate.elm +0 -800
package/src/Head.elm
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
module Head exposing
|
|
2
2
|
( Tag, metaName, metaProperty, metaRedirect
|
|
3
3
|
, rssLink, sitemapLink, rootLanguage, manifestLink
|
|
4
|
+
, nonLoadingNode
|
|
4
5
|
, structuredData
|
|
5
6
|
, AttributeValue
|
|
6
7
|
, currentPageFullUrl, urlAttribute, raw
|
|
@@ -8,18 +9,124 @@ module Head exposing
|
|
|
8
9
|
, toJson, canonicalLink
|
|
9
10
|
)
|
|
10
11
|
|
|
11
|
-
{-| This module contains
|
|
12
|
-
|
|
13
|
-
when
|
|
14
|
-
|
|
15
|
-
so you can use the `Tag` type in your type annotations.
|
|
12
|
+
{-| This module contains functions for building up
|
|
13
|
+
tags with metadata that will be rendered into the page's `<head>` tag
|
|
14
|
+
when your page is pre-rendered (or server-rendered, in the case of your server-rendered Route Modules). See also [`Head.Seo`](Head-Seo),
|
|
15
|
+
which has some helper functions for defining OpenGraph and Twitter tags.
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
One of the unique benefits of using `elm-pages` is that all of your routes (both pre-rendered and server-rendered) fully
|
|
18
|
+
render the HTML of your page. That includes the full initial `view` (with the BackendTask resolved, and the `Model` from `init`).
|
|
19
|
+
The HTML response also includes all of the `Head` tags, which are defined in two places:
|
|
20
|
+
|
|
21
|
+
1. `app/Site.elm` - there is a `head` definition in `Site.elm` where you define global head tags that will be included on every rendered page.
|
|
22
|
+
|
|
23
|
+
2. In each Route Module - there is a `head` function where you have access to both the resolved `BackendTask` and the `RouteParams` for the page and can return head tags based on that.
|
|
24
|
+
|
|
25
|
+
Here is a common set of global head tags that we can define in `Site.elm`:
|
|
26
|
+
|
|
27
|
+
module Site exposing (canonicalUrl, config)
|
|
28
|
+
|
|
29
|
+
import BackendTask exposing (BackendTask)
|
|
30
|
+
import Head
|
|
31
|
+
import MimeType
|
|
32
|
+
import SiteConfig exposing (SiteConfig)
|
|
33
|
+
|
|
34
|
+
config : SiteConfig
|
|
35
|
+
config =
|
|
36
|
+
{ canonicalUrl = "<https://elm-pages.com">
|
|
37
|
+
, head = head
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
head : BackendTask (List Head.Tag)
|
|
41
|
+
head =
|
|
42
|
+
[ Head.metaName "viewport" (Head.raw "width=device-width,initial-scale=1")
|
|
43
|
+
, Head.metaName "mobile-web-app-capable" (Head.raw "yes")
|
|
44
|
+
, Head.metaName "theme-color" (Head.raw "#ffffff")
|
|
45
|
+
, Head.metaName "apple-mobile-web-app-capable" (Head.raw "yes")
|
|
46
|
+
, Head.metaName "apple-mobile-web-app-status-bar-style" (Head.raw "black-translucent")
|
|
47
|
+
, Head.icon [ ( 32, 32 ) ] MimeType.Png (cloudinaryIcon MimeType.Png 32)
|
|
48
|
+
, Head.icon [ ( 16, 16 ) ] MimeType.Png (cloudinaryIcon MimeType.Png 16)
|
|
49
|
+
, Head.appleTouchIcon (Just 180) (cloudinaryIcon MimeType.Png 180)
|
|
50
|
+
, Head.appleTouchIcon (Just 192) (cloudinaryIcon MimeType.Png 192)
|
|
51
|
+
]
|
|
52
|
+
|> BackendTask.succeed
|
|
53
|
+
|
|
54
|
+
And here is a `head` function for a Route Module for a blog post. Note that we have access to our `BackendTask` Data and
|
|
55
|
+
are using it to populate article metadata like the article's image, publish date, etc.
|
|
56
|
+
|
|
57
|
+
import Article
|
|
58
|
+
import BackendTask
|
|
59
|
+
import Date
|
|
60
|
+
import Head
|
|
61
|
+
import Head.Seo
|
|
62
|
+
import Path
|
|
63
|
+
import Route exposing (Route)
|
|
64
|
+
import RouteBuilder exposing (App, StatelessRoute)
|
|
65
|
+
|
|
66
|
+
type alias RouteParams =
|
|
67
|
+
{ slug : String }
|
|
68
|
+
|
|
69
|
+
type alias Data =
|
|
70
|
+
{ metadata : ArticleMetadata
|
|
71
|
+
, body : List Markdown.Block.Block
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
route : StatelessRoute RouteParams Data ActionData
|
|
75
|
+
route =
|
|
76
|
+
RouteBuilder.preRender
|
|
77
|
+
{ data = data
|
|
78
|
+
, head = head
|
|
79
|
+
, pages = pages
|
|
80
|
+
}
|
|
81
|
+
|> RouteBuilder.buildNoState { view = view }
|
|
82
|
+
|
|
83
|
+
head :
|
|
84
|
+
App Data ActionData RouteParams
|
|
85
|
+
-> List Head.Tag
|
|
86
|
+
head static =
|
|
87
|
+
let
|
|
88
|
+
metadata =
|
|
89
|
+
static.data.metadata
|
|
90
|
+
in
|
|
91
|
+
Head.Seo.summaryLarge
|
|
92
|
+
{ canonicalUrlOverride = Nothing
|
|
93
|
+
, siteName = "elm-pages"
|
|
94
|
+
, image =
|
|
95
|
+
{ url = metadata.image
|
|
96
|
+
, alt = metadata.description
|
|
97
|
+
, dimensions = Nothing
|
|
98
|
+
, mimeType = Nothing
|
|
99
|
+
}
|
|
100
|
+
, description = metadata.description
|
|
101
|
+
, locale = Nothing
|
|
102
|
+
, title = metadata.title
|
|
103
|
+
}
|
|
104
|
+
|> Head.Seo.article
|
|
105
|
+
{ tags = []
|
|
106
|
+
, section = Nothing
|
|
107
|
+
, publishedTime = Just (DateOrDateTime.Date metadata.published)
|
|
108
|
+
, modifiedTime = Nothing
|
|
109
|
+
, expirationTime = Nothing
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
## Why is pre-rendered HTML important? Does it still matter for SEO?
|
|
114
|
+
|
|
115
|
+
Many search engines are able to execute JavaScript now. However, not all are, and even with crawlers like Google, there
|
|
116
|
+
is a longer lead time for your pages to be indexed when you have HTML with a blank page that is only visible after the JavaScript executes.
|
|
117
|
+
|
|
118
|
+
But most importantly, many tools that unfurl links will not execute JavaScript at all, but rather simply do a simple pass to parse your `<head>` tags.
|
|
119
|
+
It is not viable or reliable to add `<head>` tags for metadata on the client-side, it must be present in the initial HTML payload. Otherwise you may not
|
|
120
|
+
get unfurling preview content when you share a link to your site on Slack, Twitter, etc.
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
## Building up Head Tags
|
|
19
124
|
|
|
20
125
|
@docs Tag, metaName, metaProperty, metaRedirect
|
|
21
126
|
@docs rssLink, sitemapLink, rootLanguage, manifestLink
|
|
22
127
|
|
|
128
|
+
@docs nonLoadingNode
|
|
129
|
+
|
|
23
130
|
|
|
24
131
|
## Structured Data
|
|
25
132
|
|
|
@@ -45,9 +152,11 @@ writing a plugin package to extend `elm-pages`.
|
|
|
45
152
|
|
|
46
153
|
import Json.Encode
|
|
47
154
|
import LanguageTag exposing (LanguageTag)
|
|
155
|
+
import List.Extra
|
|
48
156
|
import MimeType
|
|
49
157
|
import Pages.Internal.String as String
|
|
50
158
|
import Pages.Url
|
|
159
|
+
import Regex
|
|
51
160
|
|
|
52
161
|
|
|
53
162
|
{-| Values that can be passed to the generated `Pages.application` config
|
|
@@ -57,6 +166,7 @@ type Tag
|
|
|
57
166
|
= Tag Details
|
|
58
167
|
| StructuredData Json.Encode.Value
|
|
59
168
|
| RootModifier String String
|
|
169
|
+
| Stripped String
|
|
60
170
|
|
|
61
171
|
|
|
62
172
|
type alias Details =
|
|
@@ -211,6 +321,120 @@ canonicalLink maybePath =
|
|
|
211
321
|
]
|
|
212
322
|
|
|
213
323
|
|
|
324
|
+
{-| Escape hatch for any head tags that don't have high-level helpers. This lets you build arbitrary head nodes as long as they
|
|
325
|
+
are not loading or preloading directives.
|
|
326
|
+
|
|
327
|
+
Tags that do loading/pre-loading will not work from this function. `elm-pages` uses ViteJS for loading assets like
|
|
328
|
+
script tags, stylesheets, fonts, etc., and allows you to customize which assets to preload and how through the elm-pages.config.mjs file.
|
|
329
|
+
See the full discussion of the design in [#339](https://github.com/dillonkearns/elm-pages/discussions/339).
|
|
330
|
+
|
|
331
|
+
So for example the following tags would _not_ load if defined through `nonLoadingNode`, and would instead need to be registered through Vite:
|
|
332
|
+
|
|
333
|
+
- `<script src="...">`
|
|
334
|
+
- `<link href="/style.css">`
|
|
335
|
+
- `<link rel="preload">`
|
|
336
|
+
|
|
337
|
+
The following tag would successfully render as it is a non-loading tag:
|
|
338
|
+
|
|
339
|
+
Head.nonLoadingNode "link"
|
|
340
|
+
[ ( "rel", Head.raw "alternate" )
|
|
341
|
+
, ( "type", Head.raw "application/atom+xml" )
|
|
342
|
+
, ( "title", Head.raw "News" )
|
|
343
|
+
, ( "href", Head.raw "/news/atom" )
|
|
344
|
+
]
|
|
345
|
+
|
|
346
|
+
Renders the head tag:
|
|
347
|
+
|
|
348
|
+
`<link rel="alternate" type="application/atom+xml" title="News" href="/news/atom">`
|
|
349
|
+
|
|
350
|
+
-}
|
|
351
|
+
nonLoadingNode : String -> List ( String, AttributeValue ) -> Tag
|
|
352
|
+
nonLoadingNode nodeName attributes =
|
|
353
|
+
let
|
|
354
|
+
relTag : Maybe AttributeValue
|
|
355
|
+
relTag =
|
|
356
|
+
attributes
|
|
357
|
+
|> List.Extra.find (\( key, _ ) -> key == "rel")
|
|
358
|
+
|> Maybe.map Tuple.second
|
|
359
|
+
|
|
360
|
+
isPreloadDirective : Bool
|
|
361
|
+
isPreloadDirective =
|
|
362
|
+
case relTag of
|
|
363
|
+
Just (Raw rel) ->
|
|
364
|
+
let
|
|
365
|
+
isLinkTag : Bool
|
|
366
|
+
isLinkTag =
|
|
367
|
+
nodeName |> matchesKeyword "link"
|
|
368
|
+
in
|
|
369
|
+
isLinkTag
|
|
370
|
+
&& (rel
|
|
371
|
+
|> matchesOneKeyword
|
|
372
|
+
[ "preload"
|
|
373
|
+
, "modulepreload"
|
|
374
|
+
, "preconnect"
|
|
375
|
+
, "dns-prefetch"
|
|
376
|
+
, "stylesheet"
|
|
377
|
+
]
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
_ ->
|
|
381
|
+
False
|
|
382
|
+
in
|
|
383
|
+
if
|
|
384
|
+
(nodeName |> matchesKeyword "script")
|
|
385
|
+
|| isPreloadDirective
|
|
386
|
+
then
|
|
387
|
+
Stripped
|
|
388
|
+
("<"
|
|
389
|
+
++ nodeName
|
|
390
|
+
++ " "
|
|
391
|
+
++ (attributes
|
|
392
|
+
|> List.map
|
|
393
|
+
(\( name, value ) ->
|
|
394
|
+
name
|
|
395
|
+
++ "=\""
|
|
396
|
+
++ ((case value of
|
|
397
|
+
Raw rawValue ->
|
|
398
|
+
rawValue
|
|
399
|
+
|
|
400
|
+
_ ->
|
|
401
|
+
"<internals>"
|
|
402
|
+
)
|
|
403
|
+
++ "\""
|
|
404
|
+
)
|
|
405
|
+
)
|
|
406
|
+
|> String.join " "
|
|
407
|
+
)
|
|
408
|
+
++ " />"
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
else
|
|
412
|
+
node nodeName attributes
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
matchesOneKeyword : List String -> String -> Bool
|
|
416
|
+
matchesOneKeyword keywords string =
|
|
417
|
+
List.any
|
|
418
|
+
(\keyword -> string |> matchesKeyword keyword)
|
|
419
|
+
keywords
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
matchesKeyword : String -> String -> Bool
|
|
423
|
+
matchesKeyword regex string =
|
|
424
|
+
string |> matchesRegex ("^\\s*" ++ regex ++ "\\s*$")
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
matchesRegex : String -> String -> Bool
|
|
428
|
+
matchesRegex regex string =
|
|
429
|
+
string
|
|
430
|
+
|> Regex.contains
|
|
431
|
+
(Regex.fromStringWith
|
|
432
|
+
{ caseInsensitive = True, multiline = True }
|
|
433
|
+
regex
|
|
434
|
+
|> Maybe.withDefault Regex.never
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
|
|
214
438
|
{-| Let's you link to your manifest.json file, see <https://developer.mozilla.org/en-US/docs/Web/Manifest#deploying_a_manifest>.
|
|
215
439
|
-}
|
|
216
440
|
manifestLink : String -> Tag
|
|
@@ -443,6 +667,12 @@ toJson canonicalSiteUrl currentPagePath tag =
|
|
|
443
667
|
, ( "keyValuePair", Json.Encode.list Json.Encode.string [ key, value ] )
|
|
444
668
|
]
|
|
445
669
|
|
|
670
|
+
Stripped message ->
|
|
671
|
+
Json.Encode.object
|
|
672
|
+
[ ( "type", Json.Encode.string "stripped" )
|
|
673
|
+
, ( "message", Json.Encode.string message )
|
|
674
|
+
]
|
|
675
|
+
|
|
446
676
|
|
|
447
677
|
encodeProperty : String -> String -> ( String, AttributeValue ) -> Json.Encode.Value
|
|
448
678
|
encodeProperty canonicalSiteUrl currentPagePath ( name, value ) =
|
package/src/HtmlPrinter.elm
CHANGED
|
@@ -8,15 +8,19 @@ import Test.Html.Internal.ElmHtml.ToString exposing (defaultFormatOptions, nodeT
|
|
|
8
8
|
import VirtualDom
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
htmlToString : Html msg -> String
|
|
12
|
-
htmlToString viewHtml =
|
|
11
|
+
htmlToString : Maybe { indent : Int, newLines : Bool } -> Html msg -> String
|
|
12
|
+
htmlToString formatOptions viewHtml =
|
|
13
13
|
case
|
|
14
14
|
Decode.decodeValue
|
|
15
15
|
(decodeElmHtml (\_ _ -> VirtualDom.Normal (Decode.succeed ())))
|
|
16
16
|
(asJsonView viewHtml)
|
|
17
17
|
of
|
|
18
18
|
Ok str ->
|
|
19
|
-
nodeToStringWithOptions
|
|
19
|
+
nodeToStringWithOptions
|
|
20
|
+
(formatOptions
|
|
21
|
+
|> Maybe.withDefault defaultFormatOptions
|
|
22
|
+
)
|
|
23
|
+
str
|
|
20
24
|
|
|
21
25
|
Err err ->
|
|
22
26
|
"Error pre-rendering HTML in HtmlPrinter.elm: " ++ Decode.errorToString err
|
|
@@ -8,8 +8,10 @@ module Internal.ApiRoute exposing
|
|
|
8
8
|
, withRoutes
|
|
9
9
|
)
|
|
10
10
|
|
|
11
|
-
import
|
|
11
|
+
import BackendTask exposing (BackendTask)
|
|
12
|
+
import FatalError exposing (FatalError)
|
|
12
13
|
import Head
|
|
14
|
+
import Json.Decode
|
|
13
15
|
import Pattern exposing (Pattern)
|
|
14
16
|
import Regex exposing (Regex)
|
|
15
17
|
|
|
@@ -44,12 +46,12 @@ tryMatchDone path (ApiRoute handler) =
|
|
|
44
46
|
type ApiRoute response
|
|
45
47
|
= ApiRoute
|
|
46
48
|
{ regex : Regex
|
|
47
|
-
, matchesToResponse : String ->
|
|
48
|
-
, buildTimeRoutes :
|
|
49
|
-
, handleRoute : String ->
|
|
49
|
+
, matchesToResponse : Json.Decode.Value -> String -> BackendTask FatalError (Maybe response)
|
|
50
|
+
, buildTimeRoutes : BackendTask FatalError (List String)
|
|
51
|
+
, handleRoute : String -> BackendTask FatalError Bool
|
|
50
52
|
, pattern : Pattern
|
|
51
53
|
, kind : String
|
|
52
|
-
, globalHeadTags : Maybe (
|
|
54
|
+
, globalHeadTags : Maybe (BackendTask FatalError (List Head.Tag))
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
|
|
@@ -15,7 +15,12 @@ type PageServerResponse data error
|
|
|
15
15
|
| ErrorPage error { headers : List ( String, String ) }
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
toRedirect :
|
|
18
|
+
toRedirect :
|
|
19
|
+
{ response
|
|
20
|
+
| statusCode : Int
|
|
21
|
+
, headers : List ( String, String )
|
|
22
|
+
}
|
|
23
|
+
-> Maybe { statusCode : Int, location : String }
|
|
19
24
|
toRedirect response =
|
|
20
25
|
response.headers
|
|
21
26
|
|> Dict.fromList
|
package/src/Pages/FormState.elm
CHANGED
|
@@ -12,15 +12,16 @@ import Html exposing (Attribute)
|
|
|
12
12
|
import Html.Attributes as Attr
|
|
13
13
|
import Html.Events
|
|
14
14
|
import Json.Decode as Decode exposing (Decoder)
|
|
15
|
-
import Pages.Msg
|
|
15
|
+
import Pages.Internal.Msg
|
|
16
|
+
import PagesMsg exposing (PagesMsg)
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
{-| -}
|
|
19
|
-
listeners : String -> List (Attribute (
|
|
20
|
+
listeners : String -> List (Attribute (PagesMsg userMsg))
|
|
20
21
|
listeners formId =
|
|
21
|
-
[ Html.Events.on "focusin" (Decode.value |> Decode.map Pages.Msg.FormFieldEvent)
|
|
22
|
-
, Html.Events.on "focusout" (Decode.value |> Decode.map Pages.Msg.FormFieldEvent)
|
|
23
|
-
, Html.Events.on "input" (Decode.value |> Decode.map Pages.Msg.FormFieldEvent)
|
|
22
|
+
[ Html.Events.on "focusin" (Decode.value |> Decode.map Pages.Internal.Msg.FormFieldEvent)
|
|
23
|
+
, Html.Events.on "focusout" (Decode.value |> Decode.map Pages.Internal.Msg.FormFieldEvent)
|
|
24
|
+
, Html.Events.on "input" (Decode.value |> Decode.map Pages.Internal.Msg.FormFieldEvent)
|
|
24
25
|
, Attr.id formId
|
|
25
26
|
]
|
|
26
27
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Pages.GeneratorProgramConfig exposing (GeneratorProgramConfig)
|
|
2
|
+
|
|
3
|
+
import Json.Decode as Decode
|
|
4
|
+
import Json.Encode
|
|
5
|
+
import Pages.Internal.Platform.ToJsPayload
|
|
6
|
+
import Pages.Script exposing (Script)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
type alias GeneratorProgramConfig =
|
|
10
|
+
{ data : Script
|
|
11
|
+
, toJsPort : Json.Encode.Value -> Cmd Never
|
|
12
|
+
, fromJsPort : Sub Decode.Value
|
|
13
|
+
, gotBatchSub : Sub Decode.Value
|
|
14
|
+
, sendPageData : Pages.Internal.Platform.ToJsPayload.NewThingForPort -> Cmd Never
|
|
15
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
module Pages.Internal.Form exposing (Validation(..), ViewField)
|
|
1
|
+
module Pages.Internal.Form exposing (Response(..), Validation(..), ViewField, unwrapResponse)
|
|
2
2
|
|
|
3
3
|
import Dict exposing (Dict)
|
|
4
4
|
import Form.FieldStatus exposing (FieldStatus)
|
|
@@ -15,3 +15,23 @@ type alias ViewField kind =
|
|
|
15
15
|
, status : FieldStatus
|
|
16
16
|
, kind : ( kind, List ( String, Encode.Value ) )
|
|
17
17
|
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
{-| -}
|
|
21
|
+
type Response error
|
|
22
|
+
= Response
|
|
23
|
+
{ fields : List ( String, String )
|
|
24
|
+
, errors : Dict String (List error)
|
|
25
|
+
, clientErrors : Dict String (List error)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
unwrapResponse :
|
|
30
|
+
Response error
|
|
31
|
+
->
|
|
32
|
+
{ fields : List ( String, String )
|
|
33
|
+
, errors : Dict String (List error)
|
|
34
|
+
, clientErrors : Dict String (List error)
|
|
35
|
+
}
|
|
36
|
+
unwrapResponse (Response response) =
|
|
37
|
+
response
|
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
module Pages.Msg exposing
|
|
1
|
+
module Pages.Internal.Msg exposing
|
|
2
2
|
( Msg(..)
|
|
3
|
-
,
|
|
3
|
+
, fetcherOnSubmit
|
|
4
|
+
, map
|
|
5
|
+
, onSubmit
|
|
6
|
+
, submitIfValid
|
|
4
7
|
)
|
|
5
8
|
|
|
6
|
-
{-|
|
|
7
|
-
|
|
8
|
-
@docs Msg
|
|
9
|
-
|
|
10
|
-
@docs map, onSubmit, fetcherOnSubmit, submitIfValid
|
|
11
|
-
|
|
12
|
-
-}
|
|
13
|
-
|
|
14
9
|
import Form.FormData exposing (FormData)
|
|
15
10
|
import FormDecoder
|
|
16
11
|
import Html exposing (Attribute)
|
|
@@ -22,9 +17,10 @@ import Json.Decode
|
|
|
22
17
|
type Msg userMsg
|
|
23
18
|
= UserMsg userMsg
|
|
24
19
|
| Submit FormData
|
|
25
|
-
| SubmitIfValid String FormData Bool
|
|
20
|
+
| SubmitIfValid String FormData Bool (Maybe userMsg)
|
|
26
21
|
| SubmitFetcher String FormData Bool (Maybe userMsg)
|
|
27
22
|
| FormFieldEvent Json.Decode.Value
|
|
23
|
+
| NoOp
|
|
28
24
|
|
|
29
25
|
|
|
30
26
|
{-| -}
|
|
@@ -35,10 +31,21 @@ onSubmit =
|
|
|
35
31
|
|
|
36
32
|
|
|
37
33
|
{-| -}
|
|
38
|
-
submitIfValid : String -> (List ( String, String ) -> Bool) -> Attribute (Msg userMsg)
|
|
39
|
-
submitIfValid formId isValid =
|
|
34
|
+
submitIfValid : Maybe ({ fields : List ( String, String ) } -> userMsg) -> String -> (List ( String, String ) -> Bool) -> Attribute (Msg userMsg)
|
|
35
|
+
submitIfValid userMsg formId isValid =
|
|
40
36
|
FormDecoder.formDataOnSubmit
|
|
41
|
-
|> Attr.map
|
|
37
|
+
|> Attr.map
|
|
38
|
+
(\formData ->
|
|
39
|
+
SubmitIfValid formId
|
|
40
|
+
formData
|
|
41
|
+
(isValid formData.fields)
|
|
42
|
+
(userMsg
|
|
43
|
+
|> Maybe.map
|
|
44
|
+
(\toUserMsg ->
|
|
45
|
+
toUserMsg { fields = formData.fields }
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
)
|
|
42
49
|
|
|
43
50
|
|
|
44
51
|
{-| -}
|
|
@@ -69,11 +76,14 @@ map mapFn msg =
|
|
|
69
76
|
Submit info ->
|
|
70
77
|
Submit info
|
|
71
78
|
|
|
72
|
-
SubmitIfValid formId info isValid ->
|
|
73
|
-
SubmitIfValid formId info isValid
|
|
79
|
+
SubmitIfValid formId info isValid toUserMsg ->
|
|
80
|
+
SubmitIfValid formId info isValid (Maybe.map mapFn toUserMsg)
|
|
74
81
|
|
|
75
82
|
SubmitFetcher formId info isValid toUserMsg ->
|
|
76
83
|
SubmitFetcher formId info isValid (Maybe.map mapFn toUserMsg)
|
|
77
84
|
|
|
78
85
|
FormFieldEvent value ->
|
|
79
86
|
FormFieldEvent value
|
|
87
|
+
|
|
88
|
+
NoOp ->
|
|
89
|
+
NoOp
|