on master help sign in
Create the Utils module which contains any utilities that can be created before all other modules. Switch to using Utils in existing modules.
851d2ffevancz
libraries/Native/Error.js+10−3
@@ -1,11 +1,18 @@
1
1
2−Elm.Error = {
2+Elm.Native.Error = function(elm) {
3+ 'use strict';
4+ elm.Native = elm.Native || {};
5+ if (elm.Native.Error) return elm.Native.Error;
6+
3− Case : function(span) {
7+ function Case(span) {
4 var msg = 'Non-exhaustive pattern match in case expression'
8 var msg = 'Non-exhaustive pattern match in case expression'
5 throw new Error(msg + " (" + span + ")")
9 throw new Error(msg + " (" + span + ")")
6 }
10 }
11+
7− If : function(span) {
12+ function If(span) {
8 var msg = 'Non-exhaustive pattern match in multi-way-if expression'
13 var msg = 'Non-exhaustive pattern match in multi-way-if expression'
9 throw new Error(msg + " (" + span + ")")
14 throw new Error(msg + " (" + span + ")")
10 }
15 }
16+
17+ return elm.Native.Error = { Case: Case, If: If };
11};
18};
libraries/Native/List.js+3−1
@@ -5,6 +5,8 @@ Elm.Native.List = function(elm) {
5 elm.Native = elm.Native || {};
5 elm.Native = elm.Native || {};
6 if (elm.Native.List) return elm.Native.List;
6 if (elm.Native.List) return elm.Native.List;
7
7
8+ var eq = elm.Native.Utils(elm).eq;
9+
8 var Nil = { ctor:'Nil' };
10 var Nil = { ctor:'Nil' };
9 function Cons(hd,tl) { return { ctor:"Cons", _0:hd, _1:tl }; }
11 function Cons(hd,tl) { return { ctor:"Cons", _0:hd, _1:tl }; }
10
12
@@ -141,7 +143,7 @@ Elm.Native.List = function(elm) {
141 function member(x, xs) {
143 function member(x, xs) {
142 var out = 0;
144 var out = 0;
143 while (xs.ctor === "Cons") {
145 while (xs.ctor === "Cons") {
144− if (Misc.eq(x,xs._0)) return true;
146+ if (eq(x,xs._0)) return true;
145 xs = xs._1;
147 xs = xs._1;
146 }
148 }
147 return false;
149 return false;
libraries/Native/Misc.js+18−20
@@ -2,6 +2,24 @@
2Elm.Native.Misc = function(elm) {
2Elm.Native.Misc = function(elm) {
3 'use strict';
3 'use strict';
4
4
5+ elm.node.addEventListener('elm_log', function(e) { console.log(e.value); });
6+ elm.node.addEventListener('elm_title', function(e) {document.title = e.value;});
7+ elm.node.addEventListener('elm_redirect', function(e) {
8+ if (e.value.length > 0) { window.location = e.value; }
9+ });
10+ elm.node.addEventListener('elm_viewport', function(e) {
11+ var node = document.getElementById('elm_viewport');
12+ if (!node) {
13+ node = document.createElement('meta');
14+ node.id = 'elm_viewport';
15+ node.name = 'viewport';
16+ document.head.appendChild(node);
17+ }
18+ node.content = e.value;
19+ Dispatcher.notify(elm.Window.dimensions.id,
20+ Tuple2(window.innerWidth, window.innerHeight));
21+ });
22+
5 var NativeList = Elm.Native.List(elm);
23 var NativeList = Elm.Native.List(elm);
6 var List = Elm.List(elm);
24 var List = Elm.List(elm);
7 var Maybe = Elm.Maybe(elm);
25 var Maybe = Elm.Maybe(elm);
@@ -9,26 +27,6 @@ Elm.Native.Misc = function(elm) {
9 var Dict = Elm.Dict(elm);
27 var Dict = Elm.Dict(elm);
10 var Json = Elm.Json(elm);
28 var Json = Elm.Json(elm);
11
29
12− function eq(x,y) {
13− if (x === y) return true;
14− if (typeof x === "object") {
15− if ('_' in x) {
16− for (var i in x) { if (!eq(x[i],y[i])) return false; }
17− for (var i in y) { if (!(i in x)) return false; }
18− return true;
19− }
20− if (x.ctor !== y.ctor) return false;
21− for (var i = x.length; i--; ) {
22− if (!eq(x[i],y[i])) return false;
23− }
24− return true;
25− }
26− return x === y;
27− }
28−
29− var Tuple0 = { ctor: "Tuple0" }
30− function Tuple2(x,y) { return { ctor = "Tuple2", _0:x, _1:y } }
31−
32 function getTextSize(w,h,txt) {
30 function getTextSize(w,h,txt) {
33 var t = document.createElement('div');
31 var t = document.createElement('div');
34 t.innerHTML = txt;
32 t.innerHTML = txt;
libraries/Native/Keyboard/Raw.js → libraries/Native/Signal/KeyboardRaw.jsrenamed+8−13
@@ -6,7 +6,6 @@ Elm.Native.Keyboard.Raw = function(elm) {
6 var NList = Elm.Native.List(elm);
6 var NList = Elm.Native.List(elm);
7 var List = Elm.List(elm);
7 var List = Elm.List(elm);
8 var Maybe = Elm.Maybe(elm);
8 var Maybe = Elm.Maybe(elm);
9− var Misc = Elm.Native.Misc(elm);
10
9
11 var keysDown = Signal.constant(NList.Nil);
10 var keysDown = Signal.constant(NList.Nil);
12 var charPressed = Signal.constant(Maybe.Nothing);
11 var charPressed = Signal.constant(Maybe.Nothing);
@@ -15,33 +14,29 @@ Elm.Native.Keyboard.Raw = function(elm) {
15 if (List.member(e.keyCode)(keysDown.value)) return;
14 if (List.member(e.keyCode)(keysDown.value)) return;
16 var list = NList.Cons(e.keyCode, keysDown.value);
15 var list = NList.Cons(e.keyCode, keysDown.value);
17 var hasListener = elm.notify(keysDown.id, list);
16 var hasListener = elm.notify(keysDown.id, list);
18− if (!hasListener)
19− this.removeEventListener('keydown',arguments.callee,false);
17+ if (!hasListener) elm.node.removeEventListener('keydown', down);
20 }
18 }
21 function up(e) {
19 function up(e) {
22 function notEq(kc) { return kc !== e.keyCode; }
20 function notEq(kc) { return kc !== e.keyCode; }
23 var codes = List.filter(notEq)(keysDown.value);
21 var codes = List.filter(notEq)(keysDown.value);
24 var hasListener = elm.notify(keysDown.id, codes);
22 var hasListener = elm.notify(keysDown.id, codes);
25− if (!hasListener)
26− this.removeEventListener('keyup',arguments.callee,false);
23+ if (!hasListener) elm.node.removeEventListener('keyup', up);
27 }
24 }
28 function blur(e) {
25 function blur(e) {
29 var hasListener = elm.notify(keysDown.id, NList.Nil);
26 var hasListener = elm.notify(keysDown.id, NList.Nil);
30− if (!hasListener)
31− this.removeEventListener('blur',arguments.callee,false);
27+ if (!hasListener) elm.node.removeEventListener('blur', blur);
32 }
28 }
33 function press(e) {
29 function press(e) {
34 var next = Maybe.Just(e.charCode || e.keyCode);
30 var next = Maybe.Just(e.charCode || e.keyCode);
35 var hasListener = elm.notify(charPressed.id, next);
31 var hasListener = elm.notify(charPressed.id, next);
36 elm.notify(charPressed.id, Maybe.Nothing);
32 elm.notify(charPressed.id, Maybe.Nothing);
37− if (!hasListener)
38− this.removeEventListener('keypress',arguments.callee,false);
33+ if (!hasListener) elm.node.removeEventListener('keypress', press);
39 }
34 }
40
35
41− Misc.addListener(document, 'keydown' , down );
36+ elm.node.addEventListener('keydown' , down );
42− Misc.addListener(document, 'keyup' , up );
37+ elm.node.addEventListener('keyup' , up );
43− Misc.addListener(window , 'blur' , blur );
38+ elm.node.addEventListener('blur' , blur );
44− Misc.addListener(document, 'keypress', press);
39+ elm.node.addEventListener('keypress', press);
45
40
46 return elm.Native.Keyboard.Raw = {
41 return elm.Native.Keyboard.Raw = {
47 keysDown:keysDown,
42 keysDown:keysDown,
libraries/Native/Signal/Mouse.js+14−14
@@ -5,12 +5,12 @@ Elm.Native.Mouse = function(elm) {
5 if (elm.Native.Mouse) return elm.Native.Mouse;
5 if (elm.Native.Mouse) return elm.Native.Mouse;
6
6
7 var Signal = Elm.Signal(elm);
7 var Signal = Elm.Signal(elm);
8− var Misc = Elm.Native.Misc(elm);
8+ var Utils = Elm.Native.Utils(elm);
9
9
10− var position = Signal.constant(Misc.Tuple(0,0));
10+ var position = Signal.constant(Utils.Tuple2(0,0));
11 position.defaultNumberOfKids = 2;
11 position.defaultNumberOfKids = 2;
12
12
13− // do not get rid of x and y. By setting their default number
13+ // do not move x and y into Elm. By setting their default number
14 // of kids, it is possible to detatch the mouse listeners if
14 // of kids, it is possible to detatch the mouse listeners if
15 // they are not needed.
15 // they are not needed.
16 var x = A2( Signal.lift, function(p){return p._0}, position);
16 var x = A2( Signal.lift, function(p){return p._0}, position);
@@ -20,7 +20,7 @@ Elm.Native.Mouse = function(elm) {
20
20
21 var isDown = Signal.constant(false);
21 var isDown = Signal.constant(false);
22 var isClicked = Signal.constant(false);
22 var isClicked = Signal.constant(false);
23− var clicks = Signal.constant(Misc.Tuple0);
23+ var clicks = Signal.constant(Utils.Tuple0);
24
24
25 function getXY(e) {
25 function getXY(e) {
26 var posx = 0;
26 var posx = 0;
@@ -35,36 +35,36 @@ Elm.Native.Mouse = function(elm) {
35 posy = e.clientY + document.body.scrollTop +
35 posy = e.clientY + document.body.scrollTop +
36 document.documentElement.scrollTop;
36 document.documentElement.scrollTop;
37 }
37 }
38− return Misc.Tuple2(posx, posy);
38+ return Utils.Tuple2(posx, posy);
39 }
39 }
40
40
41 function click(e) {
41 function click(e) {
42 var hasListener1 = elm.notify(isClicked.id, true);
42 var hasListener1 = elm.notify(isClicked.id, true);
43− var hasListener2 = elm.notify(clicks.id, Misc.Tuple0);
43+ var hasListener2 = elm.notify(clicks.id, Utils.Tuple0);
44 elm.notify(isClicked.id, false);
44 elm.notify(isClicked.id, false);
45 if (!hasListener1 && !hasListener2)
45 if (!hasListener1 && !hasListener2)
46− this.removeEventListener('click',arguments.callee,false);
46+ elm.node.removeEventListener('click', click);
47 }
47 }
48
48
49 function down(e) {
49 function down(e) {
50 var hasListener = elm.notify(isDown.id, true);
50 var hasListener = elm.notify(isDown.id, true);
51− if (!hasListener) this.removeEventListener('mousedown',arguments.callee,false);
51+ if (!hasListener) elm.node.removeEventListener('mousedown', down);
52 }
52 }
53
53
54 function up(e) {
54 function up(e) {
55 var hasListener = elm.notify(isDown.id, false);
55 var hasListener = elm.notify(isDown.id, false);
56− if (!hasListener) this.removeEventListener('mouseup',arguments.callee,false);
56+ if (!hasListener) elm.node.removeEventListener('mouseup', up);
57 }
57 }
58
58
59 function move(e) {
59 function move(e) {
60 var hasListener = elm.notify(position.id, getXY(e));
60 var hasListener = elm.notify(position.id, getXY(e));
61− if (!hasListener) this.removeEventListener('mousemove',arguments.callee,false);
61+ if (!hasListener) elm.node.removeEventListener('mousemove', move);
62 }
62 }
63
63
64− Misc.addListener(elm.node, 'click' , click);
64+ elm.node.addEventListener('click' , click);
65− Misc.addListener(elm.node, 'mousedown', down);
65+ elm.node.addEventListener('mousedown', down);
66− Misc.addListener(elm.node, 'mouseup' , up);
66+ elm.node.addEventListener('mouseup' , up);
67− Misc.addListener(elm.node, 'mousemove', move);
67+ elm.node.addEventListener('mousemove', move);
68
68
69 return elm.Native.Mouse = {
69 return elm.Native.Mouse = {
70 position: position,
70 position: position,
libraries/Native/Signal/Signal.js+16−13
@@ -1,12 +1,15 @@
1
1
2−/**
2+Elm.Native.Signal = function(elm) {
3−module Native.Signal where
3+ 'use strict';
4+
5+ elm.Native = elm.Native || {};
6+ if (elm.Native.Signal) return elm.Native.Signal;
7+
8+ var Utils = Elm.Native.Utils(elm);
9+ var Either = Elm.Either(elm);
10+ var foldl1 = Elm.List(elm).foldl1;
4
11
5−import Either
6−import List
7−**/
8
12
9−(function() {
10 function send(node, timestep, changed) {
13 function send(node, timestep, changed) {
11 var kids = node.kids;
14 var kids = node.kids;
12 for (var i = kids.length; i--; ) {
15 for (var i = kids.length; i--; ) {
@@ -105,7 +108,7 @@ import List
105 this.value = input.value;
108 this.value = input.value;
106 this.kids = [];
109 this.kids = [];
107 this.recv = function(timestep, changed, parentID) {
110 this.recv = function(timestep, changed, parentID) {
108− var chng = changed && !Elm.Misc.eq(this.value,input.value);
111+ var chng = changed && !Utils.eq(this.value,input.value);
109 if (chng) { this.value = input.value; }
112 if (chng) { this.value = input.value; }
110 send(this, timestep, chng);
113 send(this, timestep, chng);
111 };
114 };
@@ -119,7 +122,7 @@ import List
119 }
122 }
120
123
121 function timestamp(a) {
124 function timestamp(a) {
122− function update() { return Elm.Misc.Tuple2(Date.now(), a.value) }
125+ function update() { return Utils.Tuple2(Date.now(), a.value) }
123 return new LiftN(update, [a]);
126 return new LiftN(update, [a]);
124 }
127 }
125
128
@@ -187,9 +190,9 @@ import List
187 }
190 }
188
191
189 function merge(s1,s2) { return new Merge(s1,s2) }
192 function merge(s1,s2) { return new Merge(s1,s2) }
190− function merges(ss) { return A2(Elm.List.foldl1, F2(merge), ss) }
193+ function merges(ss) { return A2(foldl1, F2(merge), ss) }
191− function mergeEither(s1,s2) {return new Merge(A2(lift, Elm.Either.Left , s1),
194+ function mergeEither(s1,s2) {return new Merge(A2(lift, Either.Left , s1),
192− A2(lift, Elm.Either.Right, s2))}
195+ A2(lift, Either.Right, s2))}
193
196
194 function average(sampleSize, s) {
197 function average(sampleSize, s) {
195 var sample = new Array(sampleSize);
198 var sample = new Array(sampleSize);
@@ -208,7 +211,7 @@ import List
208 return lift(f,s);pp
211 return lift(f,s);pp
209 }
212 }
210
213
211− Elm.Native.Signal = {
214+ return elm.Native.Signal = {
212 constant : function(v) { return new Input(v); },
215 constant : function(v) { return new Input(v); },
213 lift : F2(lift ),
216 lift : F2(lift ),
214 lift2 : F3(lift2),
217 lift2 : F3(lift2),
@@ -237,4 +240,4 @@ import List
237 sampleOn : F2(sampleOn),
240 sampleOn : F2(sampleOn),
238 timestamp : timestamp
241 timestamp : timestamp
239 };
242 };
240−}())
243+};
libraries/Native/Signal/Touch.js+3−4
@@ -7,7 +7,6 @@ Elm.Native.Touch = function(elm) {
7
7
8 var Signal = Elm.Signal(elm);
8 var Signal = Elm.Signal(elm);
9 var JS = Elm.JavaScript(elm);
9 var JS = Elm.JavaScript(elm);
10− var Misc = Elm.Native.Misc(elm);
11
10
12 function Dict() {
11 function Dict() {
13 this.keys = [];
12 this.keys = [];
@@ -65,11 +64,11 @@ Elm.Native.Touch = function(elm) {
65 for (var i = e.changedTouches.length; i--; ) { f(e.changedTouches[i]); }
64 for (var i = e.changedTouches.length; i--; ) { f(e.changedTouches[i]); }
66 var ts = new Array(e.touches.length);
65 var ts = new Array(e.touches.length);
67 for (var i = e.touches.length; i--; ) { ts[i] = touch(e.touches[i]); }
66 for (var i = e.touches.length; i--; ) { ts[i] = touch(e.touches[i]); }
68− var hasListener = Dispatcher.notify(root.id, ts);
67+ var hasListener = elm.notify(root.id, ts);
69− if (!hasListener) return document.removeEventListener(name, update);
68+ if (!hasListener) return elm.node.removeEventListener(name, update);
70 e.preventDefault();
69 e.preventDefault();
71 }
70 }
72− Misc.addListener(document, name, update);
71+ elm.node.addEventListener(name, update);
73 }
72 }
74
73
75 listen("touchstart", start);
74 listen("touchstart", start);
libraries/Native/Signal/Window.js+10−8
@@ -6,11 +6,14 @@ Elm.Native.Window = function(elm) {
6 if (elm.Native.Window) return elm.Native.Window;
6 if (elm.Native.Window) return elm.Native.Window;
7
7
8 var Signal = Elm.Signal(elm);
8 var Signal = Elm.Signal(elm);
9− var Misc = Elm.Native.Misc(elm);
9+ var Tuple2 = Elm.Native.Utils(elm).Tuple2;
10
10
11− var dimensions = Signal.constant(Misc.Tuple2(window.innerWidth,window.innerHeight));
11+ var dimensions = Signal.constant(Tuple2(elm.node.clientWidth,
12+ elm.node.clientHeight));
12 dimensions.defaultNumberOfKids = 2;
13 dimensions.defaultNumberOfKids = 2;
13
14
15+ // Do not move width and height into Elm. By setting the default number of kids,
16+ // the resize listener can be detached.
14 var width = A2(Signal.lift, function(p){return p._0}, dimensions);
17 var width = A2(Signal.lift, function(p){return p._0}, dimensions);
15 width.defaultNumberOfKids = 0;
18 width.defaultNumberOfKids = 0;
16
19
@@ -18,13 +21,12 @@ Elm.Native.Window = function(elm) {
18 height.defaultNumberOfKids = 0;
21 height.defaultNumberOfKids = 0;
19
22
20 function resize(e) {
23 function resize(e) {
21− var w = elm.node.getElementById('widthChecker').offsetWidth;
24+ console.log('use the base node (should happen after resize)');
22− var hasListener = elm.notify(dimensions.id,
25+ var hasListener = elm.notify(dimensions.id, Tuple2(elm.node.clientWidth,
23− Misc.Tuple2(w, window.innerHeight));
26+ elm.node.clientHeight));
24− if (!hasListener)
25− this.removeEventListener('resize',arguments.callee,false);
27+ if (!hasListener) window.removeEventListener('resize', resize);
26 }
28 }
27− Misc.addListener(window, 'resize', resize);
29+ window.addEventListener('resize', resize);
28
30
29 return elm.Native.Window = {
31 return elm.Native.Window = {
30 dimensions:dimensions,
32 dimensions:dimensions,
libraries/Native/Utils.jsnew file+101
@@ -0,0 +1,101 @@
1+
2+Elm.Native.Utils = function(elm) {
3+ 'use strict';
4+
5+ function eq(x,y) {
6+ if (x === y) return true;
7+ if (typeof x === "object") {
8+ var c = 0;
9+ for (var i in x) { ++c; if (!eq(x[i],y[i])) return false; }
10+ return c === Object.keys(y).length;
11+ }
12+ if (typeof x === 'function') {
13+ throw new Error('Equality error: general function equality is ' +
14+ 'undecidable, and therefore, unsupported');
15+ }
16+ return x === y;
17+ }
18+
19+ var EQ = 0, LT = 1, GT = 2, ord = ['EQ','LT','GT'];
20+ function compare(x,y) { return { ctor: ord[cmp(x,y)] } }
21+ function cmp(x,y) {
22+ if (typeof x !== 'object') return x === y ? EQ : x < y ? LT : GT;
23+
24+ if (x.ctor === "Cons" || x.ctor === "Nil") {
25+ while (true) {
26+ if (x.ctor === "Nil" && y.ctor === "Nil") return EQ;
27+ if (x.ctor !== y.ctor) return {ctor: x.ctor==='Nil'?LT:GT};
28+ var ord = cmp(x._0, y._0);
29+ if (ord !== EQ) return ord;
30+ x = x._1;
31+ y = y._1;
32+ }
33+ }
34+ if (x.ctor.slice(0,5) === 'Tuple') {
35+ var n = x.ctor.slice(5) - 0;
36+ var err = 'cannot compare tuples with more than 6 elements.';
37+ if (n === 0) return EQ;
38+ if (n >= 1) { ord = cmp(x._0, y._0); if (ord !== EQ) return ord;
39+ if (n >= 2) { ord = cmp(x._1, y._1); if (ord !== EQ) return ord;
40+ if (n >= 3) { ord = cmp(x._2, y._2); if (ord !== EQ) return ord;
41+ if (n >= 4) { ord = cmp(x._3, y._3); if (ord !== EQ) return ord;
42+ if (n >= 5) { ord = cmp(x._4, y._4); if (ord !== EQ) return ord;
43+ if (n >= 6) { ord = cmp(x._5, y._5); if (ord !== EQ) return ord;
44+ if (n >= 7) throw new Error('Comparison error: ' + err); } } } } } }
45+ return EQ;
46+ }
47+ throw new Error('Comparison error: comparison is only defined on ints, ' +
48+ 'floats, times, chars, strings, lists of comparable values, ' +
49+ 'and tuples of comparable values.')
50+ }
51+
52+
53+ var Tuple0 = { ctor: "Tuple0" }
54+ function Tuple2(x,y) { return { ctor = "Tuple2", _0:x, _1:y } }
55+
56+
57+ function copy(r) {
58+ var o = {};
59+ for (var i in r) { o[i] = r[i]; }
60+ return o;
61+ }
62+
63+ function remove(x,r) {
64+ var o = copy(r);
65+ if (x in o._) {
66+ o[x] = o._[x][0];
67+ o._[x] = o._[x].slice(1);
68+ if (o._[x].length === 0) { delete o._[x]; }
69+ } else {
70+ delete o[x];
71+ }
72+ return o;
73+ }
74+
75+ function replace(kvs,r) {
76+ var o = copy(r);
77+ for (var i = kvs.length; i--; ) {
78+ kvsi = kvs[i];
79+ o[kvsi[0]] = kvsi[1];
80+ }
81+ return o;
82+ }
83+
84+ function insert(x,v,r) {
85+ var o = copy(r);
86+ if (x in o) o._[x] = [o[x]].concat(x in o._ ? o._[x].slice(0) : []);
87+ o[x] = v;
88+ return o;
89+ }
90+
91+ return elm.Native.Utils = {
92+ eq:eq,
93+ compare:compare,
94+ Tuple0:Tuple0,
95+ Tuple2:Tuple2,
96+ copy: copy,
97+ remove: remove,
98+ replace: replace,
99+ insert: insert
100+ };
101+};