on master help sign in
Add implementation for `buttons`, `customButtons`, and `textFields`.

Also fix updating bug in `flow`.

commitb930ac29847241445601797d67a648cd25d103ca authorevancz <info@elm-lang.org> dateSun 24 Mar 2013, 19:19 (14 years ago) parent87a275a
6 files changed+199−15
libraries/Graphics/Input.elm+6−4 libraries/Native/Graphics/Collage.js+8−4 libraries/Native/Graphics/Input.js+163 runtime/Render/Collage.js+5−1 runtime/Render/Element.js+16−6 runtime/Render/Utils.js+1
libraries/Graphics/Input.elm+6−4
@@ -1,11 +1,13 @@
11
22module Graphics.Input where
33
4+import Native.Graphics.Input as N
5+
46buttons : a -> { button : a -> String -> Element, events : Signal a }
57
68button : String -> (Element, Signal ())
79button txt =
8− let pool = buttons ()
10+ let pool = N.buttons ()
911 in (pool.button () txt, pool.events)
1012
1113customButtons : a -> { button : a -> Element -> Element -> Element -> Element,
@@ -13,14 +15,14 @@ customButtons : a -> { button : a -> Element -> Element -> Element -> Element,
1315
1416customButton : Element -> Element -> Element -> (Element, Signal ())
1517customButton up hover down =
16− let pool = customButtons ()
18+ let pool = N.customButtons ()
1719 in (pool.button () up hover down, pool.events)
1820
1921checkBoxes : a -> { box : (Bool -> a) -> Bool -> Element, events : Signal a }
2022
2123checkBox : Bool -> (Signal Element, Signal Bool)
2224checkBox b =
23− let cbs = checkBoxes b
25+ let cbs = N.checkBoxes b
2426 in (lift (cbs.box id) cbs.events, cbs.events)
2527
2628type TextState = {
@@ -34,7 +36,7 @@ textFields : a -> { field : (TextState -> a) -> String -> TextState -> Element,
3436
3537textField : String -> TextState -> (Signal Element, Signal TextState)
3638textField placeHolder textState =
37− let tfs = textFields textState
39+ let tfs = N.textFields textState
3840 in (lift (tfs.field id placeHolder) tfs.events, tfs.events)
3941
4042password : String -> TextState -> (Signal Element, Signal TextState)
libraries/Native/Graphics/Collage.js+8−4
@@ -7,12 +7,16 @@ Elm.Native.Graphics.Collage = function(elm) {
77 if (elm.Native.Graphics.Collage) return elm.Native.Graphics.Collage;
88
99 var newElement = Elm.Graphics.Element(elm).newElement;
10− var render = ElmRuntime.use(ElmRuntime.Render.Collage).render;
10+ var C = ElmRuntime.use(ElmRuntime.Render.Collage);
1111
1212 function collage(w,h,forms) {
13− return A3(newElement, w, h,
14− {ctor: 'Custom', render: render,
15− model: {w:w, h:h, forms:forms} });
13+ return A3(newElement, w, h, {
14+ ctor: 'Custom',
15+ type: 'Collage',
16+ render: C.render,
17+ update: C.update,
18+ model: {w:w, h:h, forms:forms}
19+ });
1620 }
1721 return elm.Native.Graphics.Collage = { collage:F3(collage) };
1822
libraries/Native/Graphics/Input.jsnew file+163
@@ -0,0 +1,163 @@
1+
2+Elm.Native.Graphics.Input = function(elm) {
3+ "use strict";
4+
5+ elm.Native = elm.Native || {};
6+ elm.Native.Graphics = elm.Native.Graphics || {};
7+ if (elm.Native.Graphics.Input) return elm.Native.Graphics.Input;
8+
9+ 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;
13+
14+ var Signal = Elm.Signal(elm);
15+ var newElement = Elm.Graphics.Element(elm).newElement;
16+
17+ function buttons(defaultValue) {
18+ var events = Signal.constant(defaultValue);
19+
20+ function render(model) {
21+ var b = newNode('button');
22+ b.style.display = 'block';
23+ b.elmEvent = model.event;
24+ function click() { elm.notify(events.id, b.elmEvent); }
25+ b.addEventListener('click', click);
26+ b.innerHTML = model.text;
27+ return b;
28+ }
29+
30+ function update(node, oldModel, newModel) {
31+ node.elmEvent = newModel.event;
32+ var txt = newModel.text;
33+ if (oldModel.text !== txt) node.innerHTML = txt;
34+ }
35+
36+ function button(evnt, txt) {
37+ return A3(newElement, 100, 40, {
38+ ctor: 'Custom',
39+ type: 'Button',
40+ render: render,
41+ update: update,
42+ model: { event:evnt, text:fromString(txt) }
43+ });
44+ }
45+
46+ return { _:{}, button:F2(button), events:events };
47+ }
48+
49+ function customButtons(defaultValue) {
50+ var events = Signal.constant(defaultValue);
51+
52+ function render(model) {
53+ var btn = newNode('div');
54+ btn.elmEvent = model.event;
55+
56+ btn.elmUp = Render.render(model.up);
57+ btn.elmHover = Render.render(model.hover);
58+ btn.elmDown = Render.render(model.down);
59+
60+ function replace(node) { return function() {
61+ if (node !== btn.firstChild) btn.replaceChild(node, btn.firstChild);
62+ };
63+ }
64+ var hover = replace(btn.elmHover);
65+ function up() { hover(); elm.notify(events.id, btn.elmEvent); }
66+ btn.addEventListener('mouseover', hover);
67+ btn.addEventListener('mouseout' , replace(btn.elmUp));
68+ btn.addEventListener('mousedown', replace(btn.elmDown));
69+ btn.addEventListener('mouseup' , up);
70+
71+ btn.appendChild(btn.elmUp);
72+ return btn;
73+ }
74+
75+ function update(node, oldModel, newModel) {
76+ node.elmEvent = newModel.event;
77+ Render.update(node.elmUp, oldModel.up, newModel.up)
78+ Render.update(node.elmHover, oldModel.hover, newModel.hover)
79+ Render.update(node.elmDown, oldModel.down, newModel.down)
80+ }
81+
82+ function button(evnt, up, hover, down) {
83+ return A3(newElement,
84+ Math.max(up.props.width, hover.props.width, down.props.width),
85+ Math.max(up.props.height, hover.props.height, down.props.height),
86+ { ctor: 'Custom',
87+ type: 'CustomButton',
88+ render: render,
89+ update: update,
90+ model: { event:evnt, up:up, hover:hover, down:down }
91+ });
92+ }
93+
94+ return { _:{}, button:F4(button), events:events };
95+ }
96+
97+ function textFields(defaultValue) {
98+ var events = Signal.constant(defaultValue);
99+
100+ function render(model) {
101+ console.log('render');
102+ var field = newNode('input');
103+ field.elmHandler = model.handler;
104+
105+ field.id = 'test'
106+ field.placeholder = fromString(model.placeHolder);
107+ field.elmValue = fromString(model.state.input);
108+ field.value = field.elmValue;
109+ field.setSelectionRange(model.state.start, model.state.end);
110+ field.style.border = 'none';
111+
112+ function update() {
113+ var state = { _:{},
114+ input:toString(field.value),
115+ start:field.selectionStart,
116+ end:field.selectionEnd };
117+ field.value = field.elmValue;
118+ elm.notify(events.id, state);
119+ }
120+ function mousedown() {
121+ update();
122+ elm.node.addEventListener('mouseup', mouseup);
123+ }
124+ function mouseup() {
125+ update();
126+ elm.node.removeEventListener('mouseup', mouseup)
127+ }
128+ field.addEventListener('keyup', update);
129+ field.addEventListener('mousedown', mousedown);
130+
131+ return field;
132+ }
133+
134+ function update(node, oldModel, newModel) {
135+ console.log('update');
136+ node.elmEvent = newModel.handler;
137+ node.elmValue = fromString(newModel.state.input);
138+ node.value = node.elmValue;
139+ node.setSelectionRange(newModel.state.start, newModel.state.end);
140+ }
141+
142+ function field(handler, placeHolder, state) {
143+ return A3(newElement, 200, 30,
144+ { ctor: 'Custom',
145+ type: 'TextField',
146+ render: render,
147+ update: update,
148+ model: { handler:handler,
149+ placeHolder:placeHolder,
150+ state:state }
151+ });
152+ }
153+
154+ return { _:{}, field:F3(field), events:events };
155+ }
156+
157+ return elm.Native.Graphics.Input = {
158+ buttons:buttons,
159+ customButtons:customButtons,
160+ textFields:textFields
161+ };
162+
163+};
runtime/Render/Collage.js+5−1
@@ -186,6 +186,10 @@ function render(model) {
186186 return collageForms(model.w, model.h, model.forms);
187187}
188188
189−return { render:render };
189+function update(node, oldModel, newModel) {
190+ node.parentNode.replaceChild(render(newModel), node);
191+}
192+
193+return { render:render, update:update };
190194
191195};
runtime/Render/Element.js+16−6
@@ -4,7 +4,8 @@ ElmRuntime.Render.Element = function() {
44
55var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
66var newElement = Utils.newElement, addTo = Utils.addTo, extract = Utils.extract,
7− addTransform = Utils.addTransform, removeTransform = Utils.removeTransform;
7+ addTransform = Utils.addTransform, removeTransform = Utils.removeTransform,
8+ fromList = Utils.fromList;
89
910function setProps(props, e) {
1011 e.style.width = (props.width |0) + 'px';
@@ -166,6 +167,7 @@ function makeElement(e) {
166167}
167168
168169function update(node, curr, next) {
170+ console.log('overall update', curr.element.ctor, next.element.ctor);
169171 if (node.tagName === 'A') { node = node.firstChild; }
170172 if (curr.props.id === next.props.id) return false;
171173 if (curr.element.ctor !== next.element.ctor) {
@@ -187,23 +189,27 @@ function update(node, curr, next) {
187189 }
188190 break;
189191 case "Flow":
192+ console.log('flow update', nextE._0.ctor, currE._0.ctor);
190193 if (nextE._0.ctor !== currE._0.ctor) {
191194 node.parentNode.replaceChild(render(next),node);
192195 return true;
193196 }
194− var nexts = nextE._1;
197+ var nexts = fromList(nextE._1);
195198 var kids = node.childNodes;
199+ console.log('flow length', nexts.length, kids.length);
196200 if (nexts.length !== kids.length) {
197201 node.parentNode.replaceChild(render(next),node);
198202 return true;
199203 }
200− var currs = currE._1;
204+ var currs = fromList(currE._1);
201205 var goDir = function(x) { return x; };
202− switch(nextE[1][0]) {
206+ console.log(nextE);
207+ switch(nextE._0.ctor) {
203208 case "DDown": case "DUp": goDir = goDown; break;
204209 case "DRight": case "DLeft": goDir = goRight; break;
205210 case "DOut": case "DIn": goDir = goIn; break;
206211 }
212+ console.log(currs, nexts);
207213 for (var i = kids.length; i-- ;) {
208214 update(kids[i],currs[i],nexts[i]);
209215 goDir(kids[i]);
@@ -224,8 +230,12 @@ function update(node, curr, next) {
224230 setPos(nextE._0, next.props.width, next.props.height, node.firstChild);
225231 break;
226232 case "Custom":
227− node.parentNode.replaceChild(render(next),node);
228− return true;
233+ console.log(currE.type, nextE.type);
234+ if (currE.type === nextE.type) {
235+ nextE.update(node, currE.model, nextE.model);
236+ } else {
237+ return node.parentNode.replaceChild(render(next), node);
238+ }
229239 }
230240 var props = next.props, currP = curr.props, e = node;
231241 if (props.width !== currP.width) e.style.width = (props.width |0) + 'px';
runtime/Render/Utils.js+1
@@ -41,6 +41,7 @@ return {addTo:addTo,
4141 extract : extract,
4242 fromList: JS.fromList,
4343 fromString: JS.fromString,
44+ toString: JS.toString,
4445 eq: Elm.Native.Utils({}).eq,
4546 addTransform: addTransform,
4647 removeTransform: removeTransform