Elm.Native = Elm.Native || {};
Elm.Native.Utils = {};
Elm.Native.Utils.make = function(localRuntime) {
localRuntime.Native = localRuntime.Native || {};
localRuntime.Native.Utils = localRuntime.Native.Utils || {};
if (localRuntime.Native.Utils.values) {
return localRuntime.Native.Utils.values;
}
function eq(l,r) {
var stack = [{'x': l, 'y': r}]
while (stack.length > 0) {
var front = stack.pop();
var x = front.x;
var y = front.y;
if (x === y) continue;
if (typeof x === "object") {
var c = 0;
for (var i in x) {
++c;
if (i in y) {
if (i !== 'ctor') {
stack.push({ 'x': x[i], 'y': y[i] });
}
} else {
return false;
}
}
if ('ctor' in x) {
stack.push({'x': x.ctor, 'y': y.ctor});
}
if (c !== Object.keys(y).length) {
return false;
};
} else if (typeof x === 'function') {
throw new Error('Equality error: general function equality is ' +
'undecidable, and therefore, unsupported');
} else {
return false;
}
}
return true;
}
// code in Generate/JavaScript.hs depends on the particular
// integer values assigned to LT, EQ, and GT
var LT = -1, EQ = 0, GT = 1, ord = ['LT','EQ','GT'];
function compare(x,y) { return { ctor: ord[cmp(x,y)+1] } }
function cmp(x,y) {
var ord;
if (typeof x !== 'object'){
return x === y ? EQ : x < y ? LT : GT;
}
else if (x.isChar){
var a = x.toString();
var b = y.toString();
return a === b ? EQ : a < b ? LT : GT;
}
else if (x.ctor === "::" || x.ctor === "[]") {
while (true) {
if (x.ctor === "[]" && y.ctor === "[]") return EQ;
if (x.ctor !== y.ctor) return x.ctor === '[]' ? LT : GT;
ord = cmp(x._0, y._0);
if (ord !== EQ) return ord;
x = x._1;
y = y._1;
}
}
else if (x.ctor.slice(0,6) === '_Tuple') {
var n = x.ctor.slice(6) - 0;
var err = 'cannot compare tuples with more than 6 elements.';
if (n === 0) return EQ;
if (n >= 1) { ord = cmp(x._0, y._0); if (ord !== EQ) return ord;
if (n >= 2) { ord = cmp(x._1, y._1); if (ord !== EQ) return ord;
if (n >= 3) { ord = cmp(x._2, y._2); if (ord !== EQ) return ord;
if (n >= 4) { ord = cmp(x._3, y._3); if (ord !== EQ) return ord;
if (n >= 5) { ord = cmp(x._4, y._4); if (ord !== EQ) return ord;
if (n >= 6) { ord = cmp(x._5, y._5); if (ord !== EQ) return ord;
if (n >= 7) throw new Error('Comparison error: ' + err); } } } } } }
return EQ;
}
else {
throw new Error('Comparison error: comparison is only defined on ints, ' +
'floats, times, chars, strings, lists of comparable values, ' +
'and tuples of comparable values.');
}
}
var Tuple0 = { ctor: "_Tuple0" };
function Tuple2(x,y) {
return {
ctor: "_Tuple2",
_0: x,
_1: y
};
}
function chr(c) {
var x = new String(c);
x.isChar = true;
return x;
}
function txt(str) {
var t = new String(str);
t.text = true;
return t;
}
function makeText(text) {
var style = '';
var href = '';
while (true) {
if (text.style) {
style += text.style;
text = text.text;
continue;
}
if (text.href) {
href = text.href;
text = text.text;
continue;
}
if (href) {
text = '<a href="' + href + '">' + text + '</a>';
}
if (style) {
text = '<span style="' + style + '">' + text + '</span>';
}
return text;
}
}
var count = 0;
function guid(_) {
return count++
}
function copy(oldRecord) {
var newRecord = {};
for (var key in oldRecord) {
var value = key === '_'
? copy(oldRecord._)
: oldRecord[key]
;
newRecord[key] = value;
}
return newRecord;
}
function remove(key, oldRecord) {
var record = copy(oldRecord);
if (key in record._) {
record[key] = record._[key][0];
record._[key] = record._[key].slice(1);
if (record._[key].length === 0) {
delete record._[key];
}
} else {
delete record[key];
}
return record;
}
function replace(keyValuePairs, oldRecord) {
var record = copy(oldRecord);
for (var i = keyValuePairs.length; i--; ) {
var pair = keyValuePairs[i];
record[pair[0]] = pair[1];
}
return record;
}
function insert(key, value, oldRecord) {
var newRecord = copy(oldRecord);
if (key in newRecord) {
var values = newRecord._[key];
var copiedValues = values ? values.slice(0) : [];
newRecord._[key] = [newRecord[key]].concat(copiedValues);
}
newRecord[key] = value;
return newRecord;
}
function getXY(e) {
var posx = 0;
var posy = 0;
if (e.pageX || e.pageY) {
posx = e.pageX;
posy = e.pageY;
} else if (e.clientX || e.clientY) {
posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
if (localRuntime.isEmbed()) {
var rect = localRuntime.node.getBoundingClientRect();
var relx = rect.left + document.body.scrollLeft + document.documentElement.scrollLeft;
var rely = rect.top + document.body.scrollTop + document.documentElement.scrollTop;
// TODO: figure out if there is a way to avoid rounding here
posx = posx - Math.round(relx) - localRuntime.node.clientLeft;
posy = posy - Math.round(rely) - localRuntime.node.clientTop;
}
return Tuple2(posx, posy);
}
//// LIST STUFF ////
var Nil = { ctor:'[]' };
function Cons(hd,tl) {
return {
ctor: "::",
_0: hd,
_1: tl
};
}
function append(xs,ys) {
// append Text
if (xs.text || ys.text) {
return txt(makeText(xs) + makeText(ys));
}
// append Strings
if (typeof xs === "string") {
return xs + ys;
}
// append Lists
if (xs.ctor === '[]') {
return ys;
}
var root = Cons(xs._0, Nil);
var curr = root;
xs = xs._1;
while (xs.ctor !== '[]') {
curr._1 = Cons(xs._0, Nil);
xs = xs._1;
curr = curr._1;
}
curr._1 = ys;
return root;
}
//// RUNTIME ERRORS ////
function indent(lines) {
return '\n' + lines.join('\n');
}
function badCase(moduleName, span) {
var msg = indent([
'Non-exhaustive pattern match in case-expression.',
'Make sure your patterns cover every case!'
]);
throw new Error('Runtime error in module ' + moduleName + ' (' + span + ')' + msg);
}
function badIf(moduleName, span) {
var msg = indent([
'Non-exhaustive pattern match in multi-way-if expression.',
'It is best to use \'otherwise\' as the last branch of multi-way-if.'
]);
throw new Error('Runtime error in module ' + moduleName + ' (' + span + ')' + msg);
}
function badPort(expected, received) {
var msg = indent([
'Expecting ' + expected + ' but was given ',
JSON.stringify(received)
]);
throw new Error('Runtime error when sending values through a port.' + msg);
}
return localRuntime.Native.Utils.values = {
eq:eq,
cmp:cmp,
compare:F2(compare),
Tuple0:Tuple0,
Tuple2:Tuple2,
chr:chr,
txt:txt,
makeText:makeText,
copy: copy,
remove: remove,
replace: replace,
insert: insert,
guid: guid,
getXY: getXY,
Nil: Nil,
Cons: Cons,
append: F2(append),
badCase: badCase,
badIf: badIf,
badPort: badPort
};
};