@@ -15,188 +15,184 @@ Elm.Native.Graphics.Input.make = function(elm) {
15 var Utils = Elm.Native.Utils.make(elm);
15 var Utils = Elm.Native.Utils.make(elm);
16 var Tuple2 = Utils.Tuple2;
16 var Tuple2 = Utils.Tuple2;
18− function dropDown(values) {
18+ function input(initialValue) {
19− var entries = JS.fromList(values);
20− var events = Signal.constant(entries[0]._1);
19+ var sig = Signal.constant(initialValue);
21−
20+ return Tuple2(sig, sig);
22− var drop = newNode('select');
23− drop.style.border = '0 solid';
24− for (var i = 0; i < entries.length; ++i) {
25− var option = newNode('option');
26− var name = JS.fromString(entries[i]._0);
28− option.innerHTML = name;
29− drop.appendChild(option);
31− drop.addEventListener('change', function() {
32− elm.notify(events.id, entries[drop.selectedIndex]._1);
35− var t = drop.cloneNode(true);
23+ function renderDropDown(signal, values) {
36− t.style.visibility = "hidden";
24+ return function(_) {
25+ var entries = JS.fromList(values);
27+ var drop = newNode('select');
28+ drop.style.border = '0 solid';
29+ for (var i = 0; i < entries.length; ++i) {
30+ var option = newNode('option');
31+ var name = JS.fromString(entries[i]._0);
33+ option.innerHTML = name;
34+ drop.appendChild(option);
36+ drop.addEventListener('change', function() {
37+ elm.notify(signal.id, entries[drop.selectedIndex]._1);
40+ var t = drop.cloneNode(true);
41+ t.style.visibility = "hidden";
38− elm.node.appendChild(t);
43+ elm.node.appendChild(t);
39− var style = window.getComputedStyle(t, null);
44+ var style = window.getComputedStyle(t, null);
40− var w = Math.ceil(style.getPropertyValue("width").slice(0,-2) - 0);
45+ var w = Math.ceil(style.getPropertyValue("width").slice(0,-2) - 0);
41− var h = Math.ceil(style.getPropertyValue("height").slice(0,-2) - 0);
46+ var h = Math.ceil(style.getPropertyValue("height").slice(0,-2) - 0);
42− elm.node.removeChild(t);
47+ elm.node.removeChild(t);
52+ function updateDropDown(node, oldModel, newModel) {
55+ function dropDown(signal, values) {
44− var element = A3(newElement, w, h, {
56+ return A3(newElement, w, h, {
45 ctor: 'Custom',
57 ctor: 'Custom',
46 type: 'DropDown',
58 type: 'DropDown',
47− render: function render(model) { return drop; },
59+ render: renderDropDown(signal,values),
48− update: function update(node, oldModel, newModel) {},
60+ update: updateDropDown,
52− return Tuple2(Signal.constant(element), events);
55− function buttons(defaultValue) {
65+ function renderButton(model) {
56− var events = Signal.constant(defaultValue);
58− function render(model) {
59− var b = newNode('button');
66+ var node = newNode('button');
60− b.style.display = 'block';
67+ node.style.display = 'block';
61− b.elmEvent = model.event;
68+ node.elm_signal = model.signal;
69+ node.elm_value = model.value;
62− function click() { elm.notify(events.id, b.elmEvent); }
70+ function click() {
63− b.addEventListener('click', click);
71+ elm.notify(node.elm_signal.id, node.elm_value);
64− b.innerHTML = model.text;
68− function update(node, oldModel, newModel) {
69− node.elmEvent = newModel.event;
70− var txt = newModel.text;
71− if (oldModel.text !== txt) node.innerHTML = txt;
74− function button(evnt, txt) {
75− return A3(newElement, 100, 40, {
80− model: { event:evnt, text:JS.fromString(txt) }
73+ node.addEventListener('click', click);
74+ node.innerHTML = model.text;
84− return { _:{}, button:F2(button), events:events };
78+ function updateButton(node, oldModel, newModel) {
79+ node.elm_signal = newModel.signal;
80+ node.elm_value = nemModel.value;
81+ var txt = newModel.text;
82+ if (oldModel.text !== txt) node.innerHTML = txt;
87− function customButtons(defaultValue) {
85+ function button(signal, value, text) {
88− var events = Signal.constant(defaultValue);
86+ return A3(newElement, 100, 40, {
89+ render: renderButton,
90+ update: updateButton,
91+ model: { signal:signal, value:value, text:JS.fromString(text) }
90− function render(model) {
95+ function renderCustomButton(model) {
91− var btn = newNode('div');
96+ var btn = newNode('div');
92− btn.elmEvent = model.event;
97+ btn.elm_value = model.value;
94− btn.elmUp = Render.render(model.up);
99+ btn.elm_up = Render.render(model.up);
95− btn.elmHover = Render.render(model.hover);
100+ btn.elm_hover = Render.render(model.hover);
96− btn.elmDown = Render.render(model.down);
101+ btn.elm_down = Render.render(model.down);
98− function replace(node) {
103+ function replace(node) {
104+ if (node !== btn.firstChild) {
99− if (node !== btn.firstChild) btn.replaceChild(node, btn.firstChild);
105+ btn.replaceChild(node, btn.firstChild);
103− if (overCount++ > 0) return;
104− replace(btn.elmHover);
107− if (btn.contains(e.toElement || e.relatedTarget)) return;
112− replace(btn.elmHover);
113− elm.notify(events.id, btn.elmEvent);
115− function down() { replace(btn.elmDown); }
116− btn.addEventListener('mouseover', over);
117− btn.addEventListener('mouseout' , out);
118− btn.addEventListener('mousedown', down);
119− btn.addEventListener('mouseup' , up);
121− btn.appendChild(btn.elmUp);
123− var clicker = newNode('div');
124− clicker.style.width = btn.elmUp.style.width;
125− clicker.style.height = btn.elmUp.style.height;
126− clicker.style.position = 'absolute';
127− clicker.style.top = 0;
128− btn.appendChild(clicker);
132−
108+ var overCount = 0;
133− function update(node, oldModel, newModel) {
109+ function over(e) {
134− node.elmEvent = newModel.event;
110+ if (overCount++ > 0) return;
135− Render.update(node.elmUp, oldModel.up, newModel.up)
111+ replace(btn.elm_hover);
136− Render.update(node.elmHover, oldModel.hover, newModel.hover)
137− Render.update(node.elmDown, oldModel.down, newModel.down)
139−
113+ function out(e) {
140− function button(evnt, up, hover, down) {
114+ if (btn.contains(e.toElement || e.relatedTarget)) return;
141− return A3(newElement,
115+ overCount = 0;
142− Math.max(up.props.width, hover.props.width, down.props.width),
116+ replace(btn.elm_up);
143− Math.max(up.props.height, hover.props.height, down.props.height),
117+ }
144− { ctor: 'Custom',
118+ function up() {
145− type: 'CustomButton',
119+ replace(btn.elm_hover);
146− render: render,
120+ elm.notify(btn.elm_signal.id, btn.elm_value);
148− model: { event:evnt, up:up, hover:hover, down:down }
123+ replace(btn.elm_down);
125+ btn.addEventListener('mouseover', over);
126+ btn.addEventListener('mouseout' , out);
127+ btn.addEventListener('mousedown', down);
128+ btn.addEventListener('mouseup' , up);
152− return { _:{}, customButton:F4(button), events:events };
130+ btn.appendChild(btn.elm_up);
132+ var clicker = newNode('div');
133+ clicker.style.width = btn.elm_up.style.width;
134+ clicker.style.height = btn.elm_up.style.height;
135+ clicker.style.position = 'absolute';
136+ clicker.style.top = 0;
137+ btn.appendChild(clicker);
156− function hoverables(defaultValue) {
139+ return btn;
157− var events = Signal.constant(defaultValue);
158− function hoverable(handler, elem) {
159− function onHover(bool) {
160− elm.notify(events.id, handler(bool));
162− var props = Utils.replace([['hover',onHover]], elem.props);
163− return { props:props, element:elem.element };
165− return { _:{}, hoverable:F2(hoverable), events:events };
142+ function updateCustomButton(node, oldModel, newModel) {
143+ node.elm_signal = newModel.signal;
144+ node.elm_value = newModel.value;
145+ Render.update(node.elm_up, oldModel.up, newModel.up)
146+ Render.update(node.elm_hover, oldModel.hover, newModel.hover)
147+ Render.update(node.elm_down, oldModel.down, newModel.down)
169− function checkboxes(defaultValue) {
150+ function max3(a,b,c) {
170− var events = Signal.constant(defaultValue);
151+ var ab = a > b ? a : b;
152+ return ab > c ? ab : c;
172− function render(model) {
155+ function customButton(signal, value, up, hover, down) {
173− var b = newNode('input');
156+ return A3(newElement,
174− b.type = 'checkbox';
157+ max3(up.props.width, hover.props.width, down.props.width),
175− b.checked = model.checked;
158+ max3(up.props.height, hover.props.height, down.props.height),
176− b.style.display = 'block';
159+ { ctor: 'Custom',
177− b.elmHandler = model.handler;
160+ type: 'CustomButton',
178− function change() { elm.notify(events.id, b.elmHandler(b.checked)); }
161+ render: renderCustomButton,
179− b.addEventListener('change', change);
162+ update: updateCustomButton,
180− return b;
163+ model: { signal:signal, value:value, up:up, hover:hover, down:down }
183− function update(node, oldModel, newModel) {
167+ function renderCheckbox(model) {
184− node.elmHandler = newModel.handler;
168+ var node = newNode('input');
185− node.checked = newModel.checked;
169+ node.type = 'checkbox';
186− return true;
170+ node.checked = model.checked;
171+ node.style.display = 'block';
172+ node.elm_signal = model.signal;
173+ node.elm_handler = model.handler;
175+ elm.notify(node.elm_signal.id, node.elm_handler(node.checked));
177+ node.addEventListener('change', change);
189− function box(handler, checked) {
181+ function updateCheckbox(node, oldModel, newModel) {
190− return A3(newElement, 13, 13, {
182+ node.elm_signal = newModel.signal;
191− ctor: 'Custom',
183+ node.elm_handler = newModel.handler;
192− type: 'CheckBox',
184+ node.checked = newModel.checked;
193− render: render,
185+ return true;
195− model: { checked:checked, handler:handler }
199− return { _:{}, checkbox:F2(box), events:events };
188+ function checkbox(signal, handler, checked) {
189+ return A3(newElement, 13, 13, {
192+ render: renderCheckbox,
193+ update: updateCheckbox,
194+ model: { signal:signal, handler:handler, checked:checked }
202 function setRange(node, start, end, dir) {
198 function setRange(node, start, end, dir) {
@@ -207,97 +203,114 @@ Elm.Native.Graphics.Input.make = function(elm) {
210− function mkTextPool(type) { return function fields(defaultValue) {
206+ function renderField(model) {
211− var events = Signal.constant(defaultValue);
215− function render(model) {
216− var field = newNode('input');
207+ var field = newNode('input');
208+ field.elm_signal = model.signal;
217− field.elmHandler = model.handler;
209+ field.elm_handler = model.handler;
219− field.id = 'test';
211+ field.id = 'test';
220− field.type = type;
212+ field.type = type;
221− field.placeholder = JS.fromString(model.placeHolder);
213+ field.placeholder = JS.fromString(model.placeHolder);
222− field.value = JS.fromString(model.state.string);
214+ field.value = JS.fromString(model.state.string);
223− setRange(field, model.state.selectionStart, model.state.selectionEnd, 'forward');
215+ setRange(field, model.state.selectionStart, model.state.selectionEnd, 'forward');
224− field.style.border = 'none';
216+ field.style.border = 'none';
225− state = model.state;
217+ state = model.state;
227− function update() {
219+ function update() {
228− var start = field.selectionStart,
220+ var start = field.selectionStart;
229− end = field.selectionEnd;
221+ var end = field.selectionEnd;
230− if (field.selectionDirection === 'backward') {
222+ if (field.selectionDirection === 'backward') {
231− start = end;
223+ start = end;
232− end = field.selectionStart;
224+ end = field.selectionStart;
235− string:JS.toString(field.value),
236− selectionStart:start,
238− elm.notify(events.id, field.elmHandler(state));
240− function mousedown() {
242− elm.node.addEventListener('mouseup', mouseup);
244− function mouseup() {
246− elm.node.removeEventListener('mouseup', mouseup)
248− field.addEventListener('keyup', update);
226+ elm.notify(events.id, field.elm_handler({
228+ string:JS.toString(field.value),
229+ selectionStart:start,
233+ function mousedown() {
249− field.addEventListener('mousedown', mousedown);
235+ elm.node.addEventListener('mouseup', mouseup);
251− return field;
237+ function mouseup() {
239+ elm.node.removeEventListener('mouseup', mouseup)
241+ field.addEventListener('keyup', update);
242+ field.addEventListener('mousedown', mousedown);
254− function update(node, oldModel, newModel) {
244+ return field;
255− node.elmHandler = newModel.handler;
245+ }
256− if (state === newModel.state) return;
257− var newStr = JS.fromString(newModel.state.string);
258− if (node.value !== newStr) node.value = newStr;
247+ function updateField(node, oldModel, newModel) {
248+ node.elmHandler = newModel.handler;
249+ var newStr = JS.fromString(newModel.state.string);
250+ if (node.value !== newStr) node.value = newStr;
260− var start = newModel.state.selectionStart;
252+ var start = newModel.state.selectionStart;
261− var end = newModel.state.selectionEnd;
253+ var end = newModel.state.selectionEnd;
262− var direction = 'forward';
254+ var direction = 'forward';
263− if (end < start) {
255+ if (end < start) {
264− start = end;
256+ start = end;
265− end = newModel.state.selectionStart;
257+ end = newModel.state.selectionStart;
266− direction = 'backward';
258+ direction = 'backward';
269− if (node.selectionStart !== start
261+ if (node.selectionStart !== start
270− || node.selectionEnd !== end
262+ || node.selectionEnd !== end
271− || node.selectionDirection !== direction) {
263+ || node.selectionDirection !== direction) {
272− setRange(node, start, end, direction);
264+ setRange(node, start, end, direction);
268+ function mkField(type) {
269+ function field(signal, handler, placeHolder, state) {
270+ return A3(newElement, 200, 30, {
272+ type: type + 'Input',
278+ placeHolder:placeHolder,
276− function field(handler, placeHolder, state) {
287+ function hoverable(signal, handler, element) {
277− return A3(newElement, 200, 30,
288+ function onHover(bool) {
278− { ctor: 'Custom',
289+ elm.notify(signal.id, handler(bool));
279− type: type + 'Input',
282− model: { handler:handler,
283− placeHolder:placeHolder,
291+ var props = Utils.replace([['hover',onHover]], elem.props);
292+ return { props:props, element:elem.element };
288− return { _:{}, field:F3(field), events:events };
295+ function clickable(signal, value, element) {
296+ function onClick(bool) {
297+ elm.notify(signal.id, value);
299+ var props = Utils.replace([['click',onClick]], elem.props);
300+ return { props:props, element:elem.element };
292 return elm.Native.Graphics.Input.values = {
303 return elm.Native.Graphics.Input.values = {
293− buttons:buttons,
304+ input:input,
294− customButtons:customButtons,
305+ button:F3(button),
295− hoverables:hoverables,
306+ customButton:F5(customButton),
296− checkboxes:checkboxes,
307+ checkbox:F3(checkbox),
297− fields:mkTextPool('text'),
308+ dropDown:F2(dropDown),
298− emails:mkTextPool('email'),
309+ field:mkField('text'),
299− passwords:mkTextPool('password'),
310+ email:mkField('email'),
300− dropDown:dropDown
311+ password:mkField('password'),
312+ hoverable:F3(hoverable),
313+ clickable:F3(clickable)