@@ -12,7 +12,8 @@ Elm.Native.Graphics.Input = function(elm) {
12 var Signal = Elm.Signal(elm);
12 var Signal = Elm.Signal(elm);
13 var newElement = Elm.Graphics.Element(elm).newElement;
13 var newElement = Elm.Graphics.Element(elm).newElement;
14 var JS = Elm.Native.JavaScript(elm);
14 var JS = Elm.Native.JavaScript(elm);
15− var Tuple2 = Elm.Native.Utils(elm).Tuple2;
15+ var Utils = Elm.Native.Utils(elm);
16+ var Tuple2 = Utils.Tuple2;
17 function dropDown(values) {
18 function dropDown(values) {
18 var entries = JS.fromList(values);
19 var entries = JS.fromList(values);
@@ -56,29 +57,29 @@ Elm.Native.Graphics.Input = function(elm) {
56 var events = Signal.constant(defaultValue);
57 var events = Signal.constant(defaultValue);
58 function render(model) {
59 function render(model) {
59− var b = newNode('button');
60+ var b = newNode('button');
60− b.style.display = 'block';
61+ b.style.display = 'block';
61− b.elmEvent = model.event;
62+ b.elmEvent = model.event;
62− function click() { elm.notify(events.id, b.elmEvent); }
63+ function click() { elm.notify(events.id, b.elmEvent); }
63− b.addEventListener('click', click);
64+ b.addEventListener('click', click);
64− b.innerHTML = model.text;
65+ b.innerHTML = model.text;
65− return b;
66+ return b;
68 function update(node, oldModel, newModel) {
69 function update(node, oldModel, newModel) {
69− node.elmEvent = newModel.event;
70+ node.elmEvent = newModel.event;
70− var txt = newModel.text;
71+ var txt = newModel.text;
71− if (oldModel.text !== txt) node.innerHTML = txt;
72+ if (oldModel.text !== txt) node.innerHTML = txt;
74 function button(evnt, txt) {
75 function button(evnt, txt) {
75− return A3(newElement, 100, 40, {
76+ return A3(newElement, 100, 40, {
76 ctor: 'Custom',
77 ctor: 'Custom',
77− type: 'Button',
78+ type: 'Button',
78− render: render,
79+ render: render,
79− update: update,
80+ update: update,
80− model: { event:evnt, text:JS.fromString(txt) }
81+ model: { event:evnt, text:JS.fromString(txt) }
84 return { _:{}, button:F2(button), events:events };
85 return { _:{}, button:F2(button), events:events };
@@ -88,94 +89,115 @@ Elm.Native.Graphics.Input = function(elm) {
88 var events = Signal.constant(defaultValue);
89 var events = Signal.constant(defaultValue);
90 function render(model) {
91 function render(model) {
91− var btn = newNode('div');
92+ var btn = newNode('div');
92− btn.elmEvent = model.event;
93+ btn.elmEvent = model.event;
94− btn.elmUp = Render.render(model.up);
95+ btn.elmUp = Render.render(model.up);
95− btn.elmHover = Render.render(model.hover);
96+ btn.elmHover = Render.render(model.hover);
96− btn.elmDown = Render.render(model.down);
97+ btn.elmDown = Render.render(model.down);
98− function replace(node) {
99+ function replace(node) {
99 if (node !== btn.firstChild) btn.replaceChild(node, btn.firstChild);
100 if (node !== btn.firstChild) btn.replaceChild(node, btn.firstChild);
101− var overCount = 0;
102+ var overCount = 0;
102− function over(e) {
103+ function over(e) {
103− if (overCount++ > 0) return;
104+ if (overCount++ > 0) return;
104− replace(btn.elmHover);
105+ replace(btn.elmHover);
106− function out(e) {
107+ function out(e) {
107− if (btn.contains(e.toElement || e.relatedTarget)) return;
108+ if (btn.contains(e.toElement || e.relatedTarget)) return;
108− overCount = 0;
109+ overCount = 0;
109− replace(btn.elmUp);
110+ replace(btn.elmUp);
111− function up() {
112+ function up() {
112− replace(btn.elmHover);
113+ replace(btn.elmHover);
113− elm.notify(events.id, btn.elmEvent);
114+ elm.notify(events.id, btn.elmEvent);
115− function down() { replace(btn.elmDown); }
116+ function down() { replace(btn.elmDown); }
116− btn.addEventListener('mouseover', over);
117+ btn.addEventListener('mouseover', over);
117− btn.addEventListener('mouseout' , out);
118+ btn.addEventListener('mouseout' , out);
118− btn.addEventListener('mousedown', down);
119+ btn.addEventListener('mousedown', down);
119− btn.addEventListener('mouseup' , up);
120+ btn.addEventListener('mouseup' , up);
121− btn.appendChild(btn.elmUp);
122+ btn.appendChild(btn.elmUp);
124+ var clicker = newNode('div');
125+ clicker.style.width = btn.elmUp.style.width;
126+ clicker.style.height = btn.elmUp.style.height;
127+ clicker.style.position = 'absolute';
128+ clicker.style.top = 0;
129+ btn.appendChild(clicker);
122− return btn;
131+ return btn;
125 function update(node, oldModel, newModel) {
134 function update(node, oldModel, newModel) {
126− node.elmEvent = newModel.event;
135+ node.elmEvent = newModel.event;
127− Render.update(node.elmUp, oldModel.up, newModel.up)
136+ Render.update(node.elmUp, oldModel.up, newModel.up)
128− Render.update(node.elmHover, oldModel.hover, newModel.hover)
137+ Render.update(node.elmHover, oldModel.hover, newModel.hover)
129− Render.update(node.elmDown, oldModel.down, newModel.down)
138+ Render.update(node.elmDown, oldModel.down, newModel.down)
132 function button(evnt, up, hover, down) {
141 function button(evnt, up, hover, down) {
133− return A3(newElement,
142+ return A3(newElement,
134− Math.max(up.props.width, hover.props.width, down.props.width),
143+ Math.max(up.props.width, hover.props.width, down.props.width),
135− Math.max(up.props.height, hover.props.height, down.props.height),
144+ Math.max(up.props.height, hover.props.height, down.props.height),
136 { ctor: 'Custom',
145 { ctor: 'Custom',
137− type: 'CustomButton',
146+ type: 'CustomButton',
138− render: render,
147+ render: render,
139− update: update,
148+ update: update,
140− model: { event:evnt, up:up, hover:hover, down:down }
149+ model: { event:evnt, up:up, hover:hover, down:down }
144 return { _:{}, customButton:F4(button), events:events };
153 return { _:{}, customButton:F4(button), events:events };
157+ function hoverables(defaultValue) {
158+ var events = Signal.constant(defaultValue);
159+ function hoverable(handler, elem) {
160+ function onHover(bool) {
161+ elm.notify(events.id, handler(bool));
163+ var props = Utils.replace([['hover',onHover]], elem.props);
164+ return { props:props, element:elem.element };
166+ return { _:{}, hoverable:F2(hoverable), events:events };
148 function checkboxes(defaultValue) {
170 function checkboxes(defaultValue) {
149 var events = Signal.constant(defaultValue);
171 var events = Signal.constant(defaultValue);
151 function render(model) {
173 function render(model) {
152− var b = newNode('input');
174+ var b = newNode('input');
153− b.type = 'checkbox';
175+ b.type = 'checkbox';
154− b.checked = model.checked;
176+ b.checked = model.checked;
155− b.style.display = 'block';
177+ b.style.display = 'block';
156− b.elmHandler = model.handler;
178+ b.elmHandler = model.handler;
157− function change() { elm.notify(events.id, b.elmHandler(b.checked)); }
179+ function change() { elm.notify(events.id, b.elmHandler(b.checked)); }
158− b.addEventListener('change', change);
180+ b.addEventListener('change', change);
159− return b;
181+ return b;
162 function update(node, oldModel, newModel) {
184 function update(node, oldModel, newModel) {
163− node.elmHandler = newModel.handler;
185+ node.elmHandler = newModel.handler;
164− node.checked = newModel.checked;
186+ node.checked = newModel.checked;
165− return true;
187+ return true;
168 function box(handler, checked) {
190 function box(handler, checked) {
169− return A3(newElement, 13, 13, {
191+ return A3(newElement, 13, 13, {
170 ctor: 'Custom',
192 ctor: 'Custom',
171− type: 'CheckBox',
193+ type: 'CheckBox',
172− render: render,
194+ render: render,
173− update: update,
195+ update: update,
174− model: { checked:checked, handler:handler }
196+ model: { checked:checked, handler:handler }
178− return { _:{}, box:F2(box), events:events };
200+ return { _:{}, checkbox:F2(box), events:events };
181 function setRange(node, start, end, dir) {
203 function setRange(node, start, end, dir) {
@@ -192,49 +214,49 @@ Elm.Native.Graphics.Input = function(elm) {
192 var state = null;
214 var state = null;
194 function render(model) {
216 function render(model) {
195− var field = newNode('input');
217+ var field = newNode('input');
196− field.elmHandler = model.handler;
218+ field.elmHandler = model.handler;
198− field.id = 'test';
220+ field.id = 'test';
199− field.type = type;
221+ field.type = type;
200− field.placeholder = JS.fromString(model.placeHolder);
222+ field.placeholder = JS.fromString(model.placeHolder);
201− field.value = JS.fromString(model.state.string);
223+ field.value = JS.fromString(model.state.string);
202− setRange(field, model.state.selectionStart, model.state.selectionEnd, 'forward');
224+ setRange(field, model.state.selectionStart, model.state.selectionEnd, 'forward');
203− field.style.border = 'none';
225+ field.style.border = 'none';
204 state = model.state;
226 state = model.state;
206− function update() {
228+ function update() {
207− var start = field.selectionStart,
229+ var start = field.selectionStart,
208− end = field.selectionEnd;
230+ end = field.selectionEnd;
209− if (field.selectionDirection === 'backward') {
231+ if (field.selectionDirection === 'backward') {
210− start = end;
232+ start = end;
211− end = field.selectionStart;
233+ end = field.selectionStart;
213 state = { _:{},
235 state = { _:{},
214 string:JS.toString(field.value),
236 string:JS.toString(field.value),
215 selectionStart:start,
237 selectionStart:start,
216 selectionEnd:end };
238 selectionEnd:end };
217− elm.notify(events.id, field.elmHandler(state));
239+ elm.notify(events.id, field.elmHandler(state));
219− function mousedown() {
241+ function mousedown() {
220− update();
242+ update();
221− elm.node.addEventListener('mouseup', mouseup);
243+ elm.node.addEventListener('mouseup', mouseup);
223− function mouseup() {
245+ function mouseup() {
224− update();
246+ update();
225− elm.node.removeEventListener('mouseup', mouseup)
247+ elm.node.removeEventListener('mouseup', mouseup)
227− field.addEventListener('keyup', update);
249+ field.addEventListener('keyup', update);
228− field.addEventListener('mousedown', mousedown);
250+ field.addEventListener('mousedown', mousedown);
230− return field;
252+ return field;
233 function update(node, oldModel, newModel) {
255 function update(node, oldModel, newModel) {
234− node.elmHandler = newModel.handler;
256+ node.elmHandler = newModel.handler;
235 if (state === newModel.state) return;
257 if (state === newModel.state) return;
236 var newStr = JS.fromString(newModel.state.string);
258 var newStr = JS.fromString(newModel.state.string);
237− if (node.value !== newStr) node.value = newStr;
259+ if (node.value !== newStr) node.value = newStr;
239 var start = newModel.state.selectionStart;
261 var start = newModel.state.selectionStart;
240 var end = newModel.state.selectionEnd;
262 var end = newModel.state.selectionEnd;
@@ -253,15 +275,15 @@ Elm.Native.Graphics.Input = function(elm) {
255 function field(handler, placeHolder, state) {
277 function field(handler, placeHolder, state) {
256− return A3(newElement, 200, 30,
278+ return A3(newElement, 200, 30,
257 { ctor: 'Custom',
279 { ctor: 'Custom',
258− type: type + 'Input',
280+ type: type + 'Input',
259− render: render,
281+ render: render,
260− update: update,
282+ update: update,
261− model: { handler:handler,
283+ model: { handler:handler,
262− placeHolder:placeHolder,
284+ placeHolder:placeHolder,
263− state:state }
285+ state:state }
267 return { _:{}, field:F3(field), events:events };
289 return { _:{}, field:F3(field), events:events };
@@ -271,6 +293,7 @@ Elm.Native.Graphics.Input = function(elm) {
271 return elm.Native.Graphics.Input = {
293 return elm.Native.Graphics.Input = {
272 buttons:buttons,
294 buttons:buttons,
273 customButtons:customButtons,
295 customButtons:customButtons,
296+ hoverables:hoverables,
274 checkboxes:checkboxes,
297 checkboxes:checkboxes,
275 fields:mkTextPool('text'),
298 fields:mkTextPool('text'),
276 emails:mkTextPool('email'),
299 emails:mkTextPool('email'),