on 4bec310 help sign in
elk/libraries/Native/Utils.js
246 lines 7.8 kB history raw
1Elm.Native.Utils = {};
2Elm.Native.Utils.make = function(elm) {
4 elm.Native = elm.Native || {};
5 elm.Native.Utils = elm.Native.Utils || {};
6 if (elm.Native.Utils.values) return elm.Native.Utils.values;
8 function eq(l,r) {
9 var stack = [{'x': l, 'y': r}]
10 while (stack.length > 0) {
11 var front = stack.pop();
12 var x = front.x;
13 var y = front.y;
14 if (x === y) continue;
15 if (typeof x === "object") {
16 var c = 0;
17 for (var i in x) {
18 ++c;
19 stack.push({ 'x': x[i], 'y': y[i] });
20 }
21 if (c !== Object.keys(y).length) {
22 return false;
23 };
24 } else if (typeof x === 'function') {
25 throw new Error('Equality error: general function equality is ' +
26 'undecidable, and therefore, unsupported');
27 } else {
28 return false;
29 }
30 }
31 return true;
32 }
34 // code in Generate/JavaScript.hs depends on the particular
35 // integer values assigned to LT, EQ, and GT
36 var LT = -1, EQ = 0, GT = 1, ord = ['LT','EQ','GT'];
37 function compare(x,y) { return { ctor: ord[cmp(x,y)+1] } }
38 function cmp(x,y) {
39 var ord;
40 if (typeof x !== 'object'){
41 return x === y ? EQ : x < y ? LT : GT;
42 }
43 else if (x.isChar){
44 var a = x.toString();
45 var b = y.toString();
46 return a === b ? EQ : a < b ? LT : GT;
47 }
48 else if (x.ctor === "::" || x.ctor === "[]") {
49 while (true) {
50 if (x.ctor === "[]" && y.ctor === "[]") return EQ;
51 if (x.ctor !== y.ctor) return x.ctor === '[]' ? LT : GT;
52 ord = cmp(x._0, y._0);
53 if (ord !== EQ) return ord;
54 x = x._1;
55 y = y._1;
56 }
57 }
58 else if (x.ctor.slice(0,6) === '_Tuple') {
59 var n = x.ctor.slice(6) - 0;
60 var err = 'cannot compare tuples with more than 6 elements.';
61 if (n === 0) return EQ;
62 if (n >= 1) { ord = cmp(x._0, y._0); if (ord !== EQ) return ord;
63 if (n >= 2) { ord = cmp(x._1, y._1); if (ord !== EQ) return ord;
64 if (n >= 3) { ord = cmp(x._2, y._2); if (ord !== EQ) return ord;
65 if (n >= 4) { ord = cmp(x._3, y._3); if (ord !== EQ) return ord;
66 if (n >= 5) { ord = cmp(x._4, y._4); if (ord !== EQ) return ord;
67 if (n >= 6) { ord = cmp(x._5, y._5); if (ord !== EQ) return ord;
68 if (n >= 7) throw new Error('Comparison error: ' + err); } } } } } }
69 return EQ;
70 }
71 else {
72 throw new Error('Comparison error: comparison is only defined on ints, ' +
73 'floats, times, chars, strings, lists of comparable values, ' +
74 'and tuples of comparable values.');
75 }
76 }
79 var Tuple0 = { ctor: "_Tuple0" };
80 function Tuple2(x,y) { return { ctor:"_Tuple2", _0:x, _1:y } }
82 function chr(c) {
83 var x = new String(c);
84 x.isChar = true;
85 return x;
86 }
88 function txt(str) {
89 var t = new String(str);
90 t.text = true;
91 return t;
92 }
94 function makeText(text) {
95 var style = '';
96 var href = '';
97 while (true) {
98 if (text.style) {
99 style += text.style;
100 text = text.text;
101 continue;
102 }
103 if (text.href) {
104 href = text.href;
105 text = text.text;
106 continue;
107 }
108 if (href) text = '<a href="' + href + '">' + text + '</a>';
109 if (style) text = '<span style="' + style + '">' + text + '</span>';
110 return text;
111 }
112 }
114 var count = 0;
115 function guid(_) { return count++ }
117 function copy(r) {
118 var o = {};
119 for (var i in r) { o[i] = r[i]; }
120 return o;
121 }
123 function remove(x,r) {
124 var o = copy(r);
125 if (x in o._) {
126 o[x] = o._[x][0];
127 o._[x] = o._[x].slice(1);
128 if (o._[x].length === 0) { delete o._[x]; }
129 } else {
130 delete o[x];
131 }
132 return o;
133 }
135 function replace(kvs,r) {
136 var o = copy(r);
137 for (var i = kvs.length; i--; ) {
138 var kvsi = kvs[i];
139 o[kvsi[0]] = kvsi[1];
140 }
141 return o;
142 }
144 function insert(x,v,r) {
145 var o = copy(r);
146 if (x in o) o._[x] = [o[x]].concat(x in o._ ? o._[x].slice(0) : []);
147 o[x] = v;
148 return o;
149 }
151 function max(a,b) { return a > b ? a : b }
152 function min(a,b) { return a < b ? a : b }
154 function mod(a,b) {
155 if (b === 0) {
156 throw new Error("Cannot perform mod 0. Division by zero error.");
157 }
158 var r = a % b;
159 var m = a === 0 ? 0 : (b > 0 ? (a >= 0 ? r : r+b) : -mod(-a,-b));
161 return m === b ? 0 : m;
162 }
164 function htmlHeight(width, rawHtml) {
165 // create dummy node
166 var html = rawHtml.html;
167 var t = document.createElement('div');
168 t.innerHTML = html;
169 if (width > 0) { t.style.width = width + "px"; }
170 t.style.visibility = "hidden";
171 t.style.styleFloat = "left";
172 t.style.cssFloat = "left";
174 document.body.appendChild(t);
176 // insert interpolated values
177 var args = rawHtml.args;
178 var guid = rawHtml.guid;
179 for (var i = args.length; i--; ) {
180 var arg = args[i];
181 var span = document.getElementById('md-' + guid + '-' + i);
182 if (arg.isElement) {
183 span.style.width = arg.props.width + 'px';
184 span.style.height = arg.props.height + 'px';
185 } else {
186 span.innerHTML = arg;
187 }
188 }
190 // get dimensions
191 var style = window.getComputedStyle(t, null);
192 var w = Math.ceil(style.getPropertyValue("width").slice(0,-2) - 0);
193 var h = Math.ceil(style.getPropertyValue("height").slice(0,-2) - 0);
194 document.body.removeChild(t);
195 return Tuple2(w,h);
196 }
198 function getXY(e) {
199 var posx = 0;
200 var posy = 0;
201 if (e.pageX || e.pageY) {
202 posx = e.pageX;
203 posy = e.pageY;
204 } else if (e.clientX || e.clientY) {
205 posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
206 posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
207 }
209 if (elm.display === ElmRuntime.Display.COMPONENT) {
210 var rect = elm.node.getBoundingClientRect();
211 var relx = rect.left + document.body.scrollLeft + document.documentElement.scrollLeft;
212 var rely = rect.top + document.body.scrollTop + document.documentElement.scrollTop;
213 // TODO: figure out if there is a way to avoid rounding here
214 posx = posx - Math.round(relx) - elm.node.clientLeft;
215 posy = posy - Math.round(rely) - elm.node.clientTop;
216 }
217 return Tuple2(posx, posy);
218 }
220 function isJSArray(a) {
221 return a instanceof Array;
222 }
224 return elm.Native.Utils.values = {
225 eq:eq,
226 cmp:cmp,
227 compare:F2(compare),
228 Tuple0:Tuple0,
229 Tuple2:Tuple2,
230 chr:chr,
231 txt:txt,
232 makeText:makeText,
233 copy: copy,
234 remove: remove,
235 replace: replace,
236 insert: insert,
237 guid: guid,
238 max : F2(max),
239 min : F2(min),
240 mod : F2(mod),
241 htmlHeight: F2(htmlHeight),
242 getXY: getXY,
243 isJSArray: isJSArray,
244 toFloat: function(x) { return +x; }
245 };
246};