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