on master help sign in
Add basic drop down menus.
commit2da0a59e35d2bc48e83ff4d3d638939fc2bb0431 authorevancz <info@elm-lang.org> dateThu 23 May 2013, 12:44 (13 years ago) parent5714764
2 files changed+71−13
libraries/Graphics/Input.elm+23−4 libraries/Native/Graphics/Input.js+48−9
libraries/Graphics/Input.elm+23−4
@@ -1,8 +1,9 @@
11
22module Graphics.Input where
33
4−import Signal (lift)
4+import Signal (lift,dropRepeats)
55import Native.Graphics.Input as N
6+import List
67
78id x = x
89
@@ -102,13 +103,17 @@ emptyFieldState = { string="", selectionStart=0, selectionEnd=0 }
102103field : String -> (Signal Element, Signal String)
103104field placeHolder =
104105 let tfs = N.fields emptyFieldState
105− in (lift (tfs.field id placeHolder) tfs.events, lift .string tfs.events)
106+ changes = dropRepeats tfs.events
107+ in (lift (tfs.field id placeHolder) changes,
108+ dropRepeats (lift .string changes))
106109
107110-- Same as `field` but the UI element blocks out each characters.
108111password : String -> (Signal Element, Signal String)
109112password placeHolder =
110113 let tfs = N.passwords emptyFieldState
111− in (lift (tfs.field id placeHolder) tfs.events, lift .string tfs.events)
114+ changes = dropRepeats tfs.events
115+ in (lift (tfs.field id placeHolder) changes,
116+ dropRepeats (lift .string changes))
112117
113118-- Same as `field` but it adds an annotation that this field is for email
114119-- addresses. This is helpful for auto-complete and for mobile users who may
@@ -116,4 +121,18 @@ password placeHolder =
116121email : String -> (Signal Element, Signal String)
117122email placeHolder =
118123 let tfs = N.emails emptyFieldState
119− in (lift (tfs.field id placeHolder) tfs.events, lift .string tfs.events)
124+ changes = dropRepeats tfs.events
125+ in (lift (tfs.field id placeHolder) changes,
126+ dropRepeats (lift .string changes))
127+
128+-- Create a drop-down menu. When the user selects a string,
129+-- the current state of the drop-down is set to the associated
130+-- value. This lets you avoid manually mapping the string onto
131+-- functions and values.
132+dropDown : [(String,a)] -> (Signal Element, Signal a)
133+
134+-- Create a drop-down menu for selecting strings. The resulting
135+-- signal of strings represents the string that is currently selected.
136+stringDropDown : [String] -> (Signal Element, Signal String)
137+stringDropDown strs =
138+ N.dropDown (List.map (\s -> (s,s)) strs)
libraries/Native/Graphics/Input.js+48−9
@@ -7,12 +7,50 @@ Elm.Native.Graphics.Input = function(elm) {
77 if (elm.Native.Graphics.Input) return elm.Native.Graphics.Input;
88
99 var Render = ElmRuntime.use(ElmRuntime.Render.Element);
10− var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
11− var newNode = Utils.newElement, fromString = Utils.fromString,
12− toString = Utils.toString;
10+ var newNode = ElmRuntime.use(ElmRuntime.Render.Utils).newElement;
1311
1412 var Signal = Elm.Signal(elm);
1513 var newElement = Elm.Graphics.Element(elm).newElement;
14+ var JS = Elm.Native.JavaScript(elm);
15+ var Tuple2 = Elm.Native.Utils(elm).Tuple2;
16+
17+ function dropDown(values) {
18+ var entries = JS.fromList(values);
19+ var events = Signal.constant(entries[0]._1);
20+
21+ var drop = newNode('select');
22+ drop.style.border = '0 solid';
23+ for (var i = 0; i < entries.length; ++i) {
24+ var option = newNode('option');
25+ var name = JS.fromString(entries[i]._0);
26+ option.value = name;
27+ option.innerHTML = name;
28+ drop.appendChild(option);
29+ }
30+ drop.addEventListener('change', function() {
31+ elm.notify(events.id, entries[drop.selectedIndex]._1);
32+ });
33+
34+ var t = drop.cloneNode(true);
35+ t.style.visibility = "hidden";
36+
37+ elm.node.appendChild(t);
38+ var style = window.getComputedStyle(t, null);
39+ var w = Math.ceil(style.getPropertyValue("width").slice(0,-2) - 0);
40+ var h = Math.ceil(style.getPropertyValue("height").slice(0,-2) - 0);
41+ elm.node.removeChild(t);
42+
43+ console.log(w,h);
44+ var element = A3(newElement, w, h, {
45+ ctor: 'Custom',
46+ type: 'DropDown',
47+ render: function render(model) { return drop; },
48+ update: function update(node, oldModel, newModel) {},
49+ model: {}
50+ });
51+
52+ return Tuple2(Signal.constant(element), events);
53+ }
1654
1755 function buttons(defaultValue) {
1856 var events = Signal.constant(defaultValue);
@@ -39,7 +77,7 @@ Elm.Native.Graphics.Input = function(elm) {
3977 type: 'Button',
4078 render: render,
4179 update: update,
42− model: { event:evnt, text:fromString(txt) }
80+ model: { event:evnt, text:JS.fromString(txt) }
4381 });
4482 }
4583
@@ -159,8 +197,8 @@ Elm.Native.Graphics.Input = function(elm) {
159197
160198 field.id = 'test';
161199 field.type = type;
162− field.placeholder = fromString(model.placeHolder);
163− field.value = fromString(model.state.string);
200+ field.placeholder = JS.fromString(model.placeHolder);
201+ field.value = JS.fromString(model.state.string);
164202 setRange(field, model.state.selectionStart, model.state.selectionEnd, 'forward');
165203 field.style.border = 'none';
166204 state = model.state;
@@ -173,7 +211,7 @@ Elm.Native.Graphics.Input = function(elm) {
173211 end = field.selectionStart;
174212 }
175213 state = { _:{},
176− string:toString(field.value),
214+ string:JS.toString(field.value),
177215 selectionStart:start,
178216 selectionEnd:end };
179217 elm.notify(events.id, field.elmHandler(state));
@@ -195,7 +233,7 @@ Elm.Native.Graphics.Input = function(elm) {
195233 function update(node, oldModel, newModel) {
196234 node.elmHandler = newModel.handler;
197235 if (state === newModel.state) return;
198− var newStr = fromString(newModel.state.string);
236+ var newStr = JS.fromString(newModel.state.string);
199237 if (node.value !== newStr) node.value = newStr;
200238
201239 var start = newModel.state.selectionStart;
@@ -236,7 +274,8 @@ Elm.Native.Graphics.Input = function(elm) {
236274 checkboxes:checkboxes,
237275 fields:mkTextPool('text'),
238276 emails:mkTextPool('email'),
239− passwords:mkTextPool('password')
277+ passwords:mkTextPool('password'),
278+ dropDown:dropDown
240279 };
241280
242281};