on 5714764 help sign in
242 lines 6.8 kB history raw
2Elm.Native.Graphics.Input = function(elm) {
3 "use strict";
5 elm.Native = elm.Native || {};
6 elm.Native.Graphics = elm.Native.Graphics || {};
7 if (elm.Native.Graphics.Input) return elm.Native.Graphics.Input;
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;
14 var Signal = Elm.Signal(elm);
15 var newElement = Elm.Graphics.Element(elm).newElement;
17 function buttons(defaultValue) {
18 var events = Signal.constant(defaultValue);
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 }
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 }
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 }
46 return { _:{}, button:F2(button), events:events };
47 }
49 function customButtons(defaultValue) {
50 var events = Signal.constant(defaultValue);
52 function render(model) {
53 var btn = newNode('div');
54 btn.elmEvent = model.event;
56 btn.elmUp = Render.render(model.up);
57 btn.elmHover = Render.render(model.hover);
58 btn.elmDown = Render.render(model.down);
60 function replace(node) {
61 if (node !== btn.firstChild) btn.replaceChild(node, btn.firstChild);
62 }
63 var overCount = 0;
64 function over(e) {
65 if (overCount++ > 0) return;
66 replace(btn.elmHover);
67 }
68 function out(e) {
69 if (btn.contains(e.toElement || e.relatedTarget)) return;
70 overCount = 0;
71 replace(btn.elmUp);
72 }
73 function up() {
74 replace(btn.elmHover);
75 elm.notify(events.id, btn.elmEvent);
76 }
77 function down() { replace(btn.elmDown); }
78 btn.addEventListener('mouseover', over);
79 btn.addEventListener('mouseout' , out);
80 btn.addEventListener('mousedown', down);
81 btn.addEventListener('mouseup' , up);
83 btn.appendChild(btn.elmUp);
84 return btn;
85 }
87 function update(node, oldModel, newModel) {
88 node.elmEvent = newModel.event;
89 Render.update(node.elmUp, oldModel.up, newModel.up)
90 Render.update(node.elmHover, oldModel.hover, newModel.hover)
91 Render.update(node.elmDown, oldModel.down, newModel.down)
92 }
94 function button(evnt, up, hover, down) {
95 return A3(newElement,
96 Math.max(up.props.width, hover.props.width, down.props.width),
97 Math.max(up.props.height, hover.props.height, down.props.height),
98 { ctor: 'Custom',
99 type: 'CustomButton',
100 render: render,
101 update: update,
102 model: { event:evnt, up:up, hover:hover, down:down }
103 });
104 }
106 return { _:{}, customButton:F4(button), events:events };
107 }
110 function checkboxes(defaultValue) {
111 var events = Signal.constant(defaultValue);
113 function render(model) {
114 var b = newNode('input');
115 b.type = 'checkbox';
116 b.checked = model.checked;
117 b.style.display = 'block';
118 b.elmHandler = model.handler;
119 function change() { elm.notify(events.id, b.elmHandler(b.checked)); }
120 b.addEventListener('change', change);
121 return b;
122 }
124 function update(node, oldModel, newModel) {
125 node.elmHandler = newModel.handler;
126 node.checked = newModel.checked;
127 return true;
128 }
130 function box(handler, checked) {
131 return A3(newElement, 13, 13, {
132 ctor: 'Custom',
133 type: 'CheckBox',
134 render: render,
135 update: update,
136 model: { checked:checked, handler:handler }
137 });
138 }
140 return { _:{}, box:F2(box), events:events };
141 }
143 function setRange(node, start, end, dir) {
144 if (node.parentNode) {
145 node.setSelectionRange(start, end, dir);
146 } else {
147 setTimeout(function(){node.setSelectionRange(start, end, dir);}, 0);
148 }
149 }
151 function mkTextPool(type) { return function fields(defaultValue) {
152 var events = Signal.constant(defaultValue);
154 var state = null;
156 function render(model) {
157 var field = newNode('input');
158 field.elmHandler = model.handler;
160 field.id = 'test';
161 field.type = type;
162 field.placeholder = fromString(model.placeHolder);
163 field.value = fromString(model.state.string);
164 setRange(field, model.state.selectionStart, model.state.selectionEnd, 'forward');
165 field.style.border = 'none';
166 state = model.state;
168 function update() {
169 var start = field.selectionStart,
170 end = field.selectionEnd;
171 if (field.selectionDirection === 'backward') {
172 start = end;
173 end = field.selectionStart;
174 }
175 state = { _:{},
176 string:toString(field.value),
177 selectionStart:start,
178 selectionEnd:end };
179 elm.notify(events.id, field.elmHandler(state));
180 }
181 function mousedown() {
182 update();
183 elm.node.addEventListener('mouseup', mouseup);
184 }
185 function mouseup() {
186 update();
187 elm.node.removeEventListener('mouseup', mouseup)
188 }
189 field.addEventListener('keyup', update);
190 field.addEventListener('mousedown', mousedown);
192 return field;
193 }
195 function update(node, oldModel, newModel) {
196 node.elmHandler = newModel.handler;
197 if (state === newModel.state) return;
198 var newStr = fromString(newModel.state.string);
199 if (node.value !== newStr) node.value = newStr;
201 var start = newModel.state.selectionStart;
202 var end = newModel.state.selectionEnd;
203 var direction = 'forward';
204 if (end < start) {
205 start = end;
206 end = newModel.state.selectionStart;
207 direction = 'backward';
208 }
210 if (node.selectionStart !== start
211 || node.selectionEnd !== end
212 || node.selectionDirection !== direction) {
213 setRange(node, start, end, direction);
214 }
215 }
217 function field(handler, placeHolder, state) {
218 return A3(newElement, 200, 30,
219 { ctor: 'Custom',
220 type: type + 'Input',
221 render: render,
222 update: update,
223 model: { handler:handler,
224 placeHolder:placeHolder,
225 state:state }
226 });
227 }
229 return { _:{}, field:F3(field), events:events };
230 }
231 }
233 return elm.Native.Graphics.Input = {
234 buttons:buttons,
235 customButtons:customButtons,
236 checkboxes:checkboxes,
237 fields:mkTextPool('text'),
238 emails:mkTextPool('email'),
239 passwords:mkTextPool('password')
240 };
242};