@@ -1,367 +1,143 @@
11
2−var Signal = function() {
3− function wrap(elem) {
4− var p = Value.getSize(elem);
5− return ["Element", Guid.guid(), ["EHtml",elem], p[0], p[1], 1, Nothing, Nothing];
6− }
7− function toElmString(str) {
8− var out = ["Nil"];
9− for (var i = str.length; i--; ) {
10− out = ["Cons", str[i], out];
11− }
12− return out;
13− }
14− var addListener = function() {
15− if(document.addEventListener) {
16− return function(element, event, handler) {
17− element.addEventListener(event, handler, false);
18− };
19− }
20− else {
21− return function(element, event, handler) {
22− element.attachEvent('on' + event, handler);
23− };
24− }
25− }();
26−
27− var Mouse = function() {
28− var position = Elm.Input(Value.Tuple(0,0));
29− position.defaultNumberOfKids = 2;
30−
31− var x = Elm.Lift(function(p){return p[1];},[position]);
32− x.defaultNumberOfKids = 0;
33− var y = Elm.Lift(function(p){return p[2];},[position]);
34− y.defaultNumberOfKids = 0;
35−
36− var isDown = Elm.Input(false);
37− var isClicked = Elm.Input(false);
38− var clicks = Elm.Input(Value.Tuple());
2+var Elm = Elm || {};
3+Elm.Signal = function() {
4+ var send = function(node, timestep, changed) {
5+ var kids = node.kids;
6+ for (var i = kids.length; i--; ) {
7+ kids[i].recv(timestep, changed, node.id);
8+ }
9+ };
10+ var input = function(base) {
11+ this.id = Guid.guid();
12+ this.value = base;
13+ this.kids = [];
14+ this.defaultNumberOfKids = 0;
15+ this.recv = function(timestep, eid, v) {
16+ var changed = eid === this.id;
17+ if (changed) { this.value = v; }
18+ send(this, timestep, changed);
19+ return changed;
20+ };
21+ Dispatcher.inputs.push(this);
22+ };
23+ var lift = function(func,args) {
24+ this.id = Guid.guid();
25+ this.value = null;
26+ this.kids = [];
27+ this.count = 0;
28+ this.changed = false;
29+
30+ args.reverse();
31+ this.recalc = function() {
32+ var f = func;
33+ for (var i = args.length; i--; ) {
34+ f = f(args[i].value);
35+ }
36+ this.value = f;
37+ };
38+ this.recalc();
3939
40− function getXY(e) {
41− var posx = 0;
42− var posy = 0;
43− if (!e) var e = window.event;
44− if (e.pageX || e.pageY) {
45− posx = e.pageX;
46− posy = e.pageY;
47− } else if (e.clientX || e.clientY) {
48− posx = e.clientX + document.body.scrollLeft +
49− document.documentElement.scrollLeft;
50− posy = e.clientY + document.body.scrollTop +
51− document.documentElement.scrollTop;
40+ this.recv = function(timestep, changed, parentID) {
41+ this.count += 1;
42+ if (changed) { this.changed = true; }
43+ if (this.count == args.length) {
44+ if (this.changed) { this.recalc() }
45+ send(this, timestep, this.changed);
46+ this.changed = false;
47+ this.count = 0;
5248 }
53− return Value.Tuple(posx, posy);
49+ };
50+ for (var i = args.length; i--; ) {
51+ args[i].kids.push(this);
5452 }
55−
56− addListener(document, 'click', function(e) {
57− var hasListener1 = Dispatcher.notify(isClicked.id, true);
58− var hasListener2 = Dispatcher.notify(clicks.id, Value.Tuple());
59− Dispatcher.notify(isClicked.id, false);
60− if (!hasListener1 && !hasListener2)
61− this.removeEventListener('click',arguments.callee,false);
62− });
63− addListener(document, 'mousedown', function(e) {
64− var hasListener = Dispatcher.notify(isDown.id, true);
65− if (!hasListener)
66− this.removeEventListener('mousedown',arguments.callee,false);
67− });
68− addListener(document, 'mouseup', function(e) {
69− var hasListener = Dispatcher.notify(isDown.id, false);
70− if (!hasListener)
71− this.removeEventListener('mouseup',arguments.callee,false);
72− });
73− addListener(document, 'mousemove', function(e) {
74− var hasListener = Dispatcher.notify(position.id, getXY(e));
75− if (!hasListener)
76− this.removeEventListener('mousemove',arguments.callee,false);
77− });
78− var clickedOn = function(elem) {
79− var node = Render.render(elem);
80− var click = Elm.Input(false);
81− addListener(node, 'click', function(e) {
82− Dispatcher.notify(click.id, true);
83− Dispatcher.notify(click.id, false);
84− });
85− return Value.Tuple(wrap(node), click);
53+ };
54+ var fold = function(func,base,baseIsFunc,input) {
55+ this.id = Guid.guid();
56+ this.value = baseIsFunc ? base(input.value) : base;
57+ this.kids = [];
58+ this.recv = function(timestep, changed, parentID) {
59+ if (changed) { this.value = func(input.value)(this.value); }
60+ send(this, timestep, changed);
8661 };
87− return {position: position,
88− x:x,
89− y:y,
90− isClicked: isClicked,
91− isDown: isDown,
92− clicks: clicks,
93− isClickedOn: clickedOn
94− };
95− }();
62+ input.kids.push(this);
63+ };
9664
97− var Time = function() {
98− var every = function(t) {
99− t *= 1000;
100− var clock = Elm.Input(0);
101− var time = 0;
102− setInterval(function() {
103− time += t;
104− Dispatcher.notify(clock.id, time/1000);
105− }, t);
106− return clock;
107− };
108− var after = function(t) {
109− t *= 1000;
110− var thread = Elm.Input(false);
111− setTimeout(function() { Dispatcher.notify(thread.id, true); }, t);
112− return thread;
113− };
114− var before = function(t) {
115− t *= 1000;
116− var thread = Elm.Input(true);
117− setTimeout(function() { Dispatcher.notify(thread.id, false); }, t);
118− return thread;
65+ var dropIf = function(pred,base,input) {
66+ this.id = Guid.guid();
67+ this.value = pred(input.value) ? base : input.value;
68+ this.kids = [];
69+ this.recv = function(timestep, changed, parentID) {
70+ var chng = changed && !pred(input.value);
71+ if (chng) { this.value = input.value; }
72+ send(this, timestep, chng);
73+ };
74+ input.kids.push(this);
75+ };
76+ var dropRepeats = function(input) {
77+ this.id = Guid.guid();
78+ this.value = input.value;
79+ this.kids = [];
80+ this.recv = function(timestep, changed, parentID) {
81+ var chng = changed && !eq(this.value,input.value);
82+ if (chng) { this.value = input.value; }
83+ send(this, timestep, chng);
11984 };
120− return {every:every,after:after,before:before};
121− }();
122−
123− var Window = function() {
124− var dimensions = Elm.Input(Value.Tuple(window.innerWidth,window.innerHeight));
125− dimensions.defaultNumberOfKids = 2;
126−
127− var width = Elm.Lift(function(p){return p[1];},[dimensions]);
128− width.defaultNumberOfKids = 0;
129− var height = Elm.Lift(function(p){return p[2];},[dimensions]);
130− height.defaultNumberOfKids = 0;
131−
132− addListener(window, 'resize', function(e) {
133− var w = document.getElementById('widthChecker').offsetWidth;
134− var hasListener = Dispatcher.notify(dimensions.id, Value.Tuple(w, window.innerHeight));
135− if (!hasListener)
136− this.removeEventListener('resize',arguments.callee,false);
137− });
138− return {dimensions:dimensions,width:width,height:height};
139− }();
140−
141− var Keyboard = { Raw : function() {
142− var keysDown = Elm.Input(["Nil"]);
143− var charPressed = Elm.Input(["Nothing"]);
144− function remove(x,xs) {
145− if (xs[0] === "Nil") return xs;
146− if (xs[1] === x) return xs[2];
147− return ["Cons", xs[1], remove(x,xs[2])];
148− }
149− function has(x,xs) {
150− while (xs[0] !== "Nil") {
151− if (xs[1] === x) return true;
152− xs = xs[2];
153− }
154− return false;
155− }
156− addListener(document, 'keydown', function(e) {
157− if (has(e.keyCode, keysDown.value)) return;
158− var hasListener = Dispatcher.notify(keysDown.id, ["Cons", e.keyCode, keysDown.value]);
159− if (!hasListener)
160− this.removeEventListener('keydown',arguments.callee,false);
161− });
162− addListener(document, 'keyup', function(e) {
163− var codes = remove(e.keyCode, keysDown.value);
164− var hasListener = Dispatcher.notify(keysDown.id, codes);
165− if (!hasListener)
166− this.removeEventListener('keyup',arguments.callee,false);
167− });
168− addListener(window, 'blur', function(e) {
169− var hasListener = Dispatcher.notify(keysDown.id, ["Nil"]);
170− if (!hasListener)
171− this.removeEventListener('blur',arguments.callee,false);
172− });
173− addListener(document, 'keypress', function(e) {
174− var hasListener = Dispatcher.notify(charPressed.id, ["Just",e.charCode || e.keyCode]);
175− Dispatcher.notify(charPressed.id, ["Nothing"]);
176− if (!hasListener)
177− this.removeEventListener('keypress',arguments.callee,false);
178− });
179− return {keysDown:keysDown,
180− charPressed:charPressed};
181− }()
85+ input.kids.push(this);
86+ };
87+
88+ var dropWhen = function(s1) { return function(b) { return function(s2) {
89+ var pairs = new lift(function(x){return function(y){return [x,y];};},[s1,s2]);
90+ var dropped = new dropIf(function(p){return p[0];},[true,b],pairs);
91+ return new lift(function(p){return p[1];},[dropped]); }; };
18292 };
18393
184− var HTTP = function() {
185−
186− function request(verb) { return function(url) { return function(data) {
187− return function(headers) {
188− return {0 : "Request",
189− length : 1,
190− verb : Foreign.JavaScript.castStringToJSString(verb),
191− url : Foreign.JavaScript.castStringToJSString(url),
192− data : data === null ? null : Foreign.JavaScript.castStringToJSString(data),
193− headers : headers }; }; }; };
194− }
195− function get(url) { return request("GET")(url)(null)(["Nil"]); }
196− function post(url) { return function(data) {
197− return request("POST")(url)(data)(["Nil"]); }; }
198−
199− function sendReq(responses) { return function(req) {
200− Dispatcher.notify(responses.id,["Waiting"]);
201− var request = null;
202− if (window.XMLHttpRequest) {
203− request = new XMLHttpRequest();
204− } else if (window.ActiveXObject) {
205− request = new ActiveXObject("Microsoft.XMLHTTP");
206− }
207− request.onreadystatechange = function(e) {
208− if (request.readyState === 4) {
209− Dispatcher.notify(
210− responses.id,
211− request.status === 200
212− ? ["Success", toElmString(request.responseText)]
213− : ["Failure", request.status, toElmString(request.statusText)]);
94+ var sampleOn = function(s1,s2) {
95+ this.id = Guid.guid();
96+ this.value = s2.value;
97+ this.kids = [];
98+ this.count = 0;
99+ this.changed = false;
100+
101+ this.recv = function(timestep, changed, parentID) {
102+ if (parentID === s1.id) this.changed = changed;
103+ this.count += 1;
104+ if (this.count == 2) {
105+ if (this.changed) { this.value = s2.value; }
106+ send(this, timestep, this.changed);
107+ this.count = 0;
108+ this.changed = false;
214109 }
215− };
216− request.open(req.verb, req.url, true);
217− List.map(function(pair) {
218− request.setRequestHeader(
219− Foreign.JavaScript.castStringToJSString(pair[1]),
220− Foreign.JavaScript.castStringToJSString(pair[2]));
221− })(req.headers);
222− request.send(req.data);
223− return null;
224− };
225− }
226−
227− function send(requests) {
228− var responses = Elm.Input(["Waiting"]);
229− var sender = Elm.Lift(sendReq(responses), [requests]);
230− var combine = Elm.Lift(function(x){return function(y){return x;}},
231− [responses,sender]);
232− return combine;
233− }
234−
235− return {get : get,
236− post : post,
237− request : request,
238− send : send,
239− sendGet : function(urls){return send(Elm.Lift(get,[urls]));}
240− };
241− }();
242− var Random = function() {
243− var inRange = function(min) { return function(max) {
244− return Elm.Input(Math.floor(Math.random() * (max-min+1)) + min);
245− };
246− };
247− var randomize = function(min) { return function(max) { return function(signal) {
248− return Elm.Lift(function(x) { return Math.floor(Math.random() * (max-min+1)) + min;},[signal]);
249− };
250− };
251− };
252− return { inRange:inRange, randomize:randomize };
253− }();
254− var Input = function() {
255− var newTextInput = function(elem, ghostText) {
256− elem.placeholder = Foreign.JavaScript.castStringToJSString(ghostText);
257− var str = Elm.Input(["Nil"]);
258− addListener(elem, 'keyup', function(e) {
259− Dispatcher.notify(str.id, toElmString(elem.value));
260− elem.focus();
261− });
262− elem.style.padding = "1px";
263− return Value.Tuple(wrap(elem), str);
264− };
265− var newElement = function(name) {
266− var e = document.createElement(name);
267− e.style.padding = "0";
268− e.style.margin = "0";
269− return e;
270− };
271− var textArea = function(cols) { return function(rows) {
272− var textarea = newElement('textarea');
273− textarea.rows = rows;
274− textarea.cols = cols;
275− return newTextInput(textarea, "");
276− };
277− };
278− var textField = function(ghostText) {
279− var field = newElement('input');
280− field.type = 'text';
281− return newTextInput(field, ghostText);
282− };
283− var password = function(ghostText) {
284− var field = newElement('input');
285− field.type = 'password';
286− return newTextInput(field, ghostText);
287− };
288− var checkbox = function(checked) {
289− var box = newElement('input');
290− box.type = 'checkbox';
291− box.checked = checked;
292− var status = Elm.Input(checked);
293− addListener(box, 'change', function(e) {
294− Dispatcher.notify(status.id, box.checked);
295− });
296− return Value.Tuple(wrap(box), status);
297− };
298− var dropDown = function(options) {
299− var slct = newElement('select');
300− var opts = [];
301− while (options[0] === "Cons") {
302− var opt = newElement('option');
303− var str = Text.toText(options[1][1]);
304− opt.value = str;
305− opt.innerHTML = str;
306− slct.appendChild(opt);
307− opts.push(options[1][2]);
308− options = options[2];
309− }
310− var status = Elm.Input(opts[0]);
311− addListener(slct, 'change', function(e) {
312− Dispatcher.notify(status.id, opts[slct.selectedIndex]);
313− });
314− return Value.Tuple(wrap(slct), status);
315− };
316− var stringDropDown = function(opts) {
317− return dropDown(List.map (function(x) {return Value.Tuple(x,x);}) (opts));
318− };
319− var button = function(name) {
320− var b = newElement('input');
321− b.type = "button";
322− b.value = Foreign.JavaScript.castStringToJSString(name);
323− var press = Elm.Input(false);
324− addListener(b, 'click', function(e) {
325− Dispatcher.notify(press.id, true);
326− Dispatcher.notify(press.id, false);
327− });
328− return Value.Tuple(wrap(b),press);
329− };
330− return {textArea:textArea, textField:textField,
331− password:password, checkbox:checkbox,
332− dropDown:dropDown, stringDropDown:stringDropDown,
333− button:button};
334− }();
335−
336− return {addListener:addListener,
337− Mouse:Mouse,
338− Keyboard:Keyboard,
339− Time:Time,
340− Window:Window,
341− HTTP:HTTP,
342− Random:Random,
343− Input:Input,
344− constant : function(v) { return Elm.Input(v); },
345− lift : function(f){return function(e){return Elm.Lift(f,[e]);};},
346− lift2 : function(f) { return function(e1) { return function(e2) {
347− return Elm.Lift(f, [e1,e2]); }; }; },
348− lift3 : function(f) { return function(e1) { return function(e2) {
349− return function(e3){return Elm.Lift(f,[e1,e2,e3]);};};};},
350− lift4 : function(f) { return function(e1) { return function(e2) {
110+ };
111+ s1.kids.push(this);
112+ s2.kids.push(this);
113+ };
114+
115+ return {
116+ constant : function(v) { return new input(v); },
117+ lift : function(f){return function(e){return new lift(f,[e]);};},
118+ lift2 : function(f) { return function(e1) { return function(e2) {
119+ return new lift(f, [e1,e2]); }; }; },
120+ lift3 : function(f) { return function(e1) { return function(e2) {
121+ return function(e3){return new lift(f,[e1,e2,e3]);};};};},
122+ lift4 : function(f) { return function(e1) { return function(e2) {
351123 return function(e3) { return function(e4) {
352− return Elm.Lift(f, [e1,e2,e3,e4]); }; }; }; }; },
353− foldp : function(f) { return function(b) { return function(e) {
354− return Elm.Fold(f,b,e); }; }; },
355− foldp_ : function(f) { return function(b) { return function(e) {
356− return Elm.Fold1(f,b,e); }; }; },
357− foldp1 : function(f) { return function(e) {
358− return Elm.Fold1(f,function(x){return x;},e); }; },
359− count : function(sig){return Elm.Fold(function(_){return function(c){return c+1;};},0,sig)},
360− keepIf : Elm.keepIf,
361− dropIf : Elm.dropIf,
362− keepWhen : Elm.keepWhen,
363− dropWhen : Elm.dropWhen,
364− dropRepeats : Elm.dropRepeats,
365− sampleOn : Elm.sampleOn
124+ return new lift(f, [e1,e2,e3,e4]); }; }; }; }; },
125+ foldp : function(f) { return function(b) { return function(e) {
126+ return new fold(f,b,false,e); }; }; },
127+ foldp_ : function(f) { return function(b) { return function(e) {
128+ return new fold(f,b,true,e); }; }; },
129+ foldp1 : function(f) { return function(e) {
130+ return new fold(f,function(x){return x;},true,e); }; },
131+ count : function(sig) {
132+ var incr = function(_){return function(c){return c+1;};};
133+ return new fold(incr,0,false,sig) },
134+ keepIf : function(pred) { return function(base) { return function(sig) {
135+ return new dropIf(function(x) { return !pred(x)},base,sig); }; }; },
136+ dropIf : function(pred) { return function(base) { return function(sig) {
137+ return new dropIf(pred,base,sig); }; }; },
138+ keepWhen : function(s) { return dropWhen(new lift(function(b){return !b;},[s])); },
139+ dropWhen : dropWhen,
140+ dropRepeats : function(s) { return new dropRepeats(s);},
141+ sampleOn : function(s1){return function(s2){return new sampleOn(s1,s2);};}
366142 };
367143}();