on 53389ff help sign in
303 lines 9.9 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 dropDown(values) {
19 var entries = JS.fromList(values);
20 var events = Signal.constant(entries[0]._1);
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);
27 option.value = name;
28 option.innerHTML = name;
29 drop.appendChild(option);
30 }
31 drop.addEventListener('change', function() {
32 elm.notify(events.id, entries[drop.selectedIndex]._1);
33 });
35 var t = drop.cloneNode(true);
36 t.style.visibility = "hidden";
38 elm.node.appendChild(t);
39 var style = window.getComputedStyle(t, null);
40 var w = Math.ceil(style.getPropertyValue("width").slice(0,-2) - 0);
41 var h = Math.ceil(style.getPropertyValue("height").slice(0,-2) - 0);
42 elm.node.removeChild(t);
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 });
52 return Tuple2(Signal.constant(element), events);
53 }
55 function buttons(defaultValue) {
56 var events = Signal.constant(defaultValue);
58 function render(model) {
59 var b = newNode('button');
60 b.style.display = 'block';
61 b.elmEvent = model.event;
62 function click() { elm.notify(events.id, b.elmEvent); }
63 b.addEventListener('click', click);
64 b.innerHTML = model.text;
65 return b;
66 }
68 function update(node, oldModel, newModel) {
69 node.elmEvent = newModel.event;
70 var txt = newModel.text;
71 if (oldModel.text !== txt) node.innerHTML = txt;
72 }
74 function button(evnt, txt) {
75 return A3(newElement, 100, 40, {
76 ctor: 'Custom',
77 type: 'Button',
78 render: render,
79 update: update,
80 model: { event:evnt, text:JS.fromString(txt) }
81 });
82 }
84 return { _:{}, button:F2(button), events:events };
85 }
87 function customButtons(defaultValue) {
88 var events = Signal.constant(defaultValue);
90 function render(model) {
91 var btn = newNode('div');
92 btn.elmEvent = model.event;
94 btn.elmUp = Render.render(model.up);
95 btn.elmHover = Render.render(model.hover);
96 btn.elmDown = Render.render(model.down);
98 function replace(node) {
99 if (node !== btn.firstChild) btn.replaceChild(node, btn.firstChild);
100 }
101 var overCount = 0;
102 function over(e) {
103 if (overCount++ > 0) return;
104 replace(btn.elmHover);
105 }
106 function out(e) {
107 if (btn.contains(e.toElement || e.relatedTarget)) return;
108 overCount = 0;
109 replace(btn.elmUp);
110 }
111 function up() {
112 replace(btn.elmHover);
113 elm.notify(events.id, btn.elmEvent);
114 }
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);
130 return btn;
131 }
133 function update(node, oldModel, newModel) {
134 node.elmEvent = newModel.event;
135 Render.update(node.elmUp, oldModel.up, newModel.up)
136 Render.update(node.elmHover, oldModel.hover, newModel.hover)
137 Render.update(node.elmDown, oldModel.down, newModel.down)
138 }
140 function button(evnt, up, hover, down) {
141 return A3(newElement,
142 Math.max(up.props.width, hover.props.width, down.props.width),
143 Math.max(up.props.height, hover.props.height, down.props.height),
144 { ctor: 'Custom',
145 type: 'CustomButton',
146 render: render,
147 update: update,
148 model: { event:evnt, up:up, hover:hover, down:down }
149 });
150 }
152 return { _:{}, customButton:F4(button), events:events };
153 }
156 function hoverables(defaultValue) {
157 var events = Signal.constant(defaultValue);
158 function hoverable(handler, elem) {
159 function onHover(bool) {
160 elm.notify(events.id, handler(bool));
161 }
162 var props = Utils.replace([['hover',onHover]], elem.props);
163 return { props:props, element:elem.element };
164 }
165 return { _:{}, hoverable:F2(hoverable), events:events };
166 }
169 function checkboxes(defaultValue) {
170 var events = Signal.constant(defaultValue);
172 function render(model) {
173 var b = newNode('input');
174 b.type = 'checkbox';
175 b.checked = model.checked;
176 b.style.display = 'block';
177 b.elmHandler = model.handler;
178 function change() { elm.notify(events.id, b.elmHandler(b.checked)); }
179 b.addEventListener('change', change);
180 return b;
181 }
183 function update(node, oldModel, newModel) {
184 node.elmHandler = newModel.handler;
185 node.checked = newModel.checked;
186 return true;
187 }
189 function box(handler, checked) {
190 return A3(newElement, 13, 13, {
191 ctor: 'Custom',
192 type: 'CheckBox',
193 render: render,
194 update: update,
195 model: { checked:checked, handler:handler }
196 });
197 }
199 return { _:{}, checkbox:F2(box), events:events };
200 }
202 function setRange(node, start, end, dir) {
203 if (node.parentNode) {
204 node.setSelectionRange(start, end, dir);
205 } else {
206 setTimeout(function(){node.setSelectionRange(start, end, dir);}, 0);
207 }
208 }
210 function mkTextPool(type) { return function fields(defaultValue) {
211 var events = Signal.constant(defaultValue);
213 var state = null;
215 function render(model) {
216 var field = newNode('input');
217 field.elmHandler = model.handler;
219 field.id = 'test';
220 field.type = type;
221 field.placeholder = JS.fromString(model.placeHolder);
222 field.value = JS.fromString(model.state.string);
223 setRange(field, model.state.selectionStart, model.state.selectionEnd, 'forward');
224 field.style.border = 'none';
225 state = model.state;
227 function update() {
228 var start = field.selectionStart,
229 end = field.selectionEnd;
230 if (field.selectionDirection === 'backward') {
231 start = end;
232 end = field.selectionStart;
233 }
234 state = { _:{},
235 string:JS.toString(field.value),
236 selectionStart:start,
237 selectionEnd:end };
238 elm.notify(events.id, field.elmHandler(state));
239 }
240 function mousedown() {
241 update();
242 elm.node.addEventListener('mouseup', mouseup);
243 }
244 function mouseup() {
245 update();
246 elm.node.removeEventListener('mouseup', mouseup)
247 }
248 field.addEventListener('keyup', update);
249 field.addEventListener('mousedown', mousedown);
251 return field;
252 }
254 function update(node, oldModel, newModel) {
255 node.elmHandler = newModel.handler;
256 if (state === newModel.state) return;
257 var newStr = JS.fromString(newModel.state.string);
258 if (node.value !== newStr) node.value = newStr;
260 var start = newModel.state.selectionStart;
261 var end = newModel.state.selectionEnd;
262 var direction = 'forward';
263 if (end < start) {
264 start = end;
265 end = newModel.state.selectionStart;
266 direction = 'backward';
267 }
269 if (node.selectionStart !== start
270 || node.selectionEnd !== end
271 || node.selectionDirection !== direction) {
272 setRange(node, start, end, direction);
273 }
274 }
276 function field(handler, placeHolder, state) {
277 return A3(newElement, 200, 30,
278 { ctor: 'Custom',
279 type: type + 'Input',
280 render: render,
281 update: update,
282 model: { handler:handler,
283 placeHolder:placeHolder,
284 state:state }
285 });
286 }
288 return { _:{}, field:F3(field), events:events };
289 }
290 }
292 return elm.Native.Graphics.Input.values = {
293 buttons:buttons,
294 customButtons:customButtons,
295 hoverables:hoverables,
296 checkboxes:checkboxes,
297 fields:mkTextPool('text'),
298 emails:mkTextPool('email'),
299 passwords:mkTextPool('password'),
300 dropDown:dropDown
301 };
303};