forked from evancz/elm-html
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHtml.elm
270 lines (208 loc) · 7.68 KB
/
Html.elm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
module Html where
{-| This module gives you *raw* bindings to HTML. There are no special tricks
here, just the bare essentials to use HTML.
Use `Html.Tags`, `Html.Attributes`, and `Html.Events` for helper functions like
`div` to make your code more type-safe and a bit nicer to read. If ever you need
to go outside those functions though, this core `Html` module has everything you
need.
In future releases, we plan to break out this module and the core diffing
algorithm so that anyone can build on top of it with a minimal set of
dependencies.
# Create
@docs text, node
# Embed
@docs toElement
# HTML Attributes
@docs attr, toggle
# CSS Properties
@docs style, prop
# Events
@docs on, getChecked, getValue, getValueAndSelection, Direction,
getMouseEvent, MouseEvent, getKeyboardEvent, KeyboardEvent,
getAnything, when, filterMap
-}
import Color
import Graphics.Input (Handle)
import Native.Html
import String (show, append)
data Html = Html
{-| Create a DOM node with a tag name, a list of HTML attributes that can
include styles and event listeners, a list of CSS properties like `color`, and
a list of child nodes.
node "div" [] [ text "Hello!" ]
node "div"
[ attr "id" "greeting" ]
[ text "Hello!" ]
-}
node : String -> [Attribute] -> [Html] -> Html
node = Native.Html.node
{-| Defines an embedded vectorial image.
svg "svg"
[ attr "height" "100"
, attr "width" "100"
]
[svg "circle"
[ attr "cx" "50"
, attr "cy" "50"
, attr "r" "25"] []]
-}
svg : String -> [Attribute] -> [Html] -> Html
svg = Native.Html.svg
{-| Just put plain text in the DOM. It will escape the string so that it appears
exactly as you specify.
text "Hello World!"
-}
text : String -> Html
text = Native.Html.text
{-| Embed an `Html` value in Elm's rendering system. Like any other `Element`,
this requires a known width and height, so it is not yet clear if this can be
made more convenient in the future.
-}
toElement : Int -> Int -> Html -> Element
toElement = Native.Html.toElement
-- ATTRIBUTES
data Attribute = Attribute
{-| Create a basic HTML attribute.
node "div"
[ attr "id" "greeting"
, attr "className" "message"
]
[ text "Hello!" ]
Check out `Html.Attributes` for helper functions like
`(id : String -> Attribute)` and `(class : String -> Attribute)` that make it
easier to specify attributes.
Notice that we use `className` to set the class of the div. All HTML attributes
and CSS properties must be set using the JavaScript version of their name, so
`class` becomes `className`, `float` becomes `cssFloat`, etc.
-}
attr : String -> String -> Attribute
attr = Native.Html.pair
{-| Some HTML attributes are not associated with a value, they are either there
or not. The `toggle` function lets create this kind of attribute.
node "input"
[ toggle "autofocus" True
, toggle "readonly" False
]
[]
See `Html.Attributes` for helper functions like
`(autofocus : Bool -> Attribute)` and `(readonly : Bool -> Attribute)`.
-}
toggle : String -> Bool -> Attribute
toggle = Native.Html.pair
-- STYLES
data CssProperty = CssProperty
{-| This function makes it easier to specify a set of styles.
node "div"
[ style
[ prop "backgroundColor" "red"
, prop "height" "90px"
, prop "width" "100%"
]
]
[ text "Hello!" ]
There is no `Html.Styles` module because best practices for working with HTML
suggest that this should primarily be specified in CSS files. So the general
recommendation is to use this function lightly.
-}
style : [CssProperty] -> Attribute
style = Native.Html.style
{-| Create a CSS property. -}
prop : String -> String -> CssProperty
prop = Native.Html.pair
-- EVENTS
data Get a = Get
{-| This is the most general way to handle events. Check out `Html.Events` for
a gentler introduction to event handlers.
The `on` function takes four arguments:
on "click" getMouseEvent actions.handle (\mc -> mc.button)
The first is an event name like "mousemove" or "click". These names match the
standard HTML names for events.
Second is a "getter". Getters are used to take a raw JavaScript event and safely
turn it into an Elm value. Accessing fields like `event.target.checked` can
fail, so getters let you ask for these fields without risk of runtime errors.
If the getter fails, the event is skipped.
Third is an input handle. Handles are defined in `Graphics.Input` and are a
general purpose way to route events to particular signals. So this argument
lets us declare who we are going to tell about a particular event.
Fourth we have a function to augment the event value with extra information.
Say you have forty check boxes reporting to the same signal. You need to add
an ID to these events so that you can distinguish between them.
Again, take a look at `Html.Events` for a much easier introduction to these
ideas.
-}
on : String -> Get value -> Handle a -> (value -> a) -> Attribute
on = Native.Html.on
{-| This lets us create custom getters that require that certain conditions
are met. For example, we can create an event that only triggers if the user
releases the ENTER key:
onEnter : Handle a -> a -> Attribute
onEnter handle value =
on "keyup" (when (\k -> k.keyCode == 13) getKeyboardEvent) handle (always value)
If the condition is not met, the event does not trigger.
-}
when : (a -> Bool) -> Get a -> Get a
when pred getter =
Native.Html.filterMap (\v -> if pred v then Just v else Nothing) getter
{-| Gives the ability to create new getters from the existing primitives. For
example, if you want only the `keyCode` from a `KeyboardEvent` you can create
a new getter:
getKeyCode : Get Int
getKeyCode =
filterMap (\ke -> Just ke.keyCode) getKeyboardEvent
-}
filterMap : (a -> Maybe b) -> Get a -> Get b
filterMap = Native.Html.filterMap
{-| Attempt to get `event.target.checked`. Only works with checkboxes.
-}
getChecked : Get Bool
getChecked = Native.Html.getChecked
{-| Attempt to get `event.target.value`. Best used with text fields and
text areas.
-}
getValue : Get String
getValue = Native.Html.getValue
{-| Whether a selection goes forward or backward.
-}
data Direction = Forward | Backward
{-| Attempt to get `event.target.value` and selection information held in
`event.target.selectionStart`, `event.target.selectionEnd`, and
`event.target.selectionDirection`. Only works with text fields and text areas.
This is useful when you want your model to fully capture what the user is
typing and highlighting.
-}
getValueAndSelection : Get { value : String
, selection : { start:Int, end:Int, direction:Direction }
}
getValueAndSelection = Native.Html.getValueAndSelection
{-| Attempt to interpret the event as a `MouseEvent`.
-}
getMouseEvent : Get MouseEvent
getMouseEvent = Native.Html.getMouseEvent
{-| Determine which button was clicked and with which modifiers.
-}
type MouseEvent =
{ button : Int
, altKey : Bool
, ctrlKey : Bool
, metaKey : Bool
, shiftKey : Bool
}
{-| Attempt to interpret the event as a `KeyboardEvent`.
-}
getKeyboardEvent : Get KeyboardEvent
getKeyboardEvent = Native.Html.getKeyboardEvent
{-| Determine which key was pressed and with which modifiers.
-}
type KeyboardEvent =
{ keyCode : Int
, altKey : Bool
, ctrlKey : Bool
, metaKey : Bool
, shiftKey : Bool
}
{-| Ignore the event entirely. This extraction always succeeds, returning a unit
value. This is useful for things like click events where you just need to know
that the click occured.
-}
getAnything : Get ()
getAnything = Native.Html.getAnything