on master help sign in
Merge remote-tracking branch 'evan/dev' into webgl
commitfde18d6fe816fd0af2a0490c4b77198189a9fa63 authorJohn P Mayer Jr <john.p.mayer.jr@gmail.com> dateWed 5 Mar 2014, 22:15 (13 years ago) parent899c1903cd940f
14 files changed+408−187
compiler/Metadata/Prelude.hs+4−4 libraries/Dict.elm+1−2 libraries/Graphics/Input.elm+4−57 libraries/Graphics/Input/Field.elm+130 libraries/Native/Color.js+9−2 libraries/Native/Graphics/Input.js+71−14 libraries/Native/String.js+3−2 libraries/Native/Text.js+58−42 libraries/Native/Utils.js−7 libraries/Prelude.elm−8 libraries/String.elm+28−5 libraries/Text.elm+79−40 runtime/Init.js+1−1 runtime/Render/Element.js+20−3
compiler/Metadata/Prelude.hs+4−4
@@ -20,12 +20,12 @@ add noPrelude (Module name exs ims decls) = Module name exs (customIms ++ ims) d
2020 Just _ -> []
2121
2222prelude :: [(String, ImportMethod)]
23−prelude = string : text ++ map (\n -> (n, Hiding [])) modules
23+prelude = string ++ text ++ map (\n -> (n, Hiding [])) modules
2424 where
2525 text = map ((,) "Text") [ As "Text", Hiding ["link", "color", "height"] ]
26− string = ("String", As "String")
27− modules = [ "Basics", "Signal", "List", "Maybe", "Time", "Prelude"
28− , "Graphics.Element", "Color", "Graphics.Collage", "Native.Ports" ]
26+ string = map ((,) "String") [ As "String", Importing ["show"] ]
27+ modules = [ "Basics", "Signal", "List", "Maybe", "Time", "Color"
28+ , "Graphics.Element", "Graphics.Collage", "Native.Ports" ]
2929
3030interfaces :: Bool -> IO Interfaces
3131interfaces noPrelude =
libraries/Dict.elm+1−2
@@ -35,7 +35,6 @@ import Basics (..)
3535import Maybe (..)
3636import Native.Error
3737import List
38−import String
3938import Native.Utils
4039
4140-- BBlack and NBlack should only be used during the deletion
@@ -197,7 +196,7 @@ lessBlackTree t = case t of
197196
198197reportRemBug : String -> NColor -> String -> String -> a
199198reportRemBug msg c lgot rgot =
200− Native.Error.raise . String.concat <| [
199+ Native.Error.raise <| List.concat [
201200 "Internal red-black tree invariant violated, expected ",
202201 msg,
203202 "and got",
libraries/Graphics/Input.elm+4−57
@@ -19,14 +19,15 @@ examples in this library, so just read on to get a better idea of how it works!
1919@docs Input, input
2020
2121# Basic Input Elements
22−Text fields come later.
22+
23+To learn about text fields, see the
24+[`Graphics.Input.Field`](Graphics-Input-Field) library.
25+
2326@docs button, customButton, checkbox, dropDown
2427
2528# Clicks and Hovers
2629@docs clickable, hoverable
2730
28−# Text Fields
29−@docs field, password, email, noContent, FieldContent, Selection, Direction
3031-}
3132
3233import Signal (Signal)
@@ -175,57 +176,3 @@ distinguished with IDs or more complex data structures.
175176-}
176177clickable : Handle a -> a -> Element -> Element
177178clickable = Native.Graphics.Input.clickable
178−
179−{-| Represents the current content of a text field. For example:
180−
181− FieldContent "She sells sea shells" (Selection 0 3 Backward)
182−
183−This means the user highlighted the substring `"She"` backwards.
184−-}
185−type FieldContent = { string:String, selection:Selection }
186−
187−{-| The selection within a text field. `start` is never greater than `end`:
188−
189− Selection 0 0 Forward -- cursor precedes all characters
190−
191− Selection 5 9 Backward -- highlighting characters starting after
192− -- the 5th and ending after the 9th
193−-}
194−type Selection = { start:Int, end:Int, direction:Direction }
195−
196−{-| The direction of selection.-}
197−data Direction = Forward | Backward
198−
199−{-| A field with no content:
200−
201− FieldContent "" (Selection 0 0 Forward)
202−-}
203−noContent : FieldContent
204−noContent = FieldContent "" (Selection 0 0 Forward)
205−
206−{-| Create a text field. The following example creates a time-varying element
207−called `nameField`. As the user types their name, the field will be updated
208−to match what they have entered.
209−
210− name : Input FieldContent
211− name = input noContent
212−
213− nameField : Signal Element
214− nameField = field name.handle id "Name" <~ name.signal
215−-}
216−field : Handle a -> (FieldContent -> a) -> String -> FieldContent -> Element
217−field = Native.Graphics.Input.field
218−
219−{-| Same as `field` but the UI element blocks out each characters. -}
220−password : Handle a -> (FieldContent -> a) -> String -> FieldContent -> Element
221−password = Native.Graphics.Input.password
222−
223−{-| Same as `field` but it adds an annotation that this field is for email
224−addresses. This is helpful for auto-complete and for mobile users who may
225−get a custom keyboard with an `@` and `.com` button.
226−-}
227−email : Handle a -> (FieldContent -> a) -> String -> FieldContent -> Element
228−email = Native.Graphics.Input.email
229−
230−-- area : Handle a -> (FieldContent -> a) -> Handle b -> ((Int,Int) -> b) -> (Int,Int) -> String -> FieldContent -> Element
231−-- area = Native.Graphics.Input.area
libraries/Graphics/Input/Field.elmnew file+130
@@ -0,0 +1,130 @@
1+module Graphics.Input.Field where
2+{-| This library specifically addresses text fields. It uses the same general
3+approach as the [`Graphics.Input`](Graphics-Input) module for describing an
4+`Input`, so this library focuses on creating and styling text fields.
5+
6+# Create Fields
7+@docs field, password, email
8+
9+# Field Content
10+@docs Content, Selection, Direction, noContent
11+
12+# Field Style
13+@docs Style, Outline, noOutline, Highlight, noHighlight, Dimensions, uniformly
14+-}
15+
16+import Color (Color)
17+import Color
18+import Graphics.Element (Element)
19+import Graphics.Input (Input, Handle)
20+import Native.Graphics.Input
21+import Text
22+
23+{-| Easily create uniform dimensions:
24+
25+ uniformly 4 == { left=4, right=4, top=4, bottom=4 }
26+-}
27+uniformly : Int -> Dimensions
28+uniformly n = Dimensions n n n n
29+
30+{-| For setting dimensions of a fields padding or border. The left, right, top,
31+and bottom may all have different sizes.
32+-}
33+type Dimensions = { left:Int, right:Int, top:Int, bottom:Int }
34+
35+{-| A field can have a outline around it. This lets you set its color, width,
36+and radius. The radius allows you to round the corners of your field. Set the
37+width to zero to make it invisible.
38+-}
39+type Outline = { color:Color, width:Dimensions, radius:Int }
40+
41+{-| An outline with zero width, so you cannot see it. -}
42+noOutline : Outline
43+noOutline = Outline Color.grey (uniformly 0) 0
44+
45+{-| When a field is selected, it has an highlight around it by default. Set the
46+width of the `Highlight` to zero to make it go away.
47+-}
48+type Highlight = { color:Color, width:Int }
49+
50+{-| An highlight with zero width, so you cannot see it. -}
51+noHighlight : Highlight
52+noHighlight = Highlight Color.blue 0
53+
54+{-| Describes the style of a text box. The `style` field describes the style
55+of the text itself. The `outline` field describes the glowing blue outline that
56+shows up when the field has focus. Turn off `outline` by setting its width to
57+zero. The
58+-}
59+type Style =
60+ { padding : Dimensions
61+ , outline : Outline
62+ , highlight : Highlight
63+ , style : Text.Style
64+ }
65+
66+{-| The default style for a text field. The outline is `Color.grey` with width
67+1 and radius 2. The highlight is `Color.blue` with width 1, and the default
68+text color is black.
69+-}
70+defaultStyle : Style
71+defaultStyle =
72+ { padding = uniformly 4
73+ , outline = Outline Color.grey (uniformly 1) 2
74+ , highlight = Highlight Color.blue 1
75+ , style = Text.defaultStyle
76+ }
77+
78+{-| Represents the current content of a text field. For example:
79+
80+ Content "She sells sea shells" (Selection 0 3 Backward)
81+
82+This means the user highlighted the substring `"She"` backwards.
83+-}
84+type Content = { string:String, selection:Selection }
85+
86+{-| The selection within a text field. `start` is never greater than `end`:
87+
88+ Selection 0 0 Forward -- cursor precedes all characters
89+
90+ Selection 5 9 Backward -- highlighting characters starting after
91+ -- the 5th and ending after the 9th
92+-}
93+type Selection = { start:Int, end:Int, direction:Direction }
94+
95+{-| The direction of selection.-}
96+data Direction = Forward | Backward
97+
98+{-| A field with no content:
99+
100+ Content "" (Selection 0 0 Forward)
101+-}
102+noContent : Content
103+noContent = Content "" (Selection 0 0 Forward)
104+
105+{-| Create a text field. The following example creates a time-varying element
106+called `nameField`. As the user types their name, the field will be updated
107+to match what they have entered.
108+
109+ name : Input Content
110+ name = input noContent
111+
112+ nameField : Signal Element
113+ nameField = field name.handle id defaultStyle "Name" <~ name.signal
114+-}
115+field : Handle a -> (Content -> a) -> Style -> String -> Content -> Element
116+field = Native.Graphics.Input.field
117+
118+{-| Same as `field` but the UI element blocks out each characters. -}
119+password : Handle a -> (Content -> a) -> Style -> String -> Content -> Element
120+password = Native.Graphics.Input.password
121+
122+{-| Same as `field` but it adds an annotation that this field is for email
123+addresses. This is helpful for auto-complete and for mobile users who may
124+get a custom keyboard with an `@` and `.com` button.
125+-}
126+email : Handle a -> (Content -> a) -> Style -> String -> Content -> Element
127+email = Native.Graphics.Input.email
128+
129+-- area : Handle a -> (Content -> a) -> Handle b -> ((Int,Int) -> b) -> (Int,Int) -> String -> Content -> Element
130+-- area = Native.Graphics.Input.area
libraries/Native/Color.js+9−2
@@ -6,6 +6,12 @@ Elm.Native.Color.make = function(elm) {
66
77 var Utils = Elm.Native.Utils.make(elm);
88
9+ function toCss(c) {
10+ return (c._3 === 1)
11+ ? ('rgb(' + c._0 + ', ' + c._1 + ', ' + c._2 + ')')
12+ : ('rgba(' + c._0 + ', ' + c._1 + ', ' + c._2 + ', ' + c._3 + ')');
13+ }
14+
915 function complement(rgb) {
1016 var hsv = toHSV(rgb);
1117 hsv.hue = (hsv.hue + 180) % 360;
@@ -63,7 +69,8 @@ Elm.Native.Color.make = function(elm) {
6369 return elm.Native.Color.values = {
6470 hsva:F4(hsva),
6571 hsv:F3(hsv),
66− complement:complement
72+ complement:complement,
73+ toCss:toCss
6774 };
6875
69−};
76+};
libraries/Native/Graphics/Input.js+71−14
@@ -8,6 +8,8 @@ Elm.Native.Graphics.Input.make = function(elm) {
88 var Render = ElmRuntime.use(ElmRuntime.Render.Element);
99 var newNode = ElmRuntime.use(ElmRuntime.Render.Utils).newElement;
1010
11+ var toCss = Elm.Native.Color.make(elm).toCss;
12+ var Text = Elm.Native.Text.make(elm);
1113 var Signal = Elm.Signal.make(elm);
1214 var newElement = Elm.Graphics.Element.make(elm).newElement;
1315 var JS = Elm.Native.JavaScript.make(elm);
@@ -78,7 +80,7 @@ Elm.Native.Graphics.Input.make = function(elm) {
7880
7981 function updateButton(node, oldModel, newModel) {
8082 node.elm_signal = newModel.signal;
81− node.elm_value = nemModel.value;
83+ node.elm_value = newModel.value;
8284 var txt = newModel.text;
8385 if (oldModel.text !== txt) node.innerHTML = txt;
8486 }
@@ -215,19 +217,57 @@ Elm.Native.Graphics.Input.make = function(elm) {
215217 }
216218 }
217219
220+ function updateIfNeeded(css, attribute, latestAttribute) {
221+ if (css[attribute] !== latestAttribute) {
222+ css[attribute] = latestAttribute;
223+ }
224+ }
225+ function cssDimensions(dimensions) {
226+ return dimensions.top + 'px ' +
227+ dimensions.right + 'px ' +
228+ dimensions.bottom + 'px ' +
229+ dimensions.left + 'px';
230+ }
231+ function updateFieldStyle(css, style) {
232+ updateIfNeeded(css, 'padding', cssDimensions(style.padding));
233+
234+ var outline = style.outline;
235+ updateIfNeeded(css, 'border-width', cssDimensions(outline.width));
236+ updateIfNeeded(css, 'border-color', toCss(outline.color));
237+ updateIfNeeded(css, 'border-radius', outline.radius + 'px');
238+
239+ var highlight = style.highlight;
240+ if (highlight.width === 0) {
241+ css.outline = 'none';
242+ } else {
243+ updateIfNeeded(css, 'outline-width', highlight.width + 'px');
244+ updateIfNeeded(css, 'outline-color', toCss(highlight.color));
245+ }
246+
247+ var textStyle = style.style;
248+ updateIfNeeded(css, 'color', toCss(textStyle.color));
249+ if (textStyle.typeface.ctor !== '[]') {
250+ updateIfNeeded(css, 'font-family', Text.toTypefaces(textStyle.typeface));
251+ }
252+ if (textStyle.height.ctor !== "Nothing") {
253+ updateIfNeeded(css, 'font-size', textStyle.height._0 + 'px');
254+ }
255+ updateIfNeeded(css, 'font-weight', textStyle.bold ? 'bold' : 'normal');
256+ updateIfNeeded(css, 'font-style', textStyle.italic ? 'italic' : 'normal');
257+ if (textStyle.line.ctor !== 'Nothing') {
258+ updateIfNeeded(css, 'text-decoration', Text.toLine(textStyle.line._0));
259+ }
260+ }
261+
218262 function renderField(model) {
219263 var field = newNode('input');
220− field.style.border = 'none';
221− field.style.outline = 'none';
222− field.style.backgroundColor = 'transparent';
264+ updateFieldStyle(field.style, model.style);
265+ field.style.borderStyle = 'solid';
223266 field.style.pointerEvents = 'auto';
224267
225268 field.type = model.type;
226269 field.placeholder = JS.fromString(model.placeHolder);
227270 field.value = JS.fromString(model.content.string);
228− var selection = model.content.selection;
229− var direction = selection.direction.ctor === 'Forward' ? 'forward' : 'backward';
230− setRange(field, selection.start, selection.end, direction);
231271
232272 field.elm_signal = model.signal;
233273 field.elm_handler = model.handler;
@@ -297,11 +337,20 @@ Elm.Native.Graphics.Input.make = function(elm) {
297337 field.addEventListener('keypress', keyUpdate);
298338 field.addEventListener('input', inputUpdate);
299339 field.addEventListener('mousedown', mousedown);
340+ field.addEventListener('focus', function() {
341+ field.elm_hasFocus = true;
342+ });
343+ field.addEventListener('blur', function() {
344+ field.elm_hasFocus = false;
345+ });
300346
301347 return field;
302348 }
303349
304350 function updateField(field, oldModel, newModel) {
351+ if (oldModel.style !== newModel.style) {
352+ updateFieldStyle(field.style, newModel.style);
353+ }
305354 field.elm_signal = newModel.signal;
306355 field.elm_handler = newModel.handler;
307356
@@ -310,16 +359,24 @@ Elm.Native.Graphics.Input.make = function(elm) {
310359 var value = JS.fromString(newModel.content.string);
311360 field.value = value;
312361 field.elm_old_value = value;
313− var selection = newModel.content.selection;
314− var direction = selection.direction.ctor === 'Forward' ? 'forward' : 'backward';
315− setRange(field, selection.start, selection.end, direction);
362+ if (field.elm_hasFocus) {
363+ var selection = newModel.content.selection;
364+ var direction = selection.direction.ctor === 'Forward' ? 'forward' : 'backward';
365+ setRange(field, selection.start, selection.end, direction);
366+ }
316367 }
317368
318369 function mkField(type) {
319− function field(signal, handler, placeHolder, content) {
370+ function field(signal, handler, style, placeHolder, content) {
371+ var padding = style.padding;
372+ var outline = style.outline.width;
373+ var adjustWidth = padding.left + padding.right + outline.left + outline.right;
374+ var adjustHeight = padding.top + padding.bottom + outline.top + outline.bottom;
320375 return A3(newElement, 200, 30, {
321376 ctor: 'Custom',
322− type: type + 'Input',
377+ type: type + 'Field',
378+ adjustWidth: adjustWidth,
379+ adjustHeight: adjustHeight,
323380 render: renderField,
324381 update: updateField,
325382 model: {
@@ -327,14 +384,14 @@ Elm.Native.Graphics.Input.make = function(elm) {
327384 handler:handler,
328385 placeHolder:placeHolder,
329386 content:content,
387+ style:style,
330388 type:type
331389 }
332390 });
333391 }
334− return F4(field);
392+ return F5(field);
335393 }
336394
337−
338395 function hoverable(signal, handler, elem) {
339396 function onHover(bool) {
340397 elm.notify(signal.id, handler(bool));
libraries/Native/String.js+3−2
@@ -144,7 +144,8 @@ Elm.Native.String.make = function(elm) {
144144 return str.indexOf(sub) === 0;
145145 }
146146 function endsWith(sub, str) {
147− return str.lastIndexOf(sub) === str.length - sub.length;
147+ return str.length >= sub.length &&
148+ str.lastIndexOf(sub) === str.length - sub.length;
148149 }
149150 function indexes(sub, str) {
150151 var subLen = sub.length;
@@ -248,4 +249,4 @@ Elm.Native.String.make = function(elm) {
248249 toList: toList,
249250 fromList: fromList,
250251 };
251−};
252+};
libraries/Native/Text.js+58−42
@@ -4,11 +4,10 @@ Elm.Native.Text.make = function(elm) {
44 elm.Native.Text = elm.Native.Text || {};
55 if (elm.Native.Text.values) return elm.Native.Text.values;
66
7− var JS = Elm.JavaScript.make(elm);
8− var Utils = Elm.Native.Utils.make(elm);
9− var Color = Elm.Native.Color.make(elm);
7+ var toCss = Elm.Native.Color.make(elm).toCss;
108 var Element = Elm.Graphics.Element.make(elm);
11− var show = Elm.Native.Show.make(elm).show;
9+ var List = Elm.Native.List.make(elm);
10+ var Utils = Elm.Native.Utils.make(elm);
1211
1312 function makeSpaces(s) {
1413 if (s.length == 0) { return s; }
@@ -51,13 +50,51 @@ Elm.Native.Text.make = function(elm) {
5150 return arr.join('<br/>');
5251 }
5352
54− function toText(str) { return Utils.txt(properEscape(JS.fromString(str))); }
53+ function toText(str) { return Utils.txt(properEscape(str)); }
54+
55+ // conversions from Elm values to CSS
56+ function toTypefaces(list) {
57+ var typefaces = List.toArray(list);
58+ for (var i = typefaces.length; i--; ) {
59+ var typeface = typefaces[i];
60+ if (typeface.contains(' ')) {
61+ typefaces[i] = "'" + typeface + "'";
62+ }
63+ }
64+ return typefaces.join(',');
65+ }
66+ function toLine(line) {
67+ var ctor = line.ctor;
68+ return ctor === 'Under' ? 'underline' :
69+ ctor === 'Over' ? 'overline' : 'line-through';
70+ }
5571
72+ // setting styles of Text
73+ function style(style, text) {
74+ var newText = '<span style="color:' + toCss(style.color) + ';'
75+ if (style.typeface.ctor !== '[]') {
76+ newText += 'font-family:' + toTypefaces(style.typeface) + ';'
77+ }
78+ if (style.height.ctor !== "Nothing") {
79+ newText += 'font-size:' + style.height._0 + 'px;';
80+ }
81+ if (style.bold) {
82+ newText += 'font-weight:bold;';
83+ }
84+ if (style.italic) {
85+ newText += 'font-style:italic;';
86+ }
87+ if (style.line.ctor !== 'Nothing') {
88+ newText += 'text-decoration:' + toLine(style.line._0) + ';';
89+ }
90+ newText += '">' + Utils.makeText(text) + '</span>'
91+ return Utils.txt(newText);
92+ }
5693 function height(px, text) {
5794 return { style: 'font-size:' + px + 'px;', text:text }
5895 }
59− function typeface(name, text) {
60− return { style: 'font-family:' + name + ';', text:text }
96+ function typeface(names, text) {
97+ return { style: 'font-family:' + toTypefaces(names) + ';', text:text }
6198 }
6299 function monospace(text) {
63100 return { style: 'font-family:monospace;', text:text }
@@ -71,25 +108,16 @@ Elm.Native.Text.make = function(elm) {
71108 function link(href, text) {
72109 return { href: toText(href), text:text };
73110 }
74− function underline(text) {
75− return { line: ' underline', text:text };
76− }
77− function overline(text) {
78− return { line: ' overline', text:text };
79− }
80− function strikeThrough(text) {
81− return { line: ' line-through', text:text };
111+ function line(line, text) {
112+ return { style: 'text-decoration:' + toLine(line) + ';', text:text };
82113 }
83114
84− function color(c, text) {
85− var color = (c._3 === 1)
86− ? ('rgb(' + c._0 + ', ' + c._1 + ', ' + c._2 + ')')
87− : ('rgba(' + c._0 + ', ' + c._1 + ', ' + c._2 + ', ' + c._3 + ')');
88− return { style: 'color:' + color + ';', text:text };
115+ function color(color, text) {
116+ return { style: 'color:' + toCss(color) + ';', text:text };
89117 }
90118
91− function position(align) {
92− function create(text) {
119+ function block(align) {
120+ return function(text) {
93121 var raw = {
94122 ctor :'RawHtml',
95123 html : Utils.makeText(text),
@@ -100,7 +128,6 @@ Elm.Native.Text.make = function(elm) {
100128 var pos = A2(Utils.htmlHeight, 0, raw);
101129 return A3(Element.newElement, pos._0, pos._1, raw);
102130 }
103− return create;
104131 }
105132
106133 function markdown(text, guid) {
@@ -115,36 +142,25 @@ Elm.Native.Text.make = function(elm) {
115142 return A3(Element.newElement, pos._0, pos._1, raw);
116143 }
117144
118− var text = position('left');
119− function asText(v) {
120− return text(monospace(toText(show(v))));
121− }
122−
123− function plainText(v) {
124− return text(toText(v));
125− }
126−
127145 return elm.Native.Text.values = {
128146 toText: toText,
129147
130148 height : F2(height),
131149 italic : italic,
132150 bold : bold,
133− underline : underline,
134− overline : overline,
135− strikeThrough : strikeThrough,
151+ line : F2(line),
136152 monospace : monospace,
137153 typeface : F2(typeface),
138154 color : F2(color),
139155 link : F2(link),
140156
141− justified : position('justify'),
142− centered : position('center'),
143− righted : position('right'),
144− text : text,
145− plainText : plainText,
146− markdown : markdown,
157+ leftAligned : block('left'),
158+ rightAligned : block('right'),
159+ centered : block('center'),
160+ justified : block('justify'),
161+ markdown : markdown,
147162
148− asText : asText,
163+ toTypefaces:toTypefaces,
164+ toLine:toLine,
149165 };
150166};
libraries/Native/Utils.js−7
@@ -76,14 +76,8 @@ Elm.Native.Utils.make = function(elm) {
7676
7777 function makeText(text) {
7878 var style = '';
79− var line = '';
8079 var href = '';
8180 while (true) {
82− if (text.line) {
83− line += text.line;
84− text = text.text;
85− continue;
86− }
8781 if (text.style) {
8882 style += text.style;
8983 text = text.text;
@@ -95,7 +89,6 @@ Elm.Native.Utils.make = function(elm) {
9589 continue;
9690 }
9791 if (href) text = '<a href="' + href + '">' + text + '</a>';
98− if (line) style += 'text-decoration:' + line + ';';
9992 if (style) text = '<span style="' + style + '">' + text + '</span>';
10093 return text;
10194 }
libraries/Prelude.elmdeleted−8
@@ -1,8 +0,0 @@
1−module Prelude where
2−{-| Everything that is automatically imported -}
3−
4−import Native.Show
5−
6−-- Convert almost any value to its string representation.
7−show : a -> String
8−show = Native.Show.show
libraries/String.elm+28−5
@@ -15,7 +15,7 @@ are enclosed in `"double quotes"`. Strings are *not* lists of characters.
1515@docs contains, startsWith, endsWith, indexes, indices
1616
1717# Conversions
18−@docs toInt, toFloat, toList, fromList
18+@docs show, toInt, toFloat, toList, fromList
1919
2020# Formatting
2121Cosmetic operations such as padding with extra characters or trimming whitespace.
@@ -28,10 +28,15 @@ Cosmetic operations such as padding with extra characters or trimming whitespace
2828@docs map, filter, foldl, foldr, any, all
2929-}
3030
31+import Native.Show
3132import Native.String
3233import Maybe (Maybe)
3334
34−{-| Check if a string is empty `(isEmpty "" == True)` -}
35+{-| Check if a string is empty.
36+
37+ isEmpty "" == True
38+ isEmpty "the world" == False
39+-}
3540isEmpty : String -> Bool
3641isEmpty = Native.String.isEmpty
3742
@@ -63,7 +68,11 @@ append = Native.String.append
6368concat : [String] -> String
6469concat = Native.String.concat
6570
66−{-| Get the length of a string `(length "innumerable" == 11)` -}
71+{-| Get the length of a string.
72+
73+ length "innumerable" == 11
74+
75+-}
6776length : String -> Int
6877length = Native.String.length
6978
@@ -81,7 +90,10 @@ map = Native.String.map
8190filter : (Char -> Bool) -> String -> String
8291filter = Native.String.filter
8392
84−{-| Reverse a string. `(reverse "stressed" == "desserts")` -}
93+{-| Reverse a string.
94+
95+ reverse "stressed" == "desserts"
96+-}
8597reverse : String -> String
8698reverse = Native.String.reverse
8799
@@ -117,7 +129,10 @@ split = Native.String.split
117129join : String -> [String] -> String
118130join = Native.String.join
119131
120−{-| Repeat a string N times `(repeat 3 "ha" == "hahaha")` -}
132+{-| Repeat a string N times.
133+
134+ repeat 3 "ha" == "hahaha"
135+-}
121136repeat : Int -> String -> String
122137repeat = Native.String.repeat
123138
@@ -278,6 +293,14 @@ indexes = Native.String.indexes
278293indices : String -> String -> [Int]
279294indices = Native.String.indexes
280295
296+{-| Turn any kind of value into a string.
297+
298+ show 42 == "42"
299+ show [1,2] == "[1,2]"
300+-}
301+show : a -> String
302+show = Native.Show.show
303+
281304{-| Try to convert a string into an int, failing on improperly formatted strings.
282305
283306 toInt "123" == Just 123
libraries/Text.elm+79−40
@@ -6,94 +6,132 @@ module Text where
66@docs toText
77
88# Creating Elements
9−@docs plainText, asText, text, centered, justified, righted
9+@docs leftAligned, rightAligned, centered, justified
1010
11−# Formatting
12−@docs color, typeface, height, link
11+# Links and Style
12+@docs link, Style, style, Line, defaultStyle
1313
14−# Simple Formatting
15−@docs monospace, bold, italic, underline, overline, strikeThrough
14+# Convenience Functions
15+
16+There are two convenience functions for creating an `Element` which can be
17+useful when debugging or prototyping:
18+
19+@docs plainText, asText
20+
21+There are also a bunch of functions to set parts of a `Style` individually:
22+
23+@docs typeface, monospace, height, color, bold, italic, line
1624
1725-}
1826
1927import Basics (..)
20−import Color (Color)
28+import String
29+import Color (Color, black)
2130import Graphics.Element (Element, Three, Pos, ElementPrim, Properties)
22−import Maybe (Maybe)
31+import Maybe (Maybe, Nothing)
2332import JavaScript (JSString)
33+import Native.Show
2434import Native.Text
2535
2636data Text = Text
2737
38+data Line = Under | Over | Through
39+
40+{-| Representation of all the ways you can style `Text`.
41+-}
42+type Style =
43+ { typeface : [String]
44+ , height : Maybe Float
45+ , color : Color
46+ , bold : Bool
47+ , italic : Bool
48+ , line : Maybe Line
49+ }
50+
51+{-| Plain black text. It uses the browsers default typeface and text height.
52+No decorations are used:
53+
54+ { typeface = []
55+ , height = Nothing
56+ , color = black
57+ , bold = False
58+ , italic = False
59+ , line = Nothing
60+ }
61+-}
62+defaultStyle : Style
63+defaultStyle =
64+ { typeface = []
65+ , height = Nothing
66+ , color = black
67+ , bold = False
68+ , italic = False
69+ , line = Nothing
70+ }
71+
2872{-| Convert a string into text which can be styled and displayed. -}
2973toText : String -> Text
3074toText = Native.Text.toText
3175
32−{-| Set the typeface of some text. The first argument should be a comma
33−separated listing of the desired typefaces:
76+{-| Set the style of some text.
77+-}
78+style : Style -> Text -> Text
79+style = Native.Text.style
80+
81+{-| Provide a list of prefered typefaces for some text.
3482
35− "helvetica, arial, sans-serif"
83+ ["helvetica","arial","sans-serif"]
3684
37−Works the same as the CSS font-family property.
85+Not everyone has access to the same typefaces, so rendering will use the first
86+typeface in the list that is found on the user's computer. If there are no
87+matches, it will use their default typeface. Works the same as the CSS
88+font-family property.
3889-}
39−typeface : String -> Text -> Text
90+typeface : [String] -> Text -> Text
4091typeface = Native.Text.typeface
4192
4293{-| Switch to a monospace typeface. Good for code snippets. -}
4394monospace : Text -> Text
4495monospace = Native.Text.monospace
4596
46−{-| Create a link. -}
97+{-| Create a link.
98+
99+ link "http://elm-lang.org" (toText "Elm Website")
100+-}
47101link : String -> Text -> Text
48102link = Native.Text.link
49103
50−{-| Set the height of text in pixels. -}
51104height : Float -> Text -> Text
52105height = Native.Text.height
53106
54−{-| Set the color of a string. -}
55107color : Color -> Text -> Text
56108color = Native.Text.color
57109
58−{-| Make a string bold. -}
59110bold : Text -> Text
60111bold = Native.Text.bold
61112
62−{-| Italicize a string. -}
63113italic : Text -> Text
64114italic = Native.Text.italic
65115
66−{-| Draw a line above a string. -}
67−overline : Text -> Text
68−overline = Native.Text.overline
116+line : Line -> Text -> Text
117+line = Native.Text.line
69118
70−{-| Underline a string. -}
71−underline : Text -> Text
72−underline = Native.Text.underline
119+leftAligned : Text -> Element
120+leftAligned = Native.Text.leftAligned
73121
74−{-| Draw a line through a string. -}
75−strikeThrough : Text -> Text
76−strikeThrough = Native.Text.strikeThrough
122+rightAligned : Text -> Element
123+rightAligned = Native.Text.rightAligned
77124
78−{-| Display justified, styled text. -}
79−justified : Text -> Element
80−justified = Native.Text.justified
81−
82−{-| Display centered, styled text. -}
83125centered : Text -> Element
84126centered = Native.Text.centered
85127
86−{-| Display right justified, styled text. -}
87−righted : Text -> Element
88−righted = Native.Text.righted
89−
90−{-| Display styled text. -}
91−text : Text -> Element
92−text = Native.Text.text
128+justified : Text -> Element
129+justified = Native.Text.justified
93130
94131{-| Display a plain string. -}
95132plainText : String -> Element
96−plainText = Native.Text.plainText
133+plainText str =
134+ leftAligned (toText str)
97135
98136{-| for internal use only -}
99137markdown : Element
@@ -107,4 +145,5 @@ the browser:
107145Excellent for debugging.
108146-}
109147asText : a -> Element
110−asText = Native.Text.asText
148+asText value =
149+ leftAligned (monospace (toText (Native.Show.show value)))
runtime/Init.js+1−1
@@ -91,7 +91,7 @@ function init(display, container, module, ports, moduleToReplace) {
9191 checkPorts(elm);
9292 } catch(e) {
9393 var directions = "<br/>&nbsp; &nbsp; Open the developer console for more details."
94− Module.main = Elm.Text.make(elm).text('<code>' + e.message + directions + '</code>');
94+ Module.main = Elm.Text.make(elm).leftAligned('<code>' + e.message + directions + '</code>');
9595 reportAnyErrors = function() { throw e; }
9696 }
9797 inputs = ElmRuntime.filterDeadInputs(inputs);
runtime/Render/Element.js+20−3
@@ -7,7 +7,15 @@ var newElement = Utils.newElement, extract = Utils.extract,
77 addTransform = Utils.addTransform, removeTransform = Utils.removeTransform,
88 fromList = Utils.fromList, eq = Utils.eq;
99
10−function setProps(props, e) {
10+function setProps(elem, e) {
11+ var props = elem.props;
12+ var element = elem.element;
13+ if (element.adjustWidth) {
14+ props.width -= element.adjustWidth;
15+ }
16+ if (element.adjustHeight) {
17+ props.height -= element.adjustHeight;
18+ }
1119 e.style.width = (props.width |0) + 'px';
1220 e.style.height = (props.height|0) + 'px';
1321 if (props.opacity !== 1) { e.style.opacity = props.opacity; }
@@ -200,7 +208,7 @@ function rawHtml(elem) {
200208 return div;
201209}
202210
203−function render(elem) { return setProps(elem.props, makeElement(elem)); }
211+function render(elem) { return setProps(elem, makeElement(elem)); }
204212function makeElement(e) {
205213 var elem = e.element;
206214 switch(elem.ctor) {
@@ -308,7 +316,16 @@ function update(node, curr, next) {
308316}
309317
310318function updateProps(node, curr, next) {
311− var props = next.props, currP = curr.props, e = node;
319+ var props = next.props;
320+ var currP = curr.props;
321+ var e = node;
322+ var element = next.element;
323+ if (element.adjustWidth) {
324+ props.width -= element.adjustWidth;
325+ }
326+ if (element.adjustHeight) {
327+ props.height -= element.adjustHeight;
328+ }
312329 if (props.width !== currP.width) e.style.width = (props.width |0) + 'px';
313330 if (props.height !== currP.height) e.style.height = (props.height|0) + 'px';
314331 if (props.opacity !== 1 && props.opacity !== currP.opacity) {