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