elm-pages 2.1.6 → 2.1.10
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/generator/review/elm.json +34 -0
- package/generator/review/src/ReviewConfig.elm +10 -0
- package/generator/src/basepath-middleware.js +15 -9
- package/generator/src/build.js +100 -6
- package/generator/src/cli.js +13 -9
- package/generator/src/compile-elm.js +43 -0
- package/generator/src/dev-server.js +63 -11
- package/generator/src/error-formatter.js +62 -9
- package/generator/src/generate-template-module-connector.js +17 -4
- package/generator/src/init.js +4 -0
- package/generator/src/pre-render-html.js +19 -12
- package/generator/src/render-worker.js +0 -1
- package/generator/src/render.js +1 -2
- package/generator/src/seo-renderer.js +21 -2
- package/generator/static-code/hmr.js +43 -6
- package/generator/template/elm-tooling.json +9 -0
- package/generator/template/package.json +5 -1
- package/package.json +16 -9
- package/src/ApiRoute.elm +178 -0
- package/src/AriaLiveAnnouncer.elm +36 -0
- package/src/BuildError.elm +60 -0
- package/src/DataSource/File.elm +288 -0
- package/src/DataSource/Glob.elm +1050 -0
- package/src/DataSource/Http.elm +467 -0
- package/src/DataSource/Internal/Glob.elm +74 -0
- package/src/DataSource/Port.elm +87 -0
- package/src/DataSource/ServerRequest.elm +60 -0
- package/src/DataSource.elm +801 -0
- package/src/Head/Seo.elm +516 -0
- package/src/Head/Twitter.elm +109 -0
- package/src/Head.elm +452 -0
- package/src/HtmlPrinter.elm +27 -0
- package/src/Internal/ApiRoute.elm +89 -0
- package/src/Internal/OptimizedDecoder.elm +18 -0
- package/src/KeepOrDiscard.elm +6 -0
- package/src/OptimizedDecoder/Pipeline.elm +335 -0
- package/src/OptimizedDecoder.elm +818 -0
- package/src/Pages/ContentCache.elm +248 -0
- package/src/Pages/Flags.elm +26 -0
- package/src/Pages/Http.elm +10 -0
- package/src/Pages/Internal/ApplicationType.elm +6 -0
- package/src/Pages/Internal/NotFoundReason.elm +256 -0
- package/src/Pages/Internal/Platform/Cli.elm +1015 -0
- package/src/Pages/Internal/Platform/Effect.elm +14 -0
- package/src/Pages/Internal/Platform/StaticResponses.elm +540 -0
- package/src/Pages/Internal/Platform/ToJsPayload.elm +138 -0
- package/src/Pages/Internal/Platform.elm +745 -0
- package/src/Pages/Internal/RoutePattern.elm +122 -0
- package/src/Pages/Internal/Router.elm +116 -0
- package/src/Pages/Internal/StaticHttpBody.elm +54 -0
- package/src/Pages/Internal/String.elm +39 -0
- package/src/Pages/Manifest/Category.elm +240 -0
- package/src/Pages/Manifest.elm +412 -0
- package/src/Pages/PageUrl.elm +38 -0
- package/src/Pages/ProgramConfig.elm +73 -0
- package/src/Pages/Review/NoContractViolations.elm +397 -0
- package/src/Pages/Secrets.elm +83 -0
- package/src/Pages/SiteConfig.elm +13 -0
- package/src/Pages/StaticHttp/Request.elm +42 -0
- package/src/Pages/StaticHttpRequest.elm +320 -0
- package/src/Pages/Url.elm +60 -0
- package/src/Path.elm +96 -0
- package/src/QueryParams.elm +216 -0
- package/src/RenderRequest.elm +163 -0
- package/src/RequestsAndPending.elm +20 -0
- package/src/Secrets.elm +111 -0
- package/src/SecretsDict.elm +45 -0
- package/src/StructuredData.elm +236 -0
- package/src/TerminalText.elm +242 -0
- package/src/Test/Html/Internal/ElmHtml/Constants.elm +53 -0
- package/src/Test/Html/Internal/ElmHtml/Helpers.elm +17 -0
- package/src/Test/Html/Internal/ElmHtml/InternalTypes.elm +529 -0
- package/src/Test/Html/Internal/ElmHtml/Markdown.elm +56 -0
- package/src/Test/Html/Internal/ElmHtml/ToString.elm +197 -0
- package/src/Test/Internal/KernelConstants.elm +34 -0
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
module Test.Html.Internal.ElmHtml.InternalTypes exposing
|
|
2
|
+
( ElmHtml(..), TextTagRecord, NodeRecord, CustomNodeRecord, MarkdownNodeRecord
|
|
3
|
+
, Facts, Tagger, EventHandler, ElementKind(..)
|
|
4
|
+
, Attribute(..), AttributeRecord, NamespacedAttributeRecord, PropertyRecord, EventRecord
|
|
5
|
+
, decodeElmHtml, emptyFacts, toElementKind, decodeAttribute
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
{-| Internal types used to represent Elm Html in pure Elm
|
|
9
|
+
|
|
10
|
+
@docs ElmHtml, TextTagRecord, NodeRecord, CustomNodeRecord, MarkdownNodeRecord
|
|
11
|
+
|
|
12
|
+
@docs Facts, Tagger, EventHandler, ElementKind
|
|
13
|
+
|
|
14
|
+
@docs Attribute, AttributeRecord, NamespacedAttributeRecord, PropertyRecord, EventRecord
|
|
15
|
+
|
|
16
|
+
@docs decodeElmHtml, emptyFacts, toElementKind, decodeAttribute
|
|
17
|
+
|
|
18
|
+
-}
|
|
19
|
+
|
|
20
|
+
import Dict exposing (Dict)
|
|
21
|
+
import Html.Events
|
|
22
|
+
import Json.Decode exposing (field)
|
|
23
|
+
import Json.Encode
|
|
24
|
+
import Test.Html.Internal.ElmHtml.Constants as Constants exposing (..)
|
|
25
|
+
import Test.Html.Internal.ElmHtml.Helpers exposing (..)
|
|
26
|
+
import Test.Html.Internal.ElmHtml.Markdown exposing (..)
|
|
27
|
+
import Test.Internal.KernelConstants exposing (kernelConstants)
|
|
28
|
+
import VirtualDom
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
{-| Type tree for representing Elm's Html
|
|
32
|
+
|
|
33
|
+
- TextTag is just a plain old bit of text.
|
|
34
|
+
- NodeEntry is an actual HTML node, e.g a div
|
|
35
|
+
- CustomNode are nodes defined to work with the renderer in some way, e.g webgl/markdown
|
|
36
|
+
- MarkdownNode is just a wrapper for CustomNode designed just for markdown
|
|
37
|
+
|
|
38
|
+
-}
|
|
39
|
+
type ElmHtml msg
|
|
40
|
+
= TextTag TextTagRecord
|
|
41
|
+
| NodeEntry (NodeRecord msg)
|
|
42
|
+
| CustomNode (CustomNodeRecord msg)
|
|
43
|
+
| MarkdownNode (MarkdownNodeRecord msg)
|
|
44
|
+
| NoOp
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
{-| Text tags just contain text
|
|
48
|
+
-}
|
|
49
|
+
type alias TextTagRecord =
|
|
50
|
+
{ text : String }
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
{-| A node contains the `tag` as a string, the children, the facts (e.g attributes) and descendantsCount
|
|
54
|
+
-}
|
|
55
|
+
type alias NodeRecord msg =
|
|
56
|
+
{ tag : String
|
|
57
|
+
, children : List (ElmHtml msg)
|
|
58
|
+
, facts :
|
|
59
|
+
Facts msg
|
|
60
|
+
|
|
61
|
+
--, namespace : String
|
|
62
|
+
, descendantsCount : Int
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
{-| A markdown node contains facts (e.g attributes) and the model used by markdown
|
|
67
|
+
-}
|
|
68
|
+
type alias MarkdownNodeRecord msg =
|
|
69
|
+
{ facts : Facts msg
|
|
70
|
+
, model : MarkdownModel
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
{-| Custom nodes contain facts (e.g attributes) and a json value for the model
|
|
75
|
+
-}
|
|
76
|
+
type alias CustomNodeRecord msg =
|
|
77
|
+
{ facts : Facts msg
|
|
78
|
+
, model : Json.Decode.Value
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
{-| Tagger holds the map function when Html.Map is used, the tagger
|
|
83
|
+
should then be applied to events comming from descendant nodes, it
|
|
84
|
+
is basically a javascript function.
|
|
85
|
+
-}
|
|
86
|
+
type alias Tagger =
|
|
87
|
+
Json.Decode.Value
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
{-| EventHandler holds the function that is called when an event is
|
|
91
|
+
triggered, it is basically a javascript object like this:
|
|
92
|
+
|
|
93
|
+
{ decoder: [Function] }
|
|
94
|
+
|
|
95
|
+
-}
|
|
96
|
+
type alias EventHandler =
|
|
97
|
+
Json.Decode.Value
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
{-| Facts contain various dictionaries and values for a node
|
|
101
|
+
|
|
102
|
+
- styles are a mapping of rules
|
|
103
|
+
- events may be a json object containing event handlers
|
|
104
|
+
- attributes are pulled out into stringAttributes and boolAttributes - things with string values go into
|
|
105
|
+
stringAttributes, things with bool values go into boolAttributes
|
|
106
|
+
|
|
107
|
+
-}
|
|
108
|
+
type alias Facts msg =
|
|
109
|
+
{ styles : Dict String String
|
|
110
|
+
, events : Dict String (VirtualDom.Handler msg)
|
|
111
|
+
, attributeNamespace : Maybe Json.Decode.Value
|
|
112
|
+
, stringAttributes : Dict String String
|
|
113
|
+
, boolAttributes : Dict String Bool
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
{-| Type for representing the five kinds of elements according to HTML 5
|
|
118
|
+
[spec](https://html.spec.whatwg.org/multipage/syntax.html#elements-2).
|
|
119
|
+
Used to handle different rendering behavior depending on the type of element.
|
|
120
|
+
-}
|
|
121
|
+
type ElementKind
|
|
122
|
+
= VoidElements
|
|
123
|
+
| RawTextElements
|
|
124
|
+
| EscapableRawTextElements
|
|
125
|
+
| ForeignElements
|
|
126
|
+
| NormalElements
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
type HtmlContext msg
|
|
130
|
+
= HtmlContext (List Tagger) (List Tagger -> EventHandler -> VirtualDom.Handler msg)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
{-| Type for representing Elm's Attributes
|
|
134
|
+
|
|
135
|
+
- Attribute is an HTML attribute, like `Html.Attributes.colspan`. These values
|
|
136
|
+
are applied using `element.setAttribute(key, value)` during a patch.
|
|
137
|
+
- NamespacedAttribute has an namespace, like `Svg.Attributes.xlinkHref`
|
|
138
|
+
- Property assigns a value to a node like `Html.Attributes.class`, and can
|
|
139
|
+
hold any encoded value. Unlike attributes, where `element.setAttribute()` is
|
|
140
|
+
used during the patch, properties are applied directly as
|
|
141
|
+
`element[key] = value`.
|
|
142
|
+
- Styles hold a list of key value pairs to be applied to the node's style set
|
|
143
|
+
- Event contains a decoder for a msg and the `Html.Event.Options` for the event
|
|
144
|
+
|
|
145
|
+
-}
|
|
146
|
+
type Attribute
|
|
147
|
+
= Attribute AttributeRecord
|
|
148
|
+
| NamespacedAttribute NamespacedAttributeRecord
|
|
149
|
+
| Property PropertyRecord
|
|
150
|
+
| Style { key : String, value : String }
|
|
151
|
+
| Event EventRecord
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
{-| Attribute contains a string key and a string value
|
|
155
|
+
-}
|
|
156
|
+
type alias AttributeRecord =
|
|
157
|
+
{ key : String
|
|
158
|
+
, value : String
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
{-| NamespacedAttribute contains a string key, string namespace and string value
|
|
163
|
+
-}
|
|
164
|
+
type alias NamespacedAttributeRecord =
|
|
165
|
+
{ key : String
|
|
166
|
+
, value : String
|
|
167
|
+
, namespace : String
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
{-| Property contains a string key and a value with an arbitrary type
|
|
172
|
+
-}
|
|
173
|
+
type alias PropertyRecord =
|
|
174
|
+
{ key : String
|
|
175
|
+
, value : Json.Decode.Value
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
{-| Event contains a string key, a decoder for a msg and event options
|
|
180
|
+
-}
|
|
181
|
+
type alias EventRecord =
|
|
182
|
+
{ key : String
|
|
183
|
+
, decoder : Json.Decode.Value
|
|
184
|
+
, options : EventOptions
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
type alias EventOptions =
|
|
189
|
+
{ stopPropagation : Bool
|
|
190
|
+
, preventDefault : Bool
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
{-| decode a json object into ElmHtml, you have to pass a function that decodes
|
|
195
|
+
events from Html Nodes. If you don't want to decode event msgs, you can ignore it:
|
|
196
|
+
|
|
197
|
+
decodeElmHtml (\_ _ -> VirtualDom.Normal (Json.Decode.succeed ())) jsonHtml
|
|
198
|
+
|
|
199
|
+
if you do want to decode them, you will probably need to write some native code
|
|
200
|
+
like elm-html-test does to extract the function inside those.
|
|
201
|
+
|
|
202
|
+
-}
|
|
203
|
+
decodeElmHtml : (List Tagger -> EventHandler -> VirtualDom.Handler msg) -> Json.Decode.Decoder (ElmHtml msg)
|
|
204
|
+
decodeElmHtml eventDecoder =
|
|
205
|
+
contextDecodeElmHtml (HtmlContext [] eventDecoder)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
contextDecodeElmHtml : HtmlContext msg -> Json.Decode.Decoder (ElmHtml msg)
|
|
209
|
+
contextDecodeElmHtml context =
|
|
210
|
+
field kernelConstants.virtualDom.nodeType Json.Decode.int
|
|
211
|
+
|> Json.Decode.andThen
|
|
212
|
+
(\nodeType ->
|
|
213
|
+
if nodeType == kernelConstants.virtualDom.nodeTypeText then
|
|
214
|
+
Json.Decode.map TextTag decodeTextTag
|
|
215
|
+
|
|
216
|
+
else if nodeType == kernelConstants.virtualDom.nodeTypeKeyedNode then
|
|
217
|
+
Json.Decode.map NodeEntry (decodeKeyedNode context)
|
|
218
|
+
|
|
219
|
+
else if nodeType == kernelConstants.virtualDom.nodeTypeNode then
|
|
220
|
+
Json.Decode.map NodeEntry (decodeNode context)
|
|
221
|
+
|
|
222
|
+
else if nodeType == kernelConstants.virtualDom.nodeTypeCustom then
|
|
223
|
+
decodeCustomNode context
|
|
224
|
+
|
|
225
|
+
else if nodeType == kernelConstants.virtualDom.nodeTypeTagger then
|
|
226
|
+
decodeTagger context
|
|
227
|
+
|
|
228
|
+
else if nodeType == kernelConstants.virtualDom.nodeTypeThunk then
|
|
229
|
+
field kernelConstants.virtualDom.node (contextDecodeElmHtml context)
|
|
230
|
+
|
|
231
|
+
else
|
|
232
|
+
Json.Decode.fail ("No such type as " ++ String.fromInt nodeType)
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
{-| decode text tag
|
|
237
|
+
-}
|
|
238
|
+
decodeTextTag : Json.Decode.Decoder TextTagRecord
|
|
239
|
+
decodeTextTag =
|
|
240
|
+
field kernelConstants.virtualDom.text (Json.Decode.andThen (\text -> Json.Decode.succeed { text = text }) Json.Decode.string)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
{-| decode a tagger
|
|
244
|
+
-}
|
|
245
|
+
decodeTagger : HtmlContext msg -> Json.Decode.Decoder (ElmHtml msg)
|
|
246
|
+
decodeTagger (HtmlContext taggers eventDecoder) =
|
|
247
|
+
Json.Decode.field kernelConstants.virtualDom.tagger Json.Decode.value
|
|
248
|
+
|> Json.Decode.andThen
|
|
249
|
+
(\tagger ->
|
|
250
|
+
let
|
|
251
|
+
nodeDecoder =
|
|
252
|
+
contextDecodeElmHtml (HtmlContext (taggers ++ [ tagger ]) eventDecoder)
|
|
253
|
+
in
|
|
254
|
+
Json.Decode.at [ kernelConstants.virtualDom.node ] nodeDecoder
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
decodeKeyedNode : HtmlContext msg -> Json.Decode.Decoder (NodeRecord msg)
|
|
259
|
+
decodeKeyedNode context =
|
|
260
|
+
let
|
|
261
|
+
-- elm stores keyed nodes as tuples
|
|
262
|
+
-- we only want to decode the html, in the second property
|
|
263
|
+
decodeSecondNode =
|
|
264
|
+
Json.Decode.field "b" (contextDecodeElmHtml context)
|
|
265
|
+
in
|
|
266
|
+
Json.Decode.map4 NodeRecord
|
|
267
|
+
(Json.Decode.field kernelConstants.virtualDom.tag Json.Decode.string)
|
|
268
|
+
(Json.Decode.field kernelConstants.virtualDom.kids (Json.Decode.list decodeSecondNode))
|
|
269
|
+
(Json.Decode.field kernelConstants.virtualDom.facts (decodeFacts context))
|
|
270
|
+
(Json.Decode.field kernelConstants.virtualDom.descendantsCount Json.Decode.int)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
{-| decode a node record
|
|
274
|
+
-}
|
|
275
|
+
decodeNode : HtmlContext msg -> Json.Decode.Decoder (NodeRecord msg)
|
|
276
|
+
decodeNode context =
|
|
277
|
+
Json.Decode.map4 NodeRecord
|
|
278
|
+
(field kernelConstants.virtualDom.tag Json.Decode.string)
|
|
279
|
+
(field kernelConstants.virtualDom.kids (Json.Decode.list (contextDecodeElmHtml context)))
|
|
280
|
+
(field kernelConstants.virtualDom.facts (decodeFacts context))
|
|
281
|
+
(field kernelConstants.virtualDom.descendantsCount Json.Decode.int)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
{-| decode custom node into either markdown or custom
|
|
285
|
+
-}
|
|
286
|
+
decodeCustomNode : HtmlContext msg -> Json.Decode.Decoder (ElmHtml msg)
|
|
287
|
+
decodeCustomNode context =
|
|
288
|
+
Json.Decode.oneOf
|
|
289
|
+
[ Json.Decode.map MarkdownNode (decodeMarkdownNodeRecord context)
|
|
290
|
+
, Json.Decode.map CustomNode (decodeCustomNodeRecord context)
|
|
291
|
+
]
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
{-| decode custom node record
|
|
295
|
+
-}
|
|
296
|
+
decodeCustomNodeRecord : HtmlContext msg -> Json.Decode.Decoder (CustomNodeRecord msg)
|
|
297
|
+
decodeCustomNodeRecord context =
|
|
298
|
+
Json.Decode.map2 CustomNodeRecord
|
|
299
|
+
(field kernelConstants.virtualDom.facts (decodeFacts context))
|
|
300
|
+
(field kernelConstants.virtualDom.model Json.Decode.value)
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
{-| decode markdown node record
|
|
304
|
+
-}
|
|
305
|
+
decodeMarkdownNodeRecord : HtmlContext msg -> Json.Decode.Decoder (MarkdownNodeRecord msg)
|
|
306
|
+
decodeMarkdownNodeRecord context =
|
|
307
|
+
Json.Decode.map2 MarkdownNodeRecord
|
|
308
|
+
(field kernelConstants.virtualDom.facts (decodeFacts context))
|
|
309
|
+
(field kernelConstants.virtualDom.model decodeMarkdownModel)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
{-| decode the styles
|
|
313
|
+
-}
|
|
314
|
+
decodeStyles : Json.Decode.Decoder (Dict String String)
|
|
315
|
+
decodeStyles =
|
|
316
|
+
Json.Decode.oneOf
|
|
317
|
+
[ field styleKey (Json.Decode.dict Json.Decode.string)
|
|
318
|
+
, Json.Decode.succeed Dict.empty
|
|
319
|
+
]
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
{-| grab things from attributes via a decoder, then anything that isn't filtered on
|
|
323
|
+
the object
|
|
324
|
+
-}
|
|
325
|
+
decodeOthers : Json.Decode.Decoder a -> Json.Decode.Decoder (Dict String a)
|
|
326
|
+
decodeOthers otherDecoder =
|
|
327
|
+
decodeAttributes otherDecoder
|
|
328
|
+
|> Json.Decode.andThen
|
|
329
|
+
(\attributes ->
|
|
330
|
+
decodeDictFilterMap otherDecoder
|
|
331
|
+
|> Json.Decode.map (filterKnownKeys >> Dict.union attributes)
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
{-| For a given decoder, keep the values from a dict that pass the decoder
|
|
336
|
+
-}
|
|
337
|
+
decodeDictFilterMap : Json.Decode.Decoder a -> Json.Decode.Decoder (Dict String a)
|
|
338
|
+
decodeDictFilterMap decoder =
|
|
339
|
+
Json.Decode.dict Json.Decode.value
|
|
340
|
+
|> Json.Decode.map
|
|
341
|
+
(Dict.toList
|
|
342
|
+
>> List.filterMap
|
|
343
|
+
(\( key, value ) ->
|
|
344
|
+
case Json.Decode.decodeValue decoder value of
|
|
345
|
+
Err _ ->
|
|
346
|
+
Nothing
|
|
347
|
+
|
|
348
|
+
Ok v ->
|
|
349
|
+
Just ( key, v )
|
|
350
|
+
)
|
|
351
|
+
>> Dict.fromList
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
decodeAttributes : Json.Decode.Decoder a -> Json.Decode.Decoder (Dict String a)
|
|
356
|
+
decodeAttributes decoder =
|
|
357
|
+
Json.Decode.oneOf
|
|
358
|
+
[ Json.Decode.field attributeKey (decodeDictFilterMap decoder)
|
|
359
|
+
, Json.Decode.succeed Dict.empty
|
|
360
|
+
]
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
decodeEvents : (EventHandler -> VirtualDom.Handler msg) -> Json.Decode.Decoder (Dict String (VirtualDom.Handler msg))
|
|
364
|
+
decodeEvents taggedEventDecoder =
|
|
365
|
+
Json.Decode.oneOf
|
|
366
|
+
[ Json.Decode.field eventKey (Json.Decode.dict (Json.Decode.map taggedEventDecoder Json.Decode.value))
|
|
367
|
+
, Json.Decode.succeed Dict.empty
|
|
368
|
+
]
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
{-| decode fact
|
|
372
|
+
-}
|
|
373
|
+
decodeFacts : HtmlContext msg -> Json.Decode.Decoder (Facts msg)
|
|
374
|
+
decodeFacts (HtmlContext taggers eventDecoder) =
|
|
375
|
+
Json.Decode.map5 Facts
|
|
376
|
+
decodeStyles
|
|
377
|
+
(decodeEvents (eventDecoder taggers))
|
|
378
|
+
(Json.Decode.maybe (Json.Decode.field attributeNamespaceKey Json.Decode.value))
|
|
379
|
+
(decodeOthers Json.Decode.string)
|
|
380
|
+
(decodeOthers Json.Decode.bool)
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
{-| Just empty facts
|
|
384
|
+
-}
|
|
385
|
+
emptyFacts : Facts msg
|
|
386
|
+
emptyFacts =
|
|
387
|
+
{ styles = Dict.empty
|
|
388
|
+
, events = Dict.empty
|
|
389
|
+
, attributeNamespace = Nothing
|
|
390
|
+
, stringAttributes = Dict.empty
|
|
391
|
+
, boolAttributes = Dict.empty
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
{-| Decode a JSON object into an Attribute. You have to pass a function that
|
|
396
|
+
decodes events from event attributes. If you don't want to decode event msgs,
|
|
397
|
+
you can ignore it:
|
|
398
|
+
|
|
399
|
+
decodeAttribute (\_ -> ()) jsonHtml
|
|
400
|
+
|
|
401
|
+
If you do want to decode them, you will probably need to write some native code
|
|
402
|
+
like elm-html-test does to extract the function inside those.
|
|
403
|
+
|
|
404
|
+
-}
|
|
405
|
+
decodeAttribute : Json.Decode.Decoder Attribute
|
|
406
|
+
decodeAttribute =
|
|
407
|
+
Json.Decode.field "$" Json.Decode.string
|
|
408
|
+
|> Json.Decode.andThen
|
|
409
|
+
(\tag ->
|
|
410
|
+
if tag == Constants.attributeKey then
|
|
411
|
+
Json.Decode.map2 (\key val -> Attribute (AttributeRecord key val))
|
|
412
|
+
(Json.Decode.field "n" Json.Decode.string)
|
|
413
|
+
(Json.Decode.field "o" Json.Decode.string)
|
|
414
|
+
|
|
415
|
+
else if tag == Constants.attributeNamespaceKey then
|
|
416
|
+
Json.Decode.map3 NamespacedAttributeRecord
|
|
417
|
+
(Json.Decode.field "n" Json.Decode.string)
|
|
418
|
+
(Json.Decode.at [ "o", "o" ] Json.Decode.string)
|
|
419
|
+
(Json.Decode.at [ "o", "f" ] Json.Decode.string)
|
|
420
|
+
|> Json.Decode.map NamespacedAttribute
|
|
421
|
+
|
|
422
|
+
else if tag == Constants.styleKey then
|
|
423
|
+
Json.Decode.map2 (\key val -> Style { key = key, value = val })
|
|
424
|
+
(Json.Decode.field "n" Json.Decode.string)
|
|
425
|
+
(Json.Decode.field "o" Json.Decode.string)
|
|
426
|
+
|
|
427
|
+
else if tag == Constants.propKey then
|
|
428
|
+
Json.Decode.map2 (\key val -> Property (PropertyRecord key val))
|
|
429
|
+
(Json.Decode.field "n" Json.Decode.string)
|
|
430
|
+
(Json.Decode.at [ "o", "a" ] Json.Decode.value)
|
|
431
|
+
|
|
432
|
+
else
|
|
433
|
+
Json.Decode.fail ("Unexpected Html.Attribute tag: " ++ tag)
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
elmListDecoder : Json.Decode.Decoder a -> Json.Decode.Decoder (List a)
|
|
438
|
+
elmListDecoder itemDecoder =
|
|
439
|
+
elmListDecoderHelp itemDecoder []
|
|
440
|
+
|> Json.Decode.map List.reverse
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
elmListDecoderHelp : Json.Decode.Decoder a -> List a -> Json.Decode.Decoder (List a)
|
|
444
|
+
elmListDecoderHelp itemDecoder items =
|
|
445
|
+
Json.Decode.field "ctor" Json.Decode.string
|
|
446
|
+
|> Json.Decode.andThen
|
|
447
|
+
(\ctor ->
|
|
448
|
+
case ctor of
|
|
449
|
+
"[]" ->
|
|
450
|
+
Json.Decode.succeed items
|
|
451
|
+
|
|
452
|
+
"::" ->
|
|
453
|
+
Json.Decode.field "_0" itemDecoder
|
|
454
|
+
|> Json.Decode.andThen
|
|
455
|
+
(\value ->
|
|
456
|
+
Json.Decode.field "_1" (elmListDecoderHelp itemDecoder (value :: items))
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
_ ->
|
|
460
|
+
Json.Decode.fail <| "Unrecognized constructor for an Elm List: " ++ ctor
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
{-| A list of Void elements as defined by the HTML5 specification. These
|
|
465
|
+
elements must not have closing tags and most not be written as self closing
|
|
466
|
+
either
|
|
467
|
+
-}
|
|
468
|
+
voidElements : List String
|
|
469
|
+
voidElements =
|
|
470
|
+
[ "area"
|
|
471
|
+
, "base"
|
|
472
|
+
, "br"
|
|
473
|
+
, "col"
|
|
474
|
+
, "embed"
|
|
475
|
+
, "hr"
|
|
476
|
+
, "img"
|
|
477
|
+
, "input"
|
|
478
|
+
, "link"
|
|
479
|
+
, "meta"
|
|
480
|
+
, "param"
|
|
481
|
+
, "source"
|
|
482
|
+
, "track"
|
|
483
|
+
, "wbr"
|
|
484
|
+
]
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
{-| A list of all Raw Text Elements as defined by the HTML5 specification. They
|
|
488
|
+
can contain only text and have restrictions on which characters can appear
|
|
489
|
+
within its innerHTML
|
|
490
|
+
-}
|
|
491
|
+
rawTextElements : List String
|
|
492
|
+
rawTextElements =
|
|
493
|
+
[ "script", "style" ]
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
{-| A list of all Escapable Raw Text Elements as defined by the HTML5
|
|
497
|
+
specification. They can have text and character references, but the text must
|
|
498
|
+
not contain an ambiguous ampersand along with addional restrictions:
|
|
499
|
+
<https://html.spec.whatwg.org/multipage/syntax.html#cdata-rcdata-restrictions>
|
|
500
|
+
-}
|
|
501
|
+
escapableRawTextElements : List String
|
|
502
|
+
escapableRawTextElements =
|
|
503
|
+
[ "textarea", "title" ]
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
{- Foreign elements are elements from the MathML namespace and the
|
|
508
|
+
SVG namespace. TODO: detect these nodes and handle them correctly. Right
|
|
509
|
+
now they will just be treated as Normal elements.
|
|
510
|
+
-}
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
{-| Identify the kind of element. Helper to convert an tag name into a type for
|
|
514
|
+
pattern matching.
|
|
515
|
+
-}
|
|
516
|
+
toElementKind : String -> ElementKind
|
|
517
|
+
toElementKind element =
|
|
518
|
+
if List.member element voidElements then
|
|
519
|
+
VoidElements
|
|
520
|
+
|
|
521
|
+
else if List.member element rawTextElements then
|
|
522
|
+
RawTextElements
|
|
523
|
+
|
|
524
|
+
else if List.member element escapableRawTextElements then
|
|
525
|
+
EscapableRawTextElements
|
|
526
|
+
|
|
527
|
+
else
|
|
528
|
+
-- All other allowed HTML elements are normal elements
|
|
529
|
+
NormalElements
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module Test.Html.Internal.ElmHtml.Markdown exposing
|
|
2
|
+
( MarkdownOptions, MarkdownModel, baseMarkdownModel
|
|
3
|
+
, decodeMarkdownModel
|
|
4
|
+
)
|
|
5
|
+
|
|
6
|
+
{-| Markdown helpers
|
|
7
|
+
|
|
8
|
+
@docs MarkdownOptions, MarkdownModel, baseMarkdownModel
|
|
9
|
+
|
|
10
|
+
@docs decodeMarkdownModel
|
|
11
|
+
|
|
12
|
+
-}
|
|
13
|
+
|
|
14
|
+
import Json.Decode exposing (field)
|
|
15
|
+
import Json.Encode
|
|
16
|
+
import Test.Internal.KernelConstants exposing (kernelConstants)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
{-| Just a default markdown model
|
|
20
|
+
-}
|
|
21
|
+
baseMarkdownModel : MarkdownModel
|
|
22
|
+
baseMarkdownModel =
|
|
23
|
+
{ options =
|
|
24
|
+
{ githubFlavored = Just { tables = False, breaks = False }
|
|
25
|
+
, defaultHighlighting = Nothing
|
|
26
|
+
, sanitize = False
|
|
27
|
+
, smartypants = False
|
|
28
|
+
}
|
|
29
|
+
, markdown = ""
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
{-| options markdown expects
|
|
34
|
+
-}
|
|
35
|
+
type alias MarkdownOptions =
|
|
36
|
+
{ githubFlavored : Maybe { tables : Bool, breaks : Bool }
|
|
37
|
+
, defaultHighlighting : Maybe String
|
|
38
|
+
, sanitize : Bool
|
|
39
|
+
, smartypants : Bool
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
{-| An internal markdown model. Options are the things you give markdown, markdown is the string
|
|
44
|
+
-}
|
|
45
|
+
type alias MarkdownModel =
|
|
46
|
+
{ options : MarkdownOptions
|
|
47
|
+
, markdown : String
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
{-| decode a markdown model
|
|
52
|
+
-}
|
|
53
|
+
decodeMarkdownModel : Json.Decode.Decoder MarkdownModel
|
|
54
|
+
decodeMarkdownModel =
|
|
55
|
+
field kernelConstants.markdown.markdown Json.Decode.string
|
|
56
|
+
|> Json.Decode.map (MarkdownModel baseMarkdownModel.options)
|