on 1c832af help sign in
316 lines 10 kB history raw
1Elm.Native.Graphics.Input = {};
2Elm.Native.Graphics.Input.make = function(elm) {
4 elm.Native = elm.Native || {};
5 elm.Native.Graphics = elm.Native.Graphics || {};
6 elm.Native.Graphics.Input = elm.Native.Graphics.Input || {};
7 if (elm.Native.Graphics.Input.values) return elm.Native.Graphics.Input.values;
9 var Render = ElmRuntime.use(ElmRuntime.Render.Element);
10 var newNode = ElmRuntime.use(ElmRuntime.Render.Utils).newElement;
12 var Signal = Elm.Signal.make(elm);
13 var newElement = Elm.Graphics.Element.make(elm).newElement;
14 var JS = Elm.Native.JavaScript.make(elm);
15 var Utils = Elm.Native.Utils.make(elm);
16 var Tuple2 = Utils.Tuple2;
18 function input(initialValue) {
19 var sig = Signal.constant(initialValue);
20 return Tuple2(sig, sig);
21 }
23 function renderDropDown(signal, values) {
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);
32 option.value = name;
33 option.innerHTML = name;
34 drop.appendChild(option);
35 }
36 drop.addEventListener('change', function() {
37 elm.notify(signal.id, entries[drop.selectedIndex]._1);
38 });
40 var t = drop.cloneNode(true);
41 t.style.visibility = "hidden";
43 elm.node.appendChild(t);
44 var style = window.getComputedStyle(t, null);
45 var w = Math.ceil(style.getPropertyValue("width").slice(0,-2) - 0);
46 var h = Math.ceil(style.getPropertyValue("height").slice(0,-2) - 0);
47 elm.node.removeChild(t);
48 return drop;
49 };
50 }
52 function updateDropDown(node, oldModel, newModel) {
53 }
55 function dropDown(signal, values) {
56 return A3(newElement, w, h, {
57 ctor: 'Custom',
58 type: 'DropDown',
59 render: renderDropDown(signal,values),
60 update: updateDropDown,
61 model: {}
62 });
63 }
65 function renderButton(model) {
66 var node = newNode('button');
67 node.style.display = 'block';
68 node.elm_signal = model.signal;
69 node.elm_value = model.value;
70 function click() {
71 elm.notify(node.elm_signal.id, node.elm_value);
72 }
73 node.addEventListener('click', click);
74 node.innerHTML = model.text;
75 return node;
76 }
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;
83 }
85 function button(signal, value, text) {
86 return A3(newElement, 100, 40, {
87 ctor: 'Custom',
88 type: 'Button',
89 render: renderButton,
90 update: updateButton,
91 model: { signal:signal, value:value, text:JS.fromString(text) }
92 });
93 }
95 function renderCustomButton(model) {
96 var btn = newNode('div');
97 btn.elm_value = model.value;
99 btn.elm_up = Render.render(model.up);
100 btn.elm_hover = Render.render(model.hover);
101 btn.elm_down = Render.render(model.down);
103 function replace(node) {
104 if (node !== btn.firstChild) {
105 btn.replaceChild(node, btn.firstChild);
106 }
107 }
108 var overCount = 0;
109 function over(e) {
110 if (overCount++ > 0) return;
111 replace(btn.elm_hover);
112 }
113 function out(e) {
114 if (btn.contains(e.toElement || e.relatedTarget)) return;
115 overCount = 0;
116 replace(btn.elm_up);
117 }
118 function up() {
119 replace(btn.elm_hover);
120 elm.notify(btn.elm_signal.id, btn.elm_value);
121 }
122 function down() {
123 replace(btn.elm_down);
124 }
125 btn.addEventListener('mouseover', over);
126 btn.addEventListener('mouseout' , out);
127 btn.addEventListener('mousedown', down);
128 btn.addEventListener('mouseup' , up);
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);
139 return btn;
140 }
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)
148 }
150 function max3(a,b,c) {
151 var ab = a > b ? a : b;
152 return ab > c ? ab : c;
153 }
155 function customButton(signal, value, up, hover, down) {
156 return A3(newElement,
157 max3(up.props.width, hover.props.width, down.props.width),
158 max3(up.props.height, hover.props.height, down.props.height),
159 { ctor: 'Custom',
160 type: 'CustomButton',
161 render: renderCustomButton,
162 update: updateCustomButton,
163 model: { signal:signal, value:value, up:up, hover:hover, down:down }
164 });
165 }
167 function renderCheckbox(model) {
168 var node = newNode('input');
169 node.type = 'checkbox';
170 node.checked = model.checked;
171 node.style.display = 'block';
172 node.elm_signal = model.signal;
173 node.elm_handler = model.handler;
174 function change() {
175 elm.notify(node.elm_signal.id, node.elm_handler(node.checked));
176 }
177 node.addEventListener('change', change);
178 return node;
179 }
181 function updateCheckbox(node, oldModel, newModel) {
182 node.elm_signal = newModel.signal;
183 node.elm_handler = newModel.handler;
184 node.checked = newModel.checked;
185 return true;
186 }
188 function checkbox(signal, handler, checked) {
189 return A3(newElement, 13, 13, {
190 ctor: 'Custom',
191 type: 'CheckBox',
192 render: renderCheckbox,
193 update: updateCheckbox,
194 model: { signal:signal, handler:handler, checked:checked }
195 });
196 }
198 function setRange(node, start, end, dir) {
199 if (node.parentNode) {
200 node.setSelectionRange(start, end, dir);
201 } else {
202 setTimeout(function(){node.setSelectionRange(start, end, dir);}, 0);
203 }
204 }
206 function renderField(model) {
207 var field = newNode('input');
208 field.elm_signal = model.signal;
209 field.elm_handler = model.handler;
211 field.id = 'test';
212 field.type = type;
213 field.placeholder = JS.fromString(model.placeHolder);
214 field.value = JS.fromString(model.state.string);
215 setRange(field, model.state.selectionStart, model.state.selectionEnd, 'forward');
216 field.style.border = 'none';
217 state = model.state;
219 function update() {
220 var start = field.selectionStart;
221 var end = field.selectionEnd;
222 if (field.selectionDirection === 'backward') {
223 start = end;
224 end = field.selectionStart;
225 }
226 elm.notify(events.id, field.elm_handler({
227 _:{},
228 string:JS.toString(field.value),
229 selectionStart:start,
230 selectionEnd:end
231 }));
232 }
233 function mousedown() {
234 update();
235 elm.node.addEventListener('mouseup', mouseup);
236 }
237 function mouseup() {
238 update();
239 elm.node.removeEventListener('mouseup', mouseup)
240 }
241 field.addEventListener('keyup', update);
242 field.addEventListener('mousedown', mousedown);
244 return field;
245 }
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;
252 var start = newModel.state.selectionStart;
253 var end = newModel.state.selectionEnd;
254 var direction = 'forward';
255 if (end < start) {
256 start = end;
257 end = newModel.state.selectionStart;
258 direction = 'backward';
259 }
261 if (node.selectionStart !== start
262 || node.selectionEnd !== end
263 || node.selectionDirection !== direction) {
264 setRange(node, start, end, direction);
265 }
266 }
268 function mkField(type) {
269 function field(signal, handler, placeHolder, state) {
270 return A3(newElement, 200, 30, {
271 ctor: 'Custom',
272 type: type + 'Input',
273 render: render,
274 update: update,
275 model: {
276 signal:signal,
277 handler:handler,
278 placeHolder:placeHolder,
279 state:state
280 }
281 });
282 }
283 return F4(field);
284 }
287 function hoverable(signal, handler, element) {
288 function onHover(bool) {
289 elm.notify(signal.id, handler(bool));
290 }
291 var props = Utils.replace([['hover',onHover]], elem.props);
292 return { props:props, element:elem.element };
293 }
295 function clickable(signal, value, element) {
296 function onClick(bool) {
297 elm.notify(signal.id, value);
298 }
299 var props = Utils.replace([['click',onClick]], elem.props);
300 return { props:props, element:elem.element };
301 }
303 return elm.Native.Graphics.Input.values = {
304 input:input,
305 button:F3(button),
306 customButton:F5(customButton),
307 checkbox:F3(checkbox),
308 dropDown:F2(dropDown),
309 field:mkField('text'),
310 email:mkField('email'),
311 password:mkField('password'),
312 hoverable:F3(hoverable),
313 clickable:F3(clickable)
314 };
316};