on master help sign in
merge, and also bump elm-server to 0.12
5a5f12fJohn P Mayer Jr
Elm.cabal+4−4
@@ -1,5 +1,5 @@
1Name: Elm
1Name: Elm
2−Version: 0.11
2+Version: 0.12
3Synopsis: The Elm language module.
3Synopsis: The Elm language module.
4Description: Elm aims to make client-side web-development more pleasant.
4Description: Elm aims to make client-side web-development more pleasant.
5 It is a statically/strongly typed, functional reactive
5 It is a statically/strongly typed, functional reactive
@@ -14,13 +14,13 @@ License-file: LICENSE
14
14
15Author: Evan Czaplicki
15Author: Evan Czaplicki
16Maintainer: info@elm-lang.org
16Maintainer: info@elm-lang.org
17−Copyright: Copyright: (c) 2011-2013 Evan Czaplicki
17+Copyright: Copyright: (c) 2011-2014 Evan Czaplicki
18
18
19Category: Compiler, Language
19Category: Compiler, Language
20
20
21Build-type: Custom
21Build-type: Custom
22
22
23−Extra-source-files: changelog.txt
23+Extra-source-files: changelog.md
24Data-dir: data
24Data-dir: data
25Data-files: elm-runtime.js interfaces.data docs.json
25Data-files: elm-runtime.js interfaces.data docs.json
26Cabal-version: >=1.9
26Cabal-version: >=1.9
@@ -254,7 +254,7 @@ Test-Suite test-elm
254 Elm,
254 Elm,
255 test-framework,
255 test-framework,
256 test-framework-hunit,
256 test-framework-hunit,
257− test-framework-quickcheck2,
257+ test-framework-quickcheck2 >= 0.3,
258 HUnit,
258 HUnit,
259 pretty,
259 pretty,
260 QuickCheck >= 2 && < 3,
260 QuickCheck >= 2 && < 3,
LICENSE+1−1
@@ -1,4 +1,4 @@
1−Copyright (c) 2012-2013, Evan Czaplicki
1+Copyright (c) 2012-2014, Evan Czaplicki
2
2
3All rights reserved.
3All rights reserved.
4
4
changelog.txt → changelog.mdrenamed+7−4
@@ -1,9 +1,11 @@
1
1
2−## next
2+## 0.12
3
3
4−Breaking Changes:
4+#### Breaking Changes:
5
5
6− * Overhaul Graphics.Input library (inspired by @seliopou and Jeff Smits)
6+ * Overhaul Graphics.Input library (inspired by Spiros Eliopoulos and Jeff Smitts)
7+ * Overhaul Text library to accomodate new Graphics.Input.Field
8+ library and make the API more consistent overall
7 * Overhaul Regex library (inspired by Attila Gazso)
9 * Overhaul Regex library (inspired by Attila Gazso)
8 * Change syntax for "import open List" to "import List (..)"
10 * Change syntax for "import open List" to "import List (..)"
9 * Improved JSON format for types generated by elm-doc
11 * Improved JSON format for types generated by elm-doc
@@ -11,8 +13,9 @@ Breaking Changes:
11 * Revise the semantics of keepWhen and dropWhen to only update when
13 * Revise the semantics of keepWhen and dropWhen to only update when
12 the filtered signal changes (thanks Max New and Janis Voigtländer)
14 the filtered signal changes (thanks Max New and Janis Voigtländer)
13
15
14−Improvements:
16+#### Improvements:
15
17
18+ * Add Graphics.Input.Field for customizable text fields
16 * Add Trampoline library (thanks to @maxsnew and @timthelion)
19 * Add Trampoline library (thanks to @maxsnew and @timthelion)
17 * Add Debug library (inspired by @timthelion)
20 * Add Debug library (inspired by @timthelion)
18 * Drastically improved performance on markdown parsing (thanks to @Dandandan)
21 * Drastically improved performance on markdown parsing (thanks to @Dandandan)
compiler/Build/Flags.hs+1−1
@@ -41,4 +41,4 @@ flags = Flags
41 } &= help "Compile Elm programs to HTML, CSS, and JavaScript."
41 } &= help "Compile Elm programs to HTML, CSS, and JavaScript."
42 &= helpArg [explicit, name "help", name "h"]
42 &= helpArg [explicit, name "help", name "h"]
43 &= versionArg [explicit, name "version", name "v", summary (show Version.elmVersion)]
43 &= versionArg [explicit, name "version", name "v", summary (show Version.elmVersion)]
44− &= summary ("The Elm Compiler " ++ show Version.elmVersion ++ ", (c) Evan Czaplicki 2011-2013")
44+ &= summary ("The Elm Compiler " ++ show Version.elmVersion ++ ", (c) Evan Czaplicki 2011-2014")
compiler/Generate/JavaScript.hs+8−5
@@ -55,7 +55,7 @@ literal lit =
55expression :: Expr -> State Int (Expression ())
55expression :: Expr -> State Int (Expression ())
56expression (A region expr) =
56expression (A region expr) =
57 case expr of
57 case expr of
58− Var (V.Raw x) -> return $ ref x
58+ Var (V.Raw x) -> return $ obj x
59 Literal lit -> return $ literal lit
59 Literal lit -> return $ literal lit
60
60
61 Range lo hi ->
61 Range lo hi ->
@@ -87,10 +87,9 @@ expression (A region expr) =
87 do fields' <- forM fields $ \(f,e) -> do
87 do fields' <- forM fields $ \(f,e) -> do
88 (,) f <$> expression e
88 (,) f <$> expression e
89 let fieldMap = List.foldl' combine Map.empty fields'
89 let fieldMap = List.foldl' combine Map.empty fields'
90− return $ ObjectLit () $ (PropId () (var "_"), hidden fieldMap) : visible fieldMap
90+ return $ ObjectLit () $ (prop "_", hidden fieldMap) : visible fieldMap
91 where
91 where
92 combine r (k,v) = Map.insertWith (++) k [v] r
92 combine r (k,v) = Map.insertWith (++) k [v] r
93− prop = PropId () . var
94 hidden fs = ObjectLit () . map (prop *** ArrayLit ()) .
93 hidden fs = ObjectLit () . map (prop *** ArrayLit ()) .
95 Map.toList . Map.filter (not . null) $ Map.map tail fs
94 Map.toList . Map.filter (not . null) $ Map.map tail fs
96 visible fs = map (first prop) . Map.toList $ Map.map head fs
95 visible fs = map (first prop) . Map.toList $ Map.map head fs
@@ -246,7 +245,11 @@ match region mtch =
246 isLiteral p = case p of
245 isLiteral p = case p of
247 Case.Clause (Right _) _ _ -> True
246 Case.Clause (Right _) _ _ -> True
248 _ -> False
247 _ -> False
248+
249+ access name
249− access name = if any isLiteral clauses then ref name else dotSep [name,"ctor"]
250+ | any isLiteral clauses = obj name
251+ | otherwise = dotSep (split name ++ ["ctor"])
252+
250 format isChars e
253 format isChars e
251 | or isChars = InfixExpr () OpAdd e (string "")
254 | or isChars = InfixExpr () OpAdd e (string "")
252 | otherwise = e
255 | otherwise = e
@@ -310,7 +313,7 @@ generate unsafeModule =
310 jsExports = assign ("_elm" : names modul ++ ["values"]) (ObjectLit () exs)
313 jsExports = assign ("_elm" : names modul ++ ["values"]) (ObjectLit () exs)
311 where
314 where
312 exs = map entry . filter (not . Help.isOp) $ "_op" : exports modul
315 exs = map entry . filter (not . Help.isOp) $ "_op" : exports modul
313− entry x = (PropId () (var x), ref x)
316+ entry x = (prop x, ref x)
314
317
315 assign path expr =
318 assign path expr =
316 case path of
319 case path of
compiler/Parse/Helpers.hs+5−3
@@ -82,9 +82,11 @@ innerVarChar :: IParser Char
82innerVarChar = alphaNum <|> char '_' <|> char '\'' <?> ""
82innerVarChar = alphaNum <|> char '_' <|> char '\'' <?> ""
83
83
84makeVar :: IParser Char -> IParser String
84makeVar :: IParser Char -> IParser String
85+makeVar p = do
85−makeVar p = do v <- (:) <$> p <*> many innerVarChar
86+ v <- (:) <$> p <*> many innerVarChar
86− guard (v `notElem` reserveds)
87+ if v `elem` reserveds
88+ then fail $ "unexpected keyword '" ++ v ++ "', variables cannot be keywords"
87− return v
89+ else return v
88
90
89reserved :: String -> IParser String
91reserved :: String -> IParser String
90reserved word =
92reserved word =
libraries/Automaton.elm.hiddendeleted−123
@@ -1,123 +0,0 @@
1−module Automaton ( pure, state, hiddenState, run, step
2− , (<<<), (>>>), combine, count, average
3− ) where
4−
5−{-| This library is a way to package up dynamic behavior. It makes it easier to
6−dynamically create dynamic components. See the [original release
7−notes](http://elm-lang.org/blog/announce/0.5.0.elm) on this library to get a feel for how
8−it can be used.
9−
10−# Create
11−@docs pure, state, hiddenState
12−
13−# Evaluate
14−@docs run, step
15−
16−# Combine
17−@docs (>>>), (<<<), combine
18−
19−# Common Automatons
20−@docs count, average
21−-}
22−
23−import open Basics
24−import Signal (lift,foldp,Signal)
25−import open List
26−import Maybe (Just, Nothing)
27−
28−data Automaton a b = Step (a -> (Automaton a b, b))
29−
30−{-| Run an automaton on a given signal. The automaton steps forward whenever the
31−input signal updates.
32−-}
33−run : Automaton a b -> b -> Signal a -> Signal b
34−run auto base inputs =
35− let step a (Step f, _) = f a
36− in lift (\(x,y) -> y) (foldp step (auto,base) inputs)
37−
38−{-| Step an automaton forward once with a given input. -}
39−step : a -> Automaton a b -> (Automaton a b, b)
40−step a (Step f) = f a
41−
42−{-| Compose two automatons, chaining them together. -}
43−(>>>) : Automaton a b -> Automaton b c -> Automaton a c
44−f >>> g =
45− Step (\a -> let (f', b) = step a f
46− (g', c) = step b g
47− in (f' >>> g', c))
48−
49−{-| Compose two automatons, chaining them together. -}
50−(<<<) : Automaton b c -> Automaton a b -> Automaton a c
51−g <<< f = f >>> g
52−
53−{-| Combine a list of automatons into a single automaton that produces a
54−list.
55−-}
56−combine : [Automaton a b] -> Automaton a [b]
57−combine autos =
58− Step (\a -> let (autos', bs) = unzip (map (step a) autos)
59− in (combine autos', bs))
60−
61−{-| Create an automaton with no memory. It just applies the given function to
62−every input.
63−-}
64−pure : (a -> b) -> Automaton a b
65−pure f = Step (\x -> (pure f, f x))
66−
67−
68−{-| Create an automaton with state. Requires an initial state and a step
69−function to step the state forward. For example, an automaton that counted
70−how many steps it has taken would look like this:
71−
72− count = Automaton a Int
73− count = state 0 (\\_ c -> c+1)
74−
75−It is a stateful automaton. The initial state is zero, and the step function
76−increments the state on every step.
77−-}
78−state : b -> (a -> b -> b) -> Automaton a b
79−state s f = Step (\x -> let s' = f x s
80− in (state s' f, s'))
81−
82−{-| Create an automaton with hidden state. Requires an initial state and a
83−step function to step the state forward and produce an output.
84−-}
85−hiddenState : s -> (a -> s -> (s,b)) -> Automaton a b
86−hiddenState s f = Step (\x -> let (s',out) = f x s
87− in (hiddenState s' f, out))
88−
89−{-| Count the number of steps taken. -}
90−count : Automaton a Int
91−count = state 0 (\_ c -> c + 1)
92−
93−type Queue t = ([t],[t])
94−empty = ([],[])
95−enqueue x (en,de) = (x::en, de)
96−dequeue q = case q of
97− ([],[]) -> Nothing
98− (en,[]) -> dequeue ([], reverse en)
99− (en,hd::tl) -> Just (hd, (en,tl))
100−
101−{-| Computes the running average of the last `n` inputs. -}
102−average : Int -> Automaton Float Float
103−average k =
104− let step n (ns,len,sum) =
105− if len == k then stepFull n (ns,len,sum)
106− else ((enqueue n ns, len+1, sum+n), (sum+n) / (toFloat len+1))
107− stepFull n (ns,len,sum) =
108− case dequeue ns of
109− Nothing -> ((ns,len,sum), 0)
110− Just (m,ns') -> let sum' = sum + n - m
111− in ((enqueue n ns', len, sum'), sum' / toFloat len)
112− in hiddenState (empty,0,0) step
113−
114−
115−{-- TODO(evancz): See the following papers for ideas on how to make this
116−library faster and better:
117−
118−- Functional Reactive Programming, Continued
119−- Causal commutative arrows and their optimization
120−
121−Speeding things up is a really low priority. Language features and
122−libraries with nice APIs and are way more important!
123−--}
libraries/AutomatonV2.elm.hiddendeleted−149
@@ -1,149 +0,0 @@
1−module AutomatonV2 where
2−{-| This library is a way to package up dynamic behavior. It makes it easier to
3−dynamically create dynamic components. See the [original release
4−notes](/blog/announce/version-0.5.0.elm) on this library to get a feel for how
5−it can be used.
6−-}
7−
8−import open Basics
9−import Signal (lift,foldp,Signal)
10−import open List
11−import Maybe (Just, Nothing)
12−
13−data Automaton input output = Pure (input -> output)
14− | Stateful state (input -> state -> (output,state))
15−
16−-- The basics
17−
18−-- AFRP name: arr
19−pure: (i -> o) -> Automaton i o
20−pure = Pure
21−
22−-- AFRP name: >>>
23−andThen: Automaton i inter -> Automaton inter o -> Automaton i o
24−andThen first second =
25− case first of
26− Pure f -> case second of -- f is the function from first
27− Pure s -> Pure (s . f) -- s is the function from second
28− Stateful b s -> Stateful b (\i -> s (f i)) -- b is the base state from second
29− Stateful fb f -> case second of -- fb is the base state from first
30− Pure s -> Stateful fb (\i st -> -- sb is the base state from second
31− let (inter, st') = f i st -- i is the input
32− in (s inter, st')) -- st is the input state
33− Stateful sb s -> Stateful (fb, sb) (\i (fst, sst) -> -- inter is the intermediate value
34− let (inter, fst') = f i fst -- st' is the new state
35− (o, sst') = s inter sst -- fst and sst are the state of first and second
36− in (o, (fst', sst'))) -- ect...
37−
38−-- AFRP name: first
39−extendDown: Automaton i o -> Automaton (i,extra) (o,extra)
40−extendDown auto = case auto of
41− Pure fun -> Pure (\(i,extra) -> (fun i, extra))
42− Stateful base fun -> Stateful base (\(i,extra) s -> (fun i s, extra))
43−
44−-- AFRP name: loop
45−loop: s -> Automaton (i,s) (o,s) -> Automaton i o
46−loop base auto = case auto of
47− Pure fun -> Stateful base (curry fun)
48− Stateful base2 fun -> -- fun: (i, s) -> s2 -> ((o, s), s2)
49− let newFun = (\i (s,s2) ->
50− let ((o, s'), s2') = fun (i, s) s2
51− in (o, (s', s2'))) -- newFun: i -> (s, s2) -> (o, (s, s2))
52− in Stateful (base, base2) newFun
53−
54−-- Run an automaton on a given signal
55−run: Automaton i o -> o -> Signal i -> Signal o
56−run auto baseOut input = case auto of
57− Pure fun -> lift fun input
58− Stateful base fun -> lift fst
59− (foldp (\i (o, s) -> fun i s)
60− (baseOut, base) input)
61−
62−
63−-- Other frequently used functions/operators
64−
65−-- Create an automaton with state. Requires an initial state and a step
66−-- function to step the state forward. For example, an automaton that counted
67−-- how many steps it has taken would look like this:
68−--
69−-- count = Automaton a Int
70−-- count = state 0 (\\_ c -> c+1)
71−--
72−-- It is a stateful automaton. The initial state is zero, and the step function
73−-- increments the state on every step.
74−state : s -> (i -> s -> s) -> Automaton i s
75−state base fun = loop base (pure (\(i,s) ->
76− let s' = fun i s
77− in (s',s')))
78−
79−-- Create an automaton with hidden state. Requires an initial state and a
80−-- step function to step the state forward and produce an output.
81−hiddenState : s -> (i -> s -> (s,o)) -> Automaton i o
82−hiddenState base fun = loop base (pure (\(i,s) ->
83− let (o,s') = fun i s
84− in (s',o)))
85−
86−-- AFRP name: second
87−extendUp: Automaton i o -> Automaton (extra,i) (extra,o)
88−extendUp auto =
89− let swap (a, b) = (b, a)
90− in pure swap `andThen` extendDown auto `andThen` pure swap
91−
92−-- (parallel composition)
93−pair: Automaton i1 o1 -> Automaton i2 o2 -> Automaton (i1,i2) (o1,o2)
94−pair f g = extendDown f `andThen` extendUp g
95−
96−branch : Automaton i o1 -> Automaton i o2 -> Automaton i (o1,o2)
97−branch f g =
98− let double = pure (\i -> (i,i))
99− in double `andThen` pair f g
100−
101−combi: Automaton i o -> Automaton i [o] -> Automaton i [o]
102−combi a1 a2 = (a1 `branch` a2) `andThen` pure (uncurry (::))
103−
104−-- Combine a list of automatons into a single automaton that produces a list.
105−combine : [Automaton i o] -> Automaton i [o]
106−combine autos =
107− let l = length autos
108− in if l == 0
109− then pure (\_ -> [])
110− else foldr combi (last autos `andThen` pure (\a -> [a])) (take (l-1) autos)
111−
112−
113−-- Examples of automata
114−
115−-- Count the number of steps taken.
116−count : Automaton a Int
117−count = state 0 (\_ c -> c + 1)
118−
119−type Queue t = ([t],[t])
120−empty = ([],[])
121−enqueue x (en,de) = (x::en, de)
122−dequeue q = case q of
123− ([],[]) -> Nothing
124− (en,[]) -> dequeue ([], reverse en)
125− (en,hd::tl) -> Just (hd, (en,tl))
126−
127−-- Computes the running average of the last `n` inputs.
128−average : Int -> Automaton Float Float
129−average k =
130− let step n (ns,len,sum) =
131− if len == k then stepFull n (ns,len,sum)
132− else ((enqueue n ns, len+1, sum+n), (sum+n) / (toFloat len+1))
133− stepFull n (ns,len,sum) =
134− case dequeue ns of
135− Nothing -> ((ns,len,sum), 0)
136− Just (m,ns') -> let sum' = sum + n - m
137− in ((enqueue n ns', len, sum'), sum' / toFloat len)
138− in hiddenState (empty,0,0) step
139−
140−
141−{-- TODO(evancz): See the following papers for ideas on how to make this
142−library faster and better:
143−
144−- Functional Reactive Programming, Continued -- took some inspirations from this paper (Apanatshka)
145−- Causal commutative arrows and their optimization
146−
147−Speeding things up is a really low priority. Language features and
148−libraries with nice APIs and are way more important!
149−--}
libraries/Basics.elm+27
@@ -39,6 +39,9 @@ which happen to be radians.
39# Polar Coordinates
39# Polar Coordinates
40@docs toPolar, fromPolar
40@docs toPolar, fromPolar
41
41
42+# Floating Point Checks
43+@docs isNaN, isInfinite
44+
42# Tuples
45# Tuples
43@docs fst, snd
46@docs fst, snd
44
47
@@ -271,6 +274,30 @@ ceiling = Native.Basics.ceiling
271toFloat : Int -> Float
274toFloat : Int -> Float
272toFloat = Native.Basics.toFloat
275toFloat = Native.Basics.toFloat
273
276
277+{- | Determines whether a float is an undefined or unrepresentable number.
278+NaN stands for *not a number* and it is [a standardized part of floating point
279+numbers](http://en.wikipedia.org/wiki/NaN).
280+
281+ isNaN (0/0) == True
282+ isNaN (sqrt -1) == True
283+ isNaN (1/0) == False -- infinity is a number
284+ isNaN 1 == False
285+-}
286+isNaN : Float -> Bool
287+isNaN = Native.Basics.isNaN
288+
289+{- | Determines whether a float is positive or negative infinity.
290+
291+ isInfinite (0/0) == False
292+ isInfinite (sqrt -1) == False
293+ isInfinite (1/0) == True
294+ isInfinite 1 == False
295+
296+Notice that NaN is not infinite! For float `n` to be finite implies that
297+`not (isInfinite n || isNaN n)` evaluates to `True`.
298+-}
299+isInfinite : Float -> Bool
300+isInfinite = Native.Basics.isInfinite
274
301
275-- Function Helpers
302-- Function Helpers
276
303
libraries/Char.elm+2−2
@@ -52,8 +52,8 @@ toLocaleLower = Native.Char.toLocaleLower
52
52
53type KeyCode = Int
53type KeyCode = Int
54
54
55−{-| Convert to unicode. Used with the [`Keyboard`](/docs/Keyboard.elm)
55+{-| Convert to unicode. Used with the `Keyboard` library, which expects the
56−library, which expects the input to be uppercase. -}
56+input to be uppercase. -}
57toCode : Char -> KeyCode
57toCode : Char -> KeyCode
58toCode = Native.Char.toCode
58toCode = Native.Char.toCode
59
59
libraries/Debug.elm+2
@@ -1,6 +1,8 @@
1module Debug where
1module Debug where
2{-| This library is for investigating bugs or performance problems. It should
2{-| This library is for investigating bugs or performance problems. It should
3*not* be used in production code.
3*not* be used in production code.
4+
5+@docs log
4-}
6-}
5
7
6import Native.Debug
8import Native.Debug
libraries/Graphics/Input.elm+1−1
@@ -118,7 +118,7 @@ favorite British sport:
118
118
119 data Sport = Football | Cricket | Snooker
119 data Sport = Football | Cricket | Snooker
120
120
121− sport : Input Sport
121+ sport : Input (Maybe Sport)
122 sport = input Nothing
122 sport = input Nothing
123
123
124 sportDropDown : Element
124 sportDropDown : Element
libraries/Graphics/Input/Field.elm+63−23
@@ -1,7 +1,8 @@
1module Graphics.Input.Field where
1module Graphics.Input.Field where
2−{-| This library specifically addresses text fields. It uses the same general
2+{-| This library provides an API for creating and updating text fields.
3−approach as the [`Graphics.Input`](Graphics-Input) module for describing an
3+Text fields use exactly the same approach as [`Graphics.Input`](Graphics-Input)
4−`Input`, so this library focuses on creating and styling text fields.
4+for modelling user input, allowing you to keep track of new events and update
5+text fields programmatically.
5
6
6# Create Fields
7# Create Fields
7@docs field, password, email
8@docs field, password, email
@@ -20,21 +21,33 @@ import Graphics.Input (Input, Handle)
20import Native.Graphics.Input
21import Native.Graphics.Input
21import Text
22import Text
22
23
23−{-| Easily create uniform dimensions:
24+{-| Create uniform dimensions:
24
25
25 uniformly 4 == { left=4, right=4, top=4, bottom=4 }
26 uniformly 4 == { left=4, right=4, top=4, bottom=4 }
27+
28+The following example creates an outline where the left, right, top, and bottom
29+edges all have width 1:
30+
31+ Outline grey (uniformly 1) 4
26-}
32-}
27uniformly : Int -> Dimensions
33uniformly : Int -> Dimensions
28uniformly n = Dimensions n n n n
34uniformly n = Dimensions n n n n
29
35
30{-| For setting dimensions of a fields padding or border. The left, right, top,
36{-| For setting dimensions of a fields padding or border. The left, right, top,
31−and bottom may all have different sizes.
37+and bottom may all have different sizes. The following example creates
38+dimensions such that the left and right are twice as wide as the top and bottom:
39+
40+ myDimensions : Int -> Dimensions
41+ myDimensions n = { left = 2 * n, right = 2 * n, top = n, bottom = n }
32-}
42-}
33type Dimensions = { left:Int, right:Int, top:Int, bottom:Int }
43type Dimensions = { left:Int, right:Int, top:Int, bottom:Int }
34
44
35{-| A field can have a outline around it. This lets you set its color, width,
45{-| A field can have a outline around it. This lets you set its color, width,
36and radius. The radius allows you to round the corners of your field. Set the
46and radius. The radius allows you to round the corners of your field. Set the
37−width to zero to make it invisible.
47+width to zero to make it invisible. Here is an example outline that is grey
48+and thin with slightly rounded corners:
49+
50+ { color = grey, width = uniformly 1, radius = 4 }
38-}
51-}
39type Outline = { color:Color, width:Dimensions, radius:Int }
52type Outline = { color:Color, width:Dimensions, radius:Int }
40
53
@@ -42,8 +55,12 @@ type Outline = { color:Color, width:Dimensions, radius:Int }
42noOutline : Outline
55noOutline : Outline
43noOutline = Outline Color.grey (uniformly 0) 0
56noOutline = Outline Color.grey (uniformly 0) 0
44
57
45−{-| When a field is selected, it has an highlight around it by default. Set the
58+{-| When a field has focus, it has a blue highlight around it by default. The
46−width of the `Highlight` to zero to make it go away.
59+`Highlight` lets you set the `color` and `width` of this highlight. Set the
60+`width` to zero to turn the highlight off. Here is an example highlight that
61+is blue and thin:
62+
63+ { color = blue, width = 1 }
47-}
64-}
48type Highlight = { color:Color, width:Int }
65type Highlight = { color:Color, width:Int }
49
66
@@ -51,10 +68,18 @@ type Highlight = { color:Color, width:Int }
51noHighlight : Highlight
68noHighlight : Highlight
52noHighlight = Highlight Color.blue 0
69noHighlight = Highlight Color.blue 0
53
70
54−{-| Describes the style of a text box. The `style` field describes the style
71+{-| Describe the style of a text box. `style` describes the style of the text
55−of the text itself. The `outline` field describes the glowing blue outline that
72+itself using [`Text.Style`](/Text#Style). `outline` describes the glowing blue
56−shows up when the field has focus. Turn off `outline` by setting its width to
73+outline that shows up when the field has focus. `outline` describes the line
57−zero. The
74+surrounding the text field, and `padding` adds whitespace between the `outline`
75+and the text.
76+
77+The width and height of the text box *includes* the `padding` and `outline`.
78+Say we have a text box that is 40 pixels tall. It has a uniform outline of
79+1 pixel and a uniform padding of 5 pixels. Both of these must be subtracted
80+from the total height to determine how much room there is for text. The
81+`padding` and `outline` appear on the top and bottom, so there will be 28
82+vertical pixels remaining for the text (40 - 1 - 5 - 5 - 1).
58-}
83-}
59type Style =
84type Style =
60 { padding : Dimensions
85 { padding : Dimensions
@@ -77,27 +102,32 @@ defaultStyle =
77
102
78{-| Represents the current content of a text field. For example:
103{-| Represents the current content of a text field. For example:
79
104
80− Content "She sells sea shells" (Selection 0 3 Backward)
105+ content = Content "She sells sea shells" (Selection 0 3 Backward)
81
106
82−This means the user highlighted the substring `"She"` backwards.
107+This means the user highlighted the substring `"She"` backwards. The value of
108+`content.string` is `"She sells sea shells"`.
83-}
109-}
84type Content = { string:String, selection:Selection }
110type Content = { string:String, selection:Selection }
85
111
86{-| The selection within a text field. `start` is never greater than `end`:
112{-| The selection within a text field. `start` is never greater than `end`:
87
113
88− Selection 0 0 Forward -- cursor precedes all characters
114+ Selection 0 0 Forward -- cursor precedes all characters
89
115
90− Selection 5 9 Backward -- highlighting characters starting after
116+ Selection 5 9 Backward -- highlighting characters starting after
91− -- the 5th and ending after the 9th
117+ -- the 5th and ending after the 9th
92-}
118-}
93type Selection = { start:Int, end:Int, direction:Direction }
119type Selection = { start:Int, end:Int, direction:Direction }
94
120
95−{-| The direction of selection.-}
121+{-| The direction of selection. When the user highlights a selection in a text
122+field, they must do it in a particular direction. This determines which end of
123+the selection moves when they change the selection by pressing Shift-Left or
124+Shift-Right.
125+-}
96data Direction = Forward | Backward
126data Direction = Forward | Backward
97
127
98{-| A field with no content:
128{-| A field with no content:
99
129
100− Content "" (Selection 0 0 Forward)
130+ Content "" (Selection 0 0 Forward)
101-}
131-}
102noContent : Content
132noContent : Content
103noContent = Content "" (Selection 0 0 Forward)
133noContent = Content "" (Selection 0 0 Forward)
@@ -110,20 +140,30 @@ to match what they have entered.
110 name = input noContent
140 name = input noContent
111
141
112 nameField : Signal Element
142 nameField : Signal Element
113− nameField = field name.handle id defaultStyle "Name" <~ name.signal
143+ nameField = field defaultStyle name.handle id "Name" <~ name.signal
144+
145+When we use the `field` function, we first give it a visual style. This is
146+the first argument so that it is easier to define your own custom field
147+(`myField = field myStyle`). The next two arguments are a `Handle` and a
148+handler function that processes or augments events before sending them along
149+to the associated `Input`. In the example above we use the `id` function to
150+pass events along unchanged to the `name` `Input`. We then provide the
151+place-holder message to use when no input has been provided yet. Finally,
152+we give the current `Content` of the field. This argument is last because
153+it is most likely to change frequently, making function composition easier.
114-}
154-}
115−field : Handle a -> (Content -> a) -> Style -> String -> Content -> Element
155+field : Style -> Handle a -> (Content -> a) -> String -> Content -> Element
116field = Native.Graphics.Input.field
156field = Native.Graphics.Input.field
117
157
118{-| Same as `field` but the UI element blocks out each characters. -}
158{-| Same as `field` but the UI element blocks out each characters. -}
119−password : Handle a -> (Content -> a) -> Style -> String -> Content -> Element
159+password : Style -> Handle a -> (Content -> a) -> String -> Content -> Element
120password = Native.Graphics.Input.password
160password = Native.Graphics.Input.password
121
161
122{-| Same as `field` but it adds an annotation that this field is for email
162{-| Same as `field` but it adds an annotation that this field is for email
123addresses. This is helpful for auto-complete and for mobile users who may
163addresses. This is helpful for auto-complete and for mobile users who may
124get a custom keyboard with an `@` and `.com` button.
164get a custom keyboard with an `@` and `.com` button.
125-}
165-}
126−email : Handle a -> (Content -> a) -> Style -> String -> Content -> Element
166+email : Style -> Handle a -> (Content -> a) -> String -> Content -> Element
127email = Native.Graphics.Input.email
167email = Native.Graphics.Input.email
128
168
129-- area : Handle a -> (Content -> a) -> Handle b -> ((Int,Int) -> b) -> (Int,Int) -> String -> Content -> Element
169-- area : Handle a -> (Content -> a) -> Handle b -> ((Int,Int) -> b) -> (Int,Int) -> String -> Content -> Element
libraries/Http.elm+2−4
@@ -1,8 +1,6 @@
1module Http where
1module Http where
2−
3−{-| A library for asynchronous HTTP requests. See the
2+{-| A library for asynchronous HTTP requests. See the `WebSocket`
4−[WebSocket](http://elm-lang.org/docs/WebSocket.elm) library if
5−you have very strict latency requirements.
3+library if you have very strict latency requirements.
6
4
7# Sending Requests
5# Sending Requests
8@docs send, sendGet
6@docs send, sendGet
libraries/Keyboard.elm+2−4
@@ -1,5 +1,4 @@
1module Keyboard where
1module Keyboard where
2−
3{-| Library for working with keyboard input.
2{-| Library for working with keyboard input.
4
3
5# Representing Keys
4# Representing Keys
@@ -20,9 +19,8 @@ import Signal (Signal)
20import Native.Keyboard
19import Native.Keyboard
21
20
22{-| Type alias to make it clearer what integers are supposed to represent
21{-| Type alias to make it clearer what integers are supposed to represent
23−in this library. Use [`Char.toCode`](docs/Char.elm#toCode) and
22+in this library. Use `Char.toCode` and `Char.fromCode` to convert key codes
24−[`Char.fromCode`](/docs/Char.elm#fromCode) to convert key codes to characters.
25−Use the uppercase character with `toCode`.
23+to characters. Use the uppercase character with `toCode`.
26-}
24-}
27type KeyCode = Int
25type KeyCode = Int
28
26
libraries/Native/Basics.js+3
@@ -19,6 +19,7 @@ Elm.Native.Basics.make = function(elm) {
19 return Utils.cmp(n,lo) < 0 ? lo : Utils.cmp(n,hi) > 0 ? hi : n; }
19 return Utils.cmp(n,lo) < 0 ? lo : Utils.cmp(n,hi) > 0 ? hi : n; }
20 function xor(a,b) { return a !== b; }
20 function xor(a,b) { return a !== b; }
21 function not(b) { return !b; }
21 function not(b) { return !b; }
22+ function isInfinite(n) { return n === Infinity || n === -Infinity }
22
23
23 function truncate(n) { return n|0; }
24 function truncate(n) { return n|0; }
24
25
@@ -53,6 +54,8 @@ Elm.Native.Basics.make = function(elm) {
53 floor:Math.floor,
54 floor:Math.floor,
54 round:Math.round,
55 round:Math.round,
55 toFloat:function(x) { return x; },
56 toFloat:function(x) { return x; },
57+ isNaN:isNaN,
58+ isInfinite:isInfinite
56 };
59 };
57
60
58 return elm.Native.Basics.values = basics;
61 return elm.Native.Basics.values = basics;
libraries/Native/Debug.js+5−3
@@ -7,10 +7,12 @@ Elm.Native.Debug.make = function(elm) {
7 var show = Elm.Native.Show.make(elm).show;
7 var show = Elm.Native.Show.make(elm).show;
8
8
9 function log(tag,value) {
9 function log(tag,value) {
10− if (process && process.stdout) {
11− process.stdout.write(tag + ': ' + show(value));
10+ var msg = tag + ': ' + show(value);
11+ var process = process || {};
12+ if (process.stdout) {
13+ process.stdout.write(msg);
12 } else {
14 } else {
13− console.log(tag + ': ' + show(value));
15+ console.log(msg);
14 }
16 }
15 return value;
17 return value;
16 }
18 }
libraries/Native/Graphics/Input.js+3−20
@@ -273,24 +273,6 @@ Elm.Native.Graphics.Input.make = function(elm) {
273 field.elm_handler = model.handler;
273 field.elm_handler = model.handler;
274 field.elm_old_value = field.value;
274 field.elm_old_value = field.value;
275
275
276− function keyUpdate(event) {
277− var curr = field.value;
278− var next = (curr.slice(0, field.selectionStart) +
279− String.fromCharCode(event.keyCode) +
280− curr.slice(field.selectionEnd));
281− var pos = field.selectionEnd + 1;
282− elm.notify(field.elm_signal.id, field.elm_handler({
283− _:{},
284− string: JS.toString(next),
285− selection: {
286− start: pos,
287− end: pos,
288− direction: { ctor:'Forward' }
289− },
290− }));
291− event.preventDefault();
292− }
293−
294 function inputUpdate(event) {
276 function inputUpdate(event) {
295 var curr = field.elm_old_value;
277 var curr = field.elm_old_value;
296 var next = field.value;
278 var next = field.value;
@@ -307,6 +289,7 @@ Elm.Native.Graphics.Input.make = function(elm) {
307 _:{},
289 _:{},
308 string: JS.toString(next),
290 string: JS.toString(next),
309 selection: {
291 selection: {
292+ _:{},
310 start: start,
293 start: start,
311 end: end,
294 end: end,
312 direction: { ctor: direction }
295 direction: { ctor: direction }
@@ -320,6 +303,7 @@ Elm.Native.Graphics.Input.make = function(elm) {
320 _:{},
303 _:{},
321 string: field.value,
304 string: field.value,
322 selection: {
305 selection: {
306+ _:{},
323 start: field.selectionStart,
307 start: field.selectionStart,
324 end: field.selectionEnd,
308 end: field.selectionEnd,
325 direction: { ctor: direction }
309 direction: { ctor: direction }
@@ -334,7 +318,6 @@ Elm.Native.Graphics.Input.make = function(elm) {
334 mouseUpdate(event);
318 mouseUpdate(event);
335 elm.node.removeEventListener('mouseup', mouseup)
319 elm.node.removeEventListener('mouseup', mouseup)
336 }
320 }
337− field.addEventListener('keypress', keyUpdate);
338 field.addEventListener('input', inputUpdate);
321 field.addEventListener('input', inputUpdate);
339 field.addEventListener('mousedown', mousedown);
322 field.addEventListener('mousedown', mousedown);
340 field.addEventListener('focus', function() {
323 field.addEventListener('focus', function() {
@@ -367,7 +350,7 @@ Elm.Native.Graphics.Input.make = function(elm) {
367 }
350 }
368
351
369 function mkField(type) {
352 function mkField(type) {
370− function field(signal, handler, style, placeHolder, content) {
353+ function field(style, signal, handler, placeHolder, content) {
371 var padding = style.padding;
354 var padding = style.padding;
372 var outline = style.outline.width;
355 var outline = style.outline.width;
373 var adjustWidth = padding.left + padding.right + outline.left + outline.right;
356 var adjustWidth = padding.left + padding.right + outline.left + outline.right;
libraries/Native/Regex.js+1−1
@@ -20,7 +20,7 @@ Elm.Native.Regex.make = function(elm) {
20 }
20 }
21
21
22 function contains(re, string) {
22 function contains(re, string) {
23− return re.test(JS.fromString(string));
23+ return JS.fromString(string).match(re) !== null;
24 }
24 }
25
25
26 function find(n, re, str) {
26 function find(n, re, str) {
libraries/Native/Signal/Http.js+52−49
@@ -1,61 +1,64 @@
1Elm.Native.Http = {};
1Elm.Native.Http = {};
2Elm.Native.Http.make = function(elm) {
2Elm.Native.Http.make = function(elm) {
3
3
4− elm.Native = elm.Native || {};
4+ elm.Native = elm.Native || {};
5− elm.Native.Http = elm.Native.Http || {};
5+ elm.Native.Http = elm.Native.Http || {};
6− if (elm.Native.Http.values) return elm.Native.Http.values;
6+ if (elm.Native.Http.values) return elm.Native.Http.values;
7
7
8+ var JS = Elm.JavaScript.make(elm);
9+ var List = Elm.List.make(elm);
10+ var Signal = Elm.Signal.make(elm);
8
11
9− var JS = Elm.JavaScript.make(elm);
12+ function registerReq(queue,responses) {
10− var List = Elm.List.make(elm);
13+ return function(req) {
11− var Signal = Elm.Signal.make(elm);
14+ if (req.url.length > 0) {
15+ sendReq(queue,responses,req);
16+ }
17+ };
18+ }
12
19
20+ function updateQueue(queue,responses) {
21+ if (queue.length > 0) {
22+ elm.notify(responses.id, queue[0].value);
23+ if (queue[0].value.ctor !== 'Waiting') {
24+ queue.shift();
25+ setTimeout(function() { updateQueue(queue,responses); }, 0);
26+ }
27+ }
28+ }
13
29
14− function registerReq(queue,responses) { return function(req) {
15− if (req.url.ctor !== '[]') { sendReq(queue,responses,req); }
30+ function sendReq(queue,responses,req) {
16− };
31+ var response = { value: { ctor:'Waiting' } };
17− }
32+ queue.push(response);
18
33
19− function updateQueue(queue,responses) {
34+ var request = (window.ActiveXObject
20− if (queue.length > 0) {
21− elm.notify(responses.id, queue[0].value);
22− if (queue[0].value.ctor !== 'Waiting') {
23− queue.shift();
24− setTimeout(function() { updateQueue(queue,responses); }, 0);
25− }
26− }
27− }
28−
29− function sendReq(queue,responses,req) {
30− var response = { value: { ctor:'Waiting' } };
31− queue.push(response);
32−
33− var request = null;
34− if (window.ActiveXObject) { request = new ActiveXObject("Microsoft.XMLHTTP"); }
35+ ? new ActiveXObject("Microsoft.XMLHTTP")
35− if (window.XMLHttpRequest) { request = new XMLHttpRequest(); }
36+ : new XMLHttpRequest());
36− request.onreadystatechange = function(e) {
37− if (request.readyState === 4) {
38− response.value = (request.status >= 200 && request.status < 300 ?
39− { ctor:'Success', _0:JS.toString(request.responseText) } :
40− { ctor:'Failure', _0:request.status, _1:JS.toString(request.statusText) });
41− setTimeout(function() { updateQueue(queue,responses); }, 0);
42− }
43− };
44− request.open(JS.fromString(req.verb), JS.fromString(req.url), true);
45− function setHeader(pair) {
46− request.setRequestHeader( JS.fromString(pair._0), JS.fromString(pair._1) );
47− }
48− List.map(setHeader)(req.headers);
49− request.send(JS.fromString(req.body));
50− }
51
37
52− function send(requests) {
38+ request.onreadystatechange = function(e) {
53− var responses = Signal.constant(elm.Http.values.Waiting);
39+ if (request.readyState === 4) {
54− var sender = A2( Signal.lift, registerReq([],responses), requests );
40+ response.value = (request.status >= 200 && request.status < 300 ?
55− function f(x) { return function(y) { return x; } }
41+ { ctor:'Success', _0:JS.toString(request.responseText) } :
56− return A3( Signal.lift2, f, responses, sender );
42+ { ctor:'Failure', _0:request.status, _1:JS.toString(request.statusText) });
43+ setTimeout(function() { updateQueue(queue,responses); }, 0);
44+ }
45+ };
46+ request.open(JS.fromString(req.verb), JS.fromString(req.url), true);
47+ function setHeader(pair) {
48+ request.setRequestHeader( JS.fromString(pair._0), JS.fromString(pair._1) );
49+ }
50+ List.map(setHeader)(req.headers);
51+ request.send(JS.fromString(req.body));
57− }
52+ }
58
53
59− return elm.Native.Http.values = {send:send};
54+ function send(requests) {
55+ var responses = Signal.constant(elm.Http.values.Waiting);
56+ var sender = A2( Signal.lift, registerReq([],responses), requests );
57+ function f(x) { return function(y) { return x; } }
58+ return A3( Signal.lift2, f, responses, sender );
59+ }
60
60
61+ return elm.Native.Http.values = {
62+ send:send
63+ };
61};
64};
libraries/Native/Text.js+1−1
@@ -57,7 +57,7 @@ Elm.Native.Text.make = function(elm) {
57 var typefaces = List.toArray(list);
57 var typefaces = List.toArray(list);
58 for (var i = typefaces.length; i--; ) {
58 for (var i = typefaces.length; i--; ) {
59 var typeface = typefaces[i];
59 var typeface = typefaces[i];
60− if (typeface.contains(' ')) {
60+ if (typeface.indexOf(' ') > -1) {
61 typefaces[i] = "'" + typeface + "'";
61 typefaces[i] = "'" + typeface + "'";
62 }
62 }
63 }
63 }
libraries/Native/Utils.js+6−1
@@ -9,7 +9,12 @@ Elm.Native.Utils.make = function(elm) {
9 if (x === y) return true;
9 if (x === y) return true;
10 if (typeof x === "object") {
10 if (typeof x === "object") {
11 var c = 0;
11 var c = 0;
12+ for (var i in x) {
13+ ++c;
14+ if (!eq(x[i],y[i])) {
12− for (var i in x) { ++c; if (!eq(x[i],y[i])) return false; }
15+ return false;
16+ }
17+ }
13 return c === Object.keys(y).length;
18 return c === Object.keys(y).length;
14 }
19 }
15 if (typeof x === 'function') {
20 if (typeof x === 'function') {
libraries/Signal.elm+1−1
@@ -10,7 +10,7 @@ past-dependence.
10
10
11Some useful functions for working with time (e.g. setting FPS) and combining
11Some useful functions for working with time (e.g. setting FPS) and combining
12signals and time (e.g. delaying updates, getting timestamps) can be found in
12signals and time (e.g. delaying updates, getting timestamps) can be found in
13−the [`Time`](/docs/Signal/Time.elm) library.
13+the `Time` library.
14
14
15# Combine
15# Combine
16@docs constant, lift, lift2, merge, merges, combine
16@docs constant, lift, lift2, merge, merges, combine
libraries/String.elm+6−6
@@ -174,18 +174,18 @@ pad = Native.String.pad
174
174
175{-| Pad a string on the left until it has a given length.
175{-| Pad a string on the left until it has a given length.
176
176
177− pad 5 '.' "1" == "....1"
177+ padLeft 5 '.' "1" == "....1"
178− pad 5 '.' "11" == "...11"
178+ padLeft 5 '.' "11" == "...11"
179− pad 5 '.' "121" == "..121"
179+ padLeft 5 '.' "121" == "..121"
180-}
180-}
181padLeft : Int -> Char -> String -> String
181padLeft : Int -> Char -> String -> String
182padLeft = Native.String.padLeft
182padLeft = Native.String.padLeft
183
183
184{-| Pad a string on the right until it has a given length.
184{-| Pad a string on the right until it has a given length.
185
185
186− pad 5 '.' "1" == "1...."
186+ padRight 5 '.' "1" == "1...."
187− pad 5 '.' "11" == "11..."
187+ padRight 5 '.' "11" == "11..."
188− pad 5 '.' "121" == "121.."
188+ padRight 5 '.' "121" == "121.."
189-}
189-}
190padRight : Int -> Char -> String -> String
190padRight : Int -> Char -> String -> String
191padRight = Native.String.padRight
191padRight = Native.String.padRight
libraries/Text.elm+86−13
@@ -1,15 +1,21 @@
1module Text where
1module Text where
2−
3−{-| Functions for displaying text
2+{-| A library for styling and displaying text. Whlie the `String` library
3+focuses on representing and manipulating strings of character strings, the
4+`Text` library focuses on how those strings should look on screen. It lets
5+you make text bold or italic, set the typeface, set the text size, etc.
4
6
5# Creating Text
7# Creating Text
6@docs toText
8@docs toText
7
9
8# Creating Elements
10# Creating Elements
11+
12+Each of the following functions places `Text` into a box. The function you use
13+determines the alignment of the text.
14+
9@docs leftAligned, rightAligned, centered, justified
15@docs leftAligned, rightAligned, centered, justified
10
16
11# Links and Style
17# Links and Style
12−@docs link, Style, style, Line, defaultStyle
18+@docs link, Style, style, defaultStyle, Line
13
19
14# Convenience Functions
20# Convenience Functions
15
21
@@ -35,9 +41,28 @@ import Native.Text
35
41
36data Text = Text
42data Text = Text
37
43
44+{-| Styles for lines on text. This allows you to add an underline, an overline,
45+or a strike out text:
46+
47+ line Under (toText "underline")
48+ line Over (toText "overline")
49+ line Through (toText "strike out")
50+-}
38data Line = Under | Over | Through
51data Line = Under | Over | Through
39
52
40−{-| Representation of all the ways you can style `Text`.
53+{-| Representation of all the ways you can style `Text`. If the `typeface` list
54+is empty or the `height` is `Nothing`, the users will fall back on their
55+browser's default settings. The following `Style` is black, 16 pixel tall,
56+underlined, and Times New Roman (assuming that typeface is available on the
57+user's computer):
58+
59+ { typeface = [ "Times New Roman", "serif" ]
60+ , height = Just 16
61+ , color = black
62+ , bold = False
63+ , italic = False
64+ , line = Just Under
65+ }
41-}
66-}
42type Style =
67type Style =
43 { typeface : [String]
68 { typeface : [String]
@@ -69,11 +94,19 @@ defaultStyle =
69 , line = Nothing
94 , line = Nothing
70 }
95 }
71
96
72−{-| Convert a string into text which can be styled and displayed. -}
97+{-| Convert a string into text which can be styled and displayed. To show the
98+string `"Hello World!"` on screen in italics, you could say:
99+
100+ main = leftAligned (italic (toText "Hello World!"))
101+-}
73toText : String -> Text
102toText : String -> Text
74toText = Native.Text.toText
103toText = Native.Text.toText
75
104
76−{-| Set the style of some text.
105+{-| Set the style of some text. For example, if you design a `Style` called
106+`footerStyle` that is specifically for the bottom of your page, you could apply
107+it to text like this:
108+
109+ style footerStyle (toText "the old prince / 2007")
77-}
110-}
78style : Style -> Text -> Text
111style : Style -> Text -> Text
79style = Native.Text.style
112style = Native.Text.style
@@ -82,53 +115,93 @@ style = Native.Text.style
82
115
83 ["helvetica","arial","sans-serif"]
116 ["helvetica","arial","sans-serif"]
84
117
85−Not everyone has access to the same typefaces, so rendering will use the first
118+Not every browser has access to the same typefaces, so rendering will use the
86−typeface in the list that is found on the user's computer. If there are no
119+first typeface in the list that is found on the user's computer. If there are
87−matches, it will use their default typeface. Works the same as the CSS
120+no matches, it will use their default typeface. This works the same as the CSS
88font-family property.
121font-family property.
89-}
122-}
90typeface : [String] -> Text -> Text
123typeface : [String] -> Text -> Text
91typeface = Native.Text.typeface
124typeface = Native.Text.typeface
92
125
93−{-| Switch to a monospace typeface. Good for code snippets. -}
126+{-| Switch to a monospace typeface. Good for code snippets.
127+
128+ monospace (toText "foldl (+) 0 [1,2,3]")
129+-}
94monospace : Text -> Text
130monospace : Text -> Text
95monospace = Native.Text.monospace
131monospace = Native.Text.monospace
96
132
97−{-| Create a link.
133+{-| Create a link by providing a URL and the text of the link:
98
134
99 link "http://elm-lang.org" (toText "Elm Website")
135 link "http://elm-lang.org" (toText "Elm Website")
100-}
136-}
101link : String -> Text -> Text
137link : String -> Text -> Text
102link = Native.Text.link
138link = Native.Text.link
103
139
140+{-| Set the height of some text:
141+
142+ height 40 (toText "Title")
143+-}
104height : Float -> Text -> Text
144height : Float -> Text -> Text
105height = Native.Text.height
145height = Native.Text.height
106
146
147+{-| Set the color of some text:
148+
149+ color red (toText "Red")
150+-}
107color : Color -> Text -> Text
151color : Color -> Text -> Text
108color = Native.Text.color
152color = Native.Text.color
109
153
154+{-| Make text bold:
155+
156+ toText "sometimes you want " ++ bold (toText "emphasis")
157+-}
110bold : Text -> Text
158bold : Text -> Text
111bold = Native.Text.bold
159bold = Native.Text.bold
112
160
161+{-| Make text italic:
162+
163+ toText "make it " ++ italic (toText "important")
164+-}
113italic : Text -> Text
165italic : Text -> Text
114italic = Native.Text.italic
166italic = Native.Text.italic
115
167
168+{-| Put lines on text:
169+
170+ line Under (toText "underlined")
171+ line Over (toText "overlined")
172+ line Through (toText "strike out")
173+-}
116line : Line -> Text -> Text
174line : Line -> Text -> Text
117line = Native.Text.line
175line = Native.Text.line
118
176
177+{-| `Text` is aligned along the left side of the text block. This is sometimes
178+known as *ragged right*.
179+-}
119leftAligned : Text -> Element
180leftAligned : Text -> Element
120leftAligned = Native.Text.leftAligned
181leftAligned = Native.Text.leftAligned
121
182
183+{-| `Text` is aligned along the right side of the text block. This is sometimes
184+known as *ragged left*.
185+-}
122rightAligned : Text -> Element
186rightAligned : Text -> Element
123rightAligned = Native.Text.rightAligned
187rightAligned = Native.Text.rightAligned
124
188
189+{-| `Text` is centered in the text block. There is equal spacing on either side
190+of a line of text.
191+-}
125centered : Text -> Element
192centered : Text -> Element
126centered = Native.Text.centered
193centered = Native.Text.centered
127
194
195+{-| `Text` is aligned along the left and right sides of the text block. Word
196+spacing is adjusted to make this possible.
197+-}
128justified : Text -> Element
198justified : Text -> Element
129justified = Native.Text.justified
199justified = Native.Text.justified
130
200
131−{-| Display a plain string. -}
201+{-| Display a string with no styling:
202+
203+ plainText string = leftAligned (toText string)
204+-}
132plainText : String -> Element
205plainText : String -> Element
133plainText str =
206plainText str =
134 leftAligned (toText str)
207 leftAligned (toText str)
@@ -140,7 +213,7 @@ markdown = Native.Text.markdown
140{-| Convert anything to its textual representation and make it displayable in
213{-| Convert anything to its textual representation and make it displayable in
141the browser:
214the browser:
142
215
143− asText == text . monospace . show
216+ asText value = text (monospace (show value))
144
217
145Excellent for debugging.
218Excellent for debugging.
146-}
219-}
libraries/elm_dependencies.json+4−3
@@ -1,9 +1,9 @@
1−{ "version": "0.11"
1+{ "version": "0.12"
2, "summary": "Elm's standard libraries"
2, "summary": "Elm's standard libraries"
3−, "description": "The full set of standard libraries for Elm. This library is pegged to the version number of the compiler, so if you are using Elm 0.11, you should be using version 0.11 of the standard libraries."
3+, "description": "The full set of standard libraries for Elm. This library is pegged to the version number of the compiler, so if you are using Elm 0.12, you should be using version 0.12 of the standard libraries."
4, "license": "BSD3"
4, "license": "BSD3"
5, "repository": "http://github.com/evancz/Elm.git"
5, "repository": "http://github.com/evancz/Elm.git"
6−, "elm-version": "0.11"
6+, "elm-version": "0.12"
7, "dependencies": {}
7, "dependencies": {}
8, "exposed-modules":
8, "exposed-modules":
9 [ "Basics"
9 [ "Basics"
@@ -18,6 +18,7 @@
18 , "Graphics.Collage"
18 , "Graphics.Collage"
19 , "Graphics.Input"
19 , "Graphics.Input"
20 , "Graphics.WebGL"
20 , "Graphics.WebGL"
21+ , "Graphics.Input.Field"
21 , "Http"
22 , "Http"
22 , "JavaScript"
23 , "JavaScript"
23 , "JavaScript.Experimental"
24 , "JavaScript.Experimental"
runtime/HotSwap.js+2−2
@@ -5,8 +5,8 @@
5// structure.
5// structure.
6ElmRuntime.swap = function(from, to) {
6ElmRuntime.swap = function(from, to) {
7 function similar(nodeOld,nodeNew) {
7 function similar(nodeOld,nodeNew) {
8− idOkay = nodeOld.id === nodeNew.id;
8+ var idOkay = nodeOld.id === nodeNew.id;
9− lengthOkay = nodeOld.kids.length === nodeNew.kids.length;
9+ var lengthOkay = nodeOld.kids.length === nodeNew.kids.length;
10 return idOkay && lengthOkay;
10 return idOkay && lengthOkay;
11 }
11 }
12 function swap(nodeOld,nodeNew) {
12 function swap(nodeOld,nodeNew) {
runtime/Render/Element.js+78−47
@@ -10,15 +10,13 @@ var newElement = Utils.newElement, extract = Utils.extract,
10function setProps(elem, e) {
10function setProps(elem, e) {
11 var props = elem.props;
11 var props = elem.props;
12 var element = elem.element;
12 var element = elem.element;
13− if (element.adjustWidth) {
13+ var width = props.width - (element.adjustWidth || 0);
14− props.width -= element.adjustWidth;
14+ var height = props.height - (element.adjustHeight || 0);
15− }
15+ e.style.width = (width |0) + 'px';
16− if (element.adjustHeight) {
16+ e.style.height = (height|0) + 'px';
17− props.height -= element.adjustHeight;
17+ if (props.opacity !== 1) {
18+ e.style.opacity = props.opacity;
18 }
19 }
19− e.style.width = (props.width |0) + 'px';
20− e.style.height = (props.height|0) + 'px';
21− if (props.opacity !== 1) { e.style.opacity = props.opacity; }
22 if (props.color.ctor === 'Just') {
20 if (props.color.ctor === 'Just') {
23 e.style.backgroundColor = extract(props.color._0);
21 e.style.backgroundColor = extract(props.color._0);
24 }
22 }
@@ -36,35 +34,59 @@ function setProps(elem, e) {
36 e.appendChild(a);
34 e.appendChild(a);
37 }
35 }
38 if (props.hover.ctor !== '_Tuple0') {
36 if (props.hover.ctor !== '_Tuple0') {
39− e.style.pointerEvents = 'auto';
40− e.elm_hover_handler = props.hover;
37+ addHover(e, props.hover);
41− e.elm_hover_count = 0;
42− e.addEventListener('mouseover', function() {
43− if (e.elm_hover_count++ > 0) return;
44− var handler = e.elm_hover_handler;
45− if (handler !== null) {
46− handler(true);
47− }
48− });
49− e.addEventListener('mouseout', function(evt) {
50− if (e.contains(evt.toElement || evt.relatedTarget)) return;
51− e.elm_hover_count = 0;
52− var handler = e.elm_hover_handler;
53− if (handler !== null) {
54− handler(false);
55− }
56− });
57 }
38 }
58 if (props.click.ctor !== '_Tuple0') {
39 if (props.click.ctor !== '_Tuple0') {
59− e.style.pointerEvents = 'auto';
60− e.elm_click_handler = props.click;
40+ addClick(e, props.click);
61− e.addEventListener('click', function() {
62− e.elm_click_handler(Tuple0);
63− });
64 }
41 }
65 return e;
42 return e;
66}
43}
67
44
45+function addClick(e, handler) {
46+ e.style.pointerEvents = 'auto';
47+ e.elm_click_handler = handler;
48+ function trigger() {
49+ e.elm_click_handler(Utils.Tuple0);
50+ }
51+ e.elm_click_trigger = trigger;
52+ e.addEventListener('click', trigger);
53+}
54+
55+function removeClick(e, handler) {
56+ if (e.elm_click_trigger) {
57+ e.removeEventListener('click', e.elm_click_trigger);
58+ }
59+}
60+
61+function addHover(e, handler) {
62+ e.style.pointerEvents = 'auto';
63+ e.elm_hover_handler = handler;
64+ e.elm_hover_count = 0;
65+
66+ function over() {
67+ if (e.elm_hover_count++ > 0) return;
68+ e.elm_hover_handler(true);
69+ }
70+ function out(evt) {
71+ if (e.contains(evt.toElement || evt.relatedTarget)) return;
72+ e.elm_hover_count = 0;
73+ e.elm_hover_handler(false);
74+ }
75+ e.elm_hover_over = over;
76+ e.elm_hover_out = out;
77+ e.addEventListener('mouseover', over);
78+ e.addEventListener('mouseout', out);
79+}
80+
81+function removeHover(e) {
82+ if (e.elm_hover_over) {
83+ e.removeEventListener('mouseover', e.elm_hover_over);
84+ }
85+ if (e.elm_hover_out) {
86+ e.removeEventListener('mouseout', e.elm_hover_out);
87+ }
88+}
89+
68function image(props, img) {
90function image(props, img) {
69 switch (img._0.ctor) {
91 switch (img._0.ctor) {
70 case 'Plain': return plainImage(img._3);
92 case 'Plain': return plainImage(img._3);
@@ -151,7 +173,12 @@ function toPos(pos) {
151
173
152// must clear right, left, top, bottom, and transform
174// must clear right, left, top, bottom, and transform
153// before calling this function
175// before calling this function
154−function setPos(pos,w,h,e) {
176+function setPos(pos,elem,e) {
177+ var element = elem.element;
178+ var props = elem.props;
179+ var w = props.width + (element.adjustWidth ? element.adjustWidth : 0);
180+ var h = props.height + (element.adjustHeight ? element.adjustHeight : 0);
181+
155 e.style.position = 'absolute';
182 e.style.position = 'absolute';
156 e.style.margin = 'auto';
183 e.style.margin = 'auto';
157 var transform = '';
184 var transform = '';
@@ -171,7 +198,7 @@ function setPos(pos,w,h,e) {
171
198
172function container(pos,elem) {
199function container(pos,elem) {
173 var e = render(elem);
200 var e = render(elem);
174− setPos(pos, elem.props.width, elem.props.height, e);
201+ setPos(pos, elem, e);
175 var div = newElement('div');
202 var div = newElement('div');
176 div.style.position = 'relative';
203 div.style.position = 'relative';
177 div.style.overflow = 'hidden';
204 div.style.overflow = 'hidden';
@@ -302,7 +329,7 @@ function update(node, curr, next) {
302 break;
329 break;
303 case "Container":
330 case "Container":
304 update(node.firstChild, currE._1, nextE._1);
331 update(node.firstChild, currE._1, nextE._1);
305− setPos(nextE._0, nextE._1.props.width, nextE._1.props.height, node.firstChild);
332+ setPos(nextE._0, nextE._1, node.firstChild);
306 break;
333 break;
307 case "Custom":
334 case "Custom":
308 if (currE.type === nextE.type) {
335 if (currE.type === nextE.type) {
@@ -320,15 +347,15 @@ function updateProps(node, curr, next) {
320 var currP = curr.props;
347 var currP = curr.props;
321 var e = node;
348 var e = node;
322 var element = next.element;
349 var element = next.element;
323− if (element.adjustWidth) {
350+ var width = props.width - (element.adjustWidth || 0);
324− props.width -= element.adjustWidth;
351+ var height = props.height - (element.adjustHeight || 0);
352+ if (width !== currP.width) {
353+ e.style.width = (width|0) + 'px';
325 }
354 }
326− if (element.adjustHeight) {
355+ if (height !== currP.height) {
327− props.height -= element.adjustHeight;
356+ e.style.height = (height|0) + 'px';
328 }
357 }
329− if (props.width !== currP.width) e.style.width = (props.width |0) + 'px';
330− if (props.height !== currP.height) e.style.height = (props.height|0) + 'px';
331− if (props.opacity !== 1 && props.opacity !== currP.opacity) {
358+ if (props.opacity !== currP.opacity) {
332 e.style.opacity = props.opacity;
359 e.style.opacity = props.opacity;
333 }
360 }
334 var nextColor = (props.color.ctor === 'Just' ?
361 var nextColor = (props.color.ctor === 'Just' ?
@@ -355,17 +382,21 @@ function updateProps(node, curr, next) {
355 }
382 }
356
383
357 // update hover handlers
384 // update hover handlers
358− if (props.hover.ctor !== '_Tuple0') {
385+ if (props.hover.ctor === '_Tuple0') {
359− e.elm_hover_handler = props.hover;
386+ removeHover(e);
360 } else if (e.elm_hover_handler) {
387 } else if (e.elm_hover_handler) {
361− e.elm_hover_handler = null;
388+ e.elm_hover_handler = props.hover;
389+ } else {
390+ addHover(e, props.hover);
362 }
391 }
363
392
364 // update click handlers
393 // update click handlers
365− if (props.click.ctor !== '_Tuple0') {
394+ if (props.click.ctor === '_Tuple0') {
366− e.elm_click_handler = props.click;
395+ removeClick(e);
367 } else if (e.elm_click_handler) {
396 } else if (e.elm_click_handler) {
368− e.elm_click_handler = null;
397+ e.elm_click_handler = props.click;
398+ } else {
399+ addClick(e, props.click);
369 }
400 }
370}
401}
371
402
server/LICENSE+1−1
@@ -1,4 +1,4 @@
1−Copyright (c)2012-2013, Evan Czaplicki
1+Copyright (c)2012-2014, Evan Czaplicki
2
2
3All rights reserved.
3All rights reserved.
4
4
server/Server.hs+112−99
@@ -1,114 +1,127 @@
1+{-# OPTIONS_GHC -Wall #-}
2+{-# LANGUAGE OverloadedStrings, DeriveDataTypeable #-}
1module Main where
3module Main where
2
4
3−import Control.Monad (msum,guard,when)
5+import Control.Applicative ((<$>),(<|>))
6+import Control.Monad (guard)
4import Control.Monad.Trans (MonadIO(liftIO))
7import Control.Monad.Trans (MonadIO(liftIO))
5−import Data.List (isPrefixOf, isSuffixOf, (\\))
8+import qualified Data.ByteString as BS
6−import Data.Version (showVersion)
9+import qualified Data.ByteString.Char8 as BSC
7−import Happstack.Server
10+import qualified Data.HashMap.Strict as Map
8−import Happstack.Server.Compression
11+import qualified Data.Version as Version
12+import System.Console.CmdArgs
9import System.Directory
13import System.Directory
10−import System.Environment
11import System.Exit
14import System.Exit
12import System.FilePath
15import System.FilePath
13import System.Process
16import System.Process
14−import GHC.IO.Handle
17+import System.IO (hGetContents, Handle)
18+
19+import Paths_elm_server (version)
15−import qualified Elm.Internal.Paths as ElmPaths
20+import qualified Elm.Internal.Paths as Elm
16−import Paths_elm_server
21+import Snap.Core
17−
22+import Snap.Http.Server
18−runtime = "/elm-runtime.js"
23+import Snap.Util.FileServe
19−
24+
20−serve :: Int -> String -> IO ()
25+data Flags = Flags
21−serve portNumber libLoc = do
26+ { port :: Int
27+ , runtime :: Maybe FilePath
28+ } deriving (Data,Typeable,Show,Eq)
29+
30+flags :: Flags
31+flags = Flags
32+ { port = 8000 &= help "set the port of the server"
33+ , runtime = Nothing &= typFile
34+ &= help "Specify a custom location for Elm's runtime system."
35+ } &= help "Quickly reload Elm projects in your browser. Just refresh to recompile.\n\
36+ \It serves static files and freshly recompiled Elm files."
37+ &= helpArg [explicit, name "help", name "h"]
38+ &= versionArg [ explicit, name "version", name "v"
39+ , summary (Version.showVersion version)
40+ ]
41+ &= summary ("Elm Server " ++ Version.showVersion version ++
42+ ", (c) Evan Czaplicki 2011-2014")
43+
44+
45+config :: Config Snap a
46+config = setAccessLog ConfigNoLog (setErrorLog ConfigNoLog defaultConfig)
47+
48+-- | Set up the server.
49+main :: IO ()
50+main = do
51+ cargs <- cmdArgs flags
22− putStrLn $ "Elm Server " ++ showVersion version ++
52+ putStrLn $ "Elm Server " ++ Version.showVersion version ++
23− ": running at <http://localhost:" ++ show portNumber ++ ">"
24− putStrLn "Just refresh a page to recompile it!"
53+ ": Just refresh a page to recompile it!"
25− simpleHTTP httpConf $ do
54+ httpServe (setPort (port cargs) config) $
26− _ <- compressedResponseFilter
55+ serveRuntime (maybe Elm.runtime id (runtime cargs))
27− msum [ uriRest serveElm
56+ <|> serveElm
28− , uriRest (serveLib libLoc)
57+ <|> serveDirectoryWith directoryConfig "."
29− , serveDirectory EnableBrowsing [] "."
58+
30− ]
59+directoryConfig :: MonadSnap m => DirectoryConfig m
31− where httpConf = nullConf { port = portNumber }
60+directoryConfig =
32−
61+ fancyDirectoryConfig
33−pageTitle :: String -> String
62+ { indexGenerator = defaultIndexGenerator defaultMimeTypes indexStyle
34−pageTitle = dropExtension . takeBaseName
63+ , mimeTypes = Map.insert ".elm" "text/html" defaultMimeTypes
35−
64+ }
36−serveElm :: FilePath -> ServerPartT IO Response
65+
66+indexStyle :: BS.ByteString
67+indexStyle =
68+ "body { margin:0; font-family:sans-serif; background:rgb(245,245,245);\
69+ \ font-family: calibri, verdana, helvetica, arial; }\
70+ \div.header { padding: 40px 50px; font-size: 24px; }\
71+ \div.content { padding: 0 40px }\
72+ \div.footer { display:none; }\
73+ \table { width:100%; border-collapse:collapse; }\
74+ \td { padding: 6px 10px; }\
75+ \tr:nth-child(odd) { background:rgb(216,221,225); }\
76+ \td { font-family:monospace }\
77+ \th { background:rgb(90,99,120); color:white; text-align:left;\
78+ \ padding:10px; font-weight:normal; }"
79+
80+runtimeName :: String
81+runtimeName = "elm-runtime.js"
82+
83+serveRuntime :: FilePath -> Snap ()
84+serveRuntime runtimePath =
85+ do file <- BSC.unpack . rqPathInfo <$> getRequest
86+ guard (file == runtimeName)
87+ serveFileAs "application/javascript" runtimePath
88+
37−serveElm fp =
89+serveElm :: Snap ()
90+serveElm =
91+ do file <- BSC.unpack . rqPathInfo <$> getRequest
38− do fileExists <- liftIO $ doesFileExist file
92+ exists <- liftIO $ doesFileExist file
39− guard (fileExists && takeExtension fp == ".elm")
93+ guard (exists && takeExtension file == ".elm")
40− onSuccess compile serve
94+ onSuccess (compile file) (serve file)
41 where
95 where
42− file = tail fp
96+ compile file =
97+ let elmArgs = [ "--make", "--runtime=" ++ runtimeName, file ]
98+ in createProcess $ (proc "elm" elmArgs) { std_out = CreatePipe }
43
99
44− compile = liftIO $ createProcess $ (proc "elm" args) { std_out = CreatePipe }
100+ serve file =
45− where args = [ "--make", "--runtime=" ++ runtime, file ]
101+ serveFileAs "text/html; charset=UTF-8" ("build" </> replaceExtension file "html")
46
102
47− serve = serveFile (asContentType "text/html")
103+failure :: String -> Snap ()
48− ("build" </> replaceExtension file "html")
104+failure msg =
105+ do modifyResponse $ setResponseStatus 404 "Not found"
106+ writeBS $ BSC.pack msg
49
107
108+onSuccess :: IO (t, Maybe Handle, t1, ProcessHandle) -> Snap () -> Snap ()
50−onSuccess action success = do
109+onSuccess action success =
51− (_, stdout, _, handle) <- action
110+ do (_, stdout, _, handle) <- liftIO action
52− exitCode <- liftIO $ waitForProcess handle
111+ exitCode <- liftIO $ waitForProcess handle
53− case (exitCode, stdout) of
112+ case (exitCode, stdout) of
54− (ExitFailure 127, _) ->
113+ (ExitFailure 127, _) ->
55− badRequest $ toResponse "Error: elm binary not found in your path."
114+ failure "Error: elm compiler not found in your path."
56− (ExitFailure _, Just out) ->
57− do str <- liftIO $ hGetContents out
58− badRequest $ toResponse str
59− (ExitFailure _, Nothing) ->
60− badRequest $ toResponse "See command line for error message."
61− (ExitSuccess, _) -> success
62
115
116+ (ExitFailure _, Just out) ->
117+ failure =<< liftIO (hGetContents out)
63
118
64−serveLib :: FilePath -> String -> ServerPartT IO Response
119+ (ExitFailure _, Nothing) ->
65−serveLib libLoc fp = do
120+ failure "See command line for error message."
66− guard (fp == runtime)
67− serveFile (asContentType "application/javascript") libLoc
68
121
69−main :: IO ()
122+ (ExitSuccess, _) -> success
70−main = getArgs >>= parse
71−
72−parse :: [String] -> IO ()
73−parse ("--help":_) = putStrLn usage
74−parse ("--version":_) = putStrLn ("The Elm Server " ++ showVersion version)
75−parse args =
76− if null remainingArgs then
77− serve portNumber elmRuntime
78− else
79− putStrLn usageMini
80
123
81− where
124+{--
82− runtimeArg = filter (isPrefixOf "--runtime-location=") args
125+pageTitle :: String -> String
83− portArg = filter (isPrefixOf "--port=") args
126+pageTitle = dropExtension . takeBaseName
84− remainingArgs = (args \\ runtimeArg) \\ portArg
127+--}
85−
86− argValue arg = tail $ dropWhile (/= '=') (head arg)
87− portNumber = if null portArg then 8000 else read (argValue portArg) :: Int
88− elmRuntime = if null runtimeArg then
89− ElmPaths.runtime
90− else
91− argValue runtimeArg
92−
93−usageMini :: String
94−usageMini =
95− "Usage: elm-server [OPTIONS]\n\
96− \Try `elm-server --help' for more information."
97−
98−usage :: String
99−usage =
100− "Usage: elm-server [OPTIONS]\n\
101− \Compiles and serves .elm files from the current directory.\n\
102− \Example: elm-server\n\
103− \\n\
104− \Server configuration:\n\
105− \ --port set the port to listen on (default: 8000)\n\
106− \\n\
107− \Resource Locations:\n\
108− \ --runtime-location set the location of the Elm runtime\n\
109− \\n\
110− \Compiler Information:\n\
111− \ --version print the version information and exit\n\
112− \ --help display this help and exit\n\
113− \\n\
114− \Elm home page: <http://elm-lang.org>"
server/elm-server.cabal+14−13
@@ -1,7 +1,9 @@
1Name: elm-server
1Name: elm-server
2−Version: 0.10.1
2+Version: 0.12
3−Synopsis: The Elm language server.
3+Synopsis: Server for developing Elm projects
4−Description: This package provides a standalone, Happstack-based Elm server.
4+Description: Provides a standalone Snap server that serves static files.
5+ For Elm files, it recompiles them and serves them as HTML,
6+ so you can just refresh to see the new version.
5
7
6Homepage: http://elm-lang.org
8Homepage: http://elm-lang.org
7
9
@@ -10,7 +12,7 @@ License-file: LICENSE
10
12
11Author: Evan Czaplicki
13Author: Evan Czaplicki
12Maintainer: info@elm-lang.org
14Maintainer: info@elm-lang.org
13−Copyright: Copyright: (c) 2011-2013 Evan Czaplicki
15+Copyright: Copyright: (c) 2011-2014 Evan Czaplicki
14
16
15Category: Compiler, Language
17Category: Compiler, Language
16
18
@@ -26,15 +28,14 @@ source-repository head
26Executable elm-server
28Executable elm-server
27 Main-is: Server.hs
29 Main-is: Server.hs
28 Build-depends: base >=4.2 && <5,
30 Build-depends: base >=4.2 && <5,
31+ bytestring,
32+ cmdargs,
29 containers >= 0.3,
33 containers >= 0.3,
30 directory,
34 directory,
31− transformers >= 0.2,
32− mtl >= 2,
33− parsec >= 3.1.1,
34− blaze-html >= 0.5.1,
35− HTTP >= 4000,
36− happstack-server,
37− deepseq,
38 filepath,
35 filepath,
39− Elm >= 0.10.1,
36+ Elm >= 0.12,
37+ snap-core,
38+ snap-server,
39+ mtl,
40− process
40+ process,
41+ unordered-containers