summaryrefslogtreecommitdiffstats
path: root/sca-cpp/trunk/modules/js/htdocs/util.js
diff options
context:
space:
mode:
Diffstat (limited to 'sca-cpp/trunk/modules/js/htdocs/util.js')
-rw-r--r--sca-cpp/trunk/modules/js/htdocs/util.js520
1 files changed, 336 insertions, 184 deletions
diff --git a/sca-cpp/trunk/modules/js/htdocs/util.js b/sca-cpp/trunk/modules/js/htdocs/util.js
index a8fec3994d..00ebd7a0c6 100644
--- a/sca-cpp/trunk/modules/js/htdocs/util.js
+++ b/sca-cpp/trunk/modules/js/htdocs/util.js
@@ -24,200 +24,298 @@
/**
* Scheme-like lists.
*/
+function cell(car, cdr) {
+ this.car = car;
+ this.cdr = cdr;
+}
+
+cell.prototype.toString = function() {
+ return writeValue(this);
+};
+
function cons(car, cdr) {
- var a = new Array();
- a.push(car);
- return a.concat(cdr);
+ return new cell(car, cdr);
}
-function car(l) {
- return l[0];
+var nil = new cell(undefined, null);
+
+function mklist() {
+ if(arguments.length == 0)
+ return nil;
+ var l = nil;
+ for(var i = arguments.length - 1; i >= 0; i--)
+ l = cons(arguments[i], l);
+ return l;
}
-function first(l) {
- return l[0];
+function mkalist(a) {
+ if(a.length == 0)
+ return nil;
+ var l = nil;
+ for(var i = a.length - 1; i >= 0; i--)
+ l = cons(a[i], l);
+ return l;
}
-function cdr(l) {
- return l.slice(1);
+function car(l) {
+ if(l.cdr == null)
+ throw new Error('car out of bounds');
+ //error('car out of bounds');
+ return l.car;
}
-function rest(l) {
- return l.slice(1);
+function cdr(l) {
+ if(l.cdr == null)
+ throw new Error('cdr out of bounds');
+ //error('cdr out of bounds');
+ return l.cdr;
}
function cadr(l) {
- return l[1];
+ return car(cdr(l));
}
function cddr(l) {
- return l.slice(2);
+ return cdr(cdr(l));
}
function caddr(l) {
- return l[2];
+ return car(cdr(cdr(l)));
}
function cdddr(l) {
- return l.slice(3);
+ return cdr(cdr(cdr(l)));
}
function cadddr(l) {
- return l[3];
+ return car(cdr(cdr(cdr(l))));
+}
+
+function last(l) {
+ if(l == nil)
+ throw new Error('last out of bounds');
+ //error('last out of bounds');
+ if(cdr(l) == nil)
+ return car(l);
+ return last(cdr(l));
}
function append(a, b) {
- return a.concat(b);
+ if(a == nil)
+ return b;
+ return cons(car(a), append(cdr(a), b));
}
function reverse(l) {
- return l.slice(0).reverse();
+ function reverseIter(acc, l) {
+ if(l == nil)
+ return acc;
+ return reverseIter(cons(car(l), acc), cdr(l));
+ }
+ return reverseIter(nil, l);
}
-function range(a, b) {
- var l = new Array();
- for (var x = a; x < b; x++)
- l.push(x);
- return l;
+function seq(start, end) {
+ if(start == end)
+ return mklist(start);
+ if(start < end)
+ return cons(start, seq(start + 1, end));
+ return cons(start, seq(start - 1, end));
}
function isNull(v) {
- return (v == null || typeof v == 'undefined' || (v.constructor == Array && v.length == 0));
+ return v == nil || v == null || typeof v == 'undefined';
}
function isSymbol(v) {
- return (typeof v == 'string' && v.slice(0, 1) == "'");
+ return typeof v == 'string' && v[0] == "'";
}
function isString(v) {
- return (typeof v == 'string' && v.slice(0, 1) != "'");
+ return typeof v == 'string' && v[0] != "'";
}
function isList(v) {
- return (v != null && typeof v != 'undefined' && v.constructor == Array);
+ return v != null && typeof v != 'undefined' && typeof v.cdr != 'undefined';
}
function isTaggedList(v, t) {
- return (isList(v) && !isNull(v) && car(v) == t);
+ return isList(v) && v != nil && car(v) == t;
}
-var emptylist = new Array();
-
-function mklist() {
- if (arguments.length == 0)
- return emptylist;
- var a = new Array();
- for (i = 0; i < arguments.length; i++)
- a[i] = arguments[i];
+function mkarray(l) {
+ return reduce(function(a, v) {
+ a[a.length] = v;
return a;
+ }, [], l);
}
function length(l) {
- return l.length;
+ function lengthRef(c, l) {
+ if(l == nil)
+ return c;
+ return lengthRef(c + 1, cdr(l));
+ }
+ return lengthRef(0, l);
}
/**
* Scheme-like associations.
*/
function assoc(k, l) {
- if (isNull(l))
- return emptylist;
- var n = l.length;
- for(var i = 0; i < n; i++) {
- if (k == car(l[i]))
- return l[i];
- }
- return emptylist;
+ if(l == nil)
+ return nil;
+ var c = car(l);
+ if(isList(c) && c != nil && k == car(c))
+ return c;
+ return assoc(k, cdr(l));
}
/**
* Map, filter and reduce functions.
*/
function map(f, l) {
- if (isNull(l))
- return l;
- var n = l.length;
- var a = new Array();
- for(var i = 0; i < n; i++) {
- a.push(f(l[i]));
- }
- return a;
+ if(l == nil)
+ return nil;
+ return cons(f(car(l)), map(f, cdr(l)));
}
function filter(f, l) {
- if (isNull(l))
- return l;
- var n = l.length;
- var a = new Array();
- for(var i = 0; i < n; i++) {
- if (f(l[i]))
- a.push(l[i]);
- }
- return a;
+ if(l == nil)
+ return nil;
+ if (f(car(l)))
+ return cons(car(l), filter(f, cdr(l)));
+ return filter(f, cdr(l));
}
function reduce(f, i, l) {
- if (isNull(l))
- return i;
- return reduce(f, f(i, car(l)), cdr(l));
+ function reduceAccumulate(acc, l) {
+ if(l == nil)
+ return acc;
+ return reduceAccumulate(f(acc, car(l)), cdr(l));
+ };
+ return reduceAccumulate(i, l);
}
/**
- * Split a path into a list of segments.
+ * Sort.
*/
+function sort(f, l) {
+ return mkalist(mkarray(l).sort(f));
+}
+
+/**
+ * String split, join and tokenize functions.
+ */
+function split(s, d) {
+ return mkalist(s.split(d));
+}
+
+function join(l, d) {
+ return mkarray(l).join(d);
+}
+
function tokens(path) {
- return filter(function(s) { return length(s) != 0; }, path.split("/"));
+ return filter(function(s) { return s.length != 0; }, split(path, '/'));
}
/**
- * Debug log a value.
+ * Log values to debug log.
*/
-var rconsole;
+if(window.debugging == undefined)
+ window.debugging = false;
+var remoteLog;
+var bufferedLog;
+
+function debug() {
+ if (!window.debugging)
+ return false;
+ var s = '';
+ for(var i = 0; i < arguments.length; i++) {
+ s += writeValue(arguments[i]);
+ if(i < arguments.length)
+ s += ' ';
+ }
+ if(remoteLog)
+ remoteLog.log(s);
+ if (bufferedLog)
+ bufferedLog[bufferedLog.length] = s;
+ return console.log(s);
+}
-function debug(v) {
- try {
+function error() {
var s = '';
- for (i = 0; i < arguments.length; i++) {
- s = s + writeValue(arguments[i]);
+ for(var i = 0; i < arguments.length; i++) {
+ s += writeValue(arguments[i]);
+ var a = arguments[i];
+ if(a != null && typeof a == 'object' && typeof a.stack != 'undefined') {
+ s += ' ';
+ s += writeValue(a.stack);
+ }
if(i < arguments.length)
s = s + ' ';
}
- if (rconsole) {
- try {
- rconsole.log(s);
- } catch (e) {}
+ if(remoteLog)
+ remoteLog.error(s);
+ if (bufferedLog) {
+ try { throw new Error(); } catch(t) { bufferedLog[bufferedLog.length] = writeValue(t.stack); }
+ bufferedLog[bufferedLog.length] = s;
+ }
+ return console.error(s);
+}
+
+/**
+ * Log uncaught errors.
+ */
+if (typeof window != 'undefined') {
+ window.onerror = function(msg, url, line) {
+ error('window.onerror', msg, url, line);
+ return false;
+ };
+}
+
+/**
+ * Buffer log entries in memory.
+ */
+function bufferLog() {
+ bufferedLog = [];
+ return true;
}
- try {
- console.log(s);
- } catch (e) {}
- } catch (e) {}
+
+function printLog() {
+ if (!bufferedLog)
+ return false;
+ for(var i in bufferedLog)
+ console.log(bufferedLog[i]);
+ return true;
+}
+
+function clearLog() {
+ bufferedLog = [];
return true;
}
/**
- * Dump an object to the console.
+ * Dump an object to the log.
*/
function dump(o) {
- try {
- for (f in o) {
- try {
- debug('dump ' + f + '=' + o[f]);
- } catch (e) {}
- }
- } catch (e) {}
+ if (!window.debugging)
+ return false;
+ for(var f in o)
+ debug('dump', f, '=', o[f]);
return true;
}
/**
* Return true if the current browser is Internet Explorer.
*/
-function isIE() {
- if (typeof isIE.detected != 'undefined')
- return isIE.detected;
- isIE.detected = navigator.appName == 'Microsoft Internet Explorer';
- return isIE.detected;
-};
+function isMSIE() {
+ if(typeof isMSIE.detected != 'undefined')
+ return isMSIE.detected;
+ isMSIE.detected = navigator.userAgent.match(/MSIE/i);
+ return isMSIE.detected;
+}
/**
* External build configuration.
@@ -227,32 +325,19 @@ if (isNull(config))
config = {};
/**
- * Simple assert function.
+ * Assertion.
*/
-function AssertException() {
-}
-
-AssertException.prototype.toString = function () {
- return 'AssertException';
-};
-
function assert(exp) {
if(!exp)
- throw new AssertException();
+ throw new Error('assertion failed');
+ return true;
}
/**
* Write a list of strings.
*/
function writeStrings(l) {
- if (isNull(l))
- return '';
- var s = '';
- var n = l.length;
- for(var i = 0; i < n; i++) {
- s = s + l[i];
- }
- return s;
+ return reduce(function(a, s) { return a + s; }, '', l);
}
/**
@@ -268,14 +353,14 @@ function writeValue(v) {
}
function writeList(l) {
- if (isNull(l))
+ if(l == nil)
return '';
return ' ' + writeValue(car(l)) + writeList(cdr(l));
}
if(!isList(v))
return writePrimitive(v);
- if (isNull(v))
+ if(v == nil)
return '()';
return '(' + writeValue(car(v)) + writeList(cdr(v)) + ')';
}
@@ -284,7 +369,7 @@ function writeValue(v) {
* Apply a function and memoize its result.
*/
function memo(obj, key, f) {
- if (!('memo' in obj)) {
+ if(typeof obj.memo == 'undefined') {
obj.memo = {};
return obj.memo[key] = f();
}
@@ -301,14 +386,15 @@ function unmemo(obj, prefix) {
obj.memo = {};
return true;
}
- if (!('memo' in obj)) {
+ if(typeof obj.memo == 'undefined') {
obj.memo = {};
return true;
}
- for (key in obj.memo) {
+ for(var key in obj.memo) {
if(key.substring(0, prefix.length) == prefix)
delete obj.memo[key];
}
+ return true;
}
/**
@@ -322,12 +408,8 @@ lstorage.enabled = true;
*/
lstorage.key = function(i) {
if(!lstorage.enabled)
- return null;
- try {
+ return undefined;
return localStorage.key(i);
- } catch(e) {
- return null;
- }
};
/**
@@ -336,11 +418,7 @@ lstorage.key = function(i) {
lstorage.length = function() {
if(!lstorage.enabled)
return 0;
- try {
return localStorage.length;
- } catch(e) {
- return 0;
- }
};
/**
@@ -348,12 +426,8 @@ lstorage.length = function() {
*/
lstorage.getItem = function(k) {
if(!lstorage.enabled)
- return null;
- try {
+ return undefined;
return localStorage.getItem(k);
- } catch(e) {
- return null;
- }
};
/**
@@ -361,12 +435,11 @@ lstorage.getItem = function(k) {
*/
lstorage.setItem = function(k, v) {
if(!lstorage.enabled)
- return null;
- try {
+ return v;
+ if (localStorage.getItem(k) != v)
return localStorage.setItem(k, v);
- } catch(e) {
- return null;
- }
+ else
+ return v;
};
/**
@@ -374,62 +447,72 @@ lstorage.setItem = function(k, v) {
*/
lstorage.removeItem = function(k) {
if(!lstorage.enabled)
- return null;
- try {
+ return undefined;
return localStorage.removeItem(k);
- } catch(e) {
- return null;
- }
};
/**
* Returns a list of the properties of an object.
*/
function properties(o) {
- var a = new Array();
- for (p in o)
- a.push(p);
- return a;
+ var l = nil;
+ for(var p in o)
+ l = cons(p, l);
+ return reverse(l);
+}
+
+/**
+ * Convert a DOM node list to a regular list.
+ */
+function nodeList(n) {
+ if (n == null || n.length == 0)
+ return nil;
+ var l = nil;
+ for (var i = n.length - 1; i >= 0; i--)
+ l = cons(n[i], l);
+ return l;
}
/**
* Convert a host name to a domain name.
*/
-function domainname(host) {
+function domainName(host) {
var ds = host.indexOf('//');
if(ds != -1)
- return domainname(host.substring(ds + 2));
+ return domainName(host.substring(ds + 2));
var s = host.indexOf('/');
if(s != -1)
- return domainname(host.substring(0, s));
- var h = reverse(host.split('.'));
- var d = (!isNull(cddr(h)) && caddr(h) == 'www')? mklist(car(h), cadr(h), caddr(h)) : mklist(car(h), cadr(h));
- return reverse(d).join('.');
+ return domainName(host.substring(0, s));
+ var h = reverse(split(host, '.'));
+ var d = (cddr(h) != nil && caddr(h) == 'www')? mklist(car(h), cadr(h), caddr(h)) : mklist(car(h), cadr(h));
+ return join(reverse(d), '.');
}
/**
* Convert a host name to a top domain name.
*/
-function topdomainname(host) {
- var d = reverse(domainname(host).split('.'));
- return reverse(mklist(car(d), cadr(d))).join('.');
+function topDomainName(host) {
+ var d = reverse(split(domainName(host),'.'));
+ return join(mklist(car(d), cadr(d)), '.');
}
/**
* Return true if a host name is a subdomain.
*/
-function issubdomain(host) {
- return host.split('.').length > 2;
+function isSubDomain(host) {
+ return length(split(host, '.')) > 2;
}
/**
* Clear auth information from the document cookie.
*/
-function clearauthcookie() {
- document.cookie = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/; secure; httponly';
- document.cookie = 'TuscanyOAuth1=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/; secure; httponly';
- document.cookie = 'TuscanyOAuth2=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/; secure; httponly';
- document.cookie = 'TuscanyOpenIDAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/; secure; httponly';
+function clearAuthCookie() {
+ var d = new Date(1970,01,01).toGMTString();
+ var dn = domainName(window.location.hostname);
+ document.cookie = 'TuscanyOpenAuth=; expires=' + d + '; domain=.' + dn + '; path=/; secure; httponly';
+ document.cookie = 'TuscanyOAuth1=; expires=' + d + '; domain=.' + dn + '; path=/; secure; httponly';
+ document.cookie = 'TuscanyOAuth2=; expires=' + d + '; domain=.' + dn + '; path=/; secure; httponly';
+ document.cookie = 'TuscanyOpenIDAuth=; expires=' + d + '; domain=.' + dn + '; path=/; secure; httponly';
return true;
}
@@ -439,7 +522,7 @@ function clearauthcookie() {
function format() {
var i = 0;
var s = '';
- for (a in arguments) {
+ for(var a = 0; a < arguments.length; a++) {
s = i == 0? arguments[a] : s.replace('{' + a + '}', arguments[a]);
i++;
}
@@ -449,7 +532,7 @@ function format() {
/**
* Parse an XML dateTime.
*/
-function xmldatetime(xml) {
+function xmlDateTime(xml) {
var re = /^([0-9]{4,})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(\.[0-9]+)?(Z|([+-])([0-9]{2}):([0-9]{2}))?$/;
var match = xml.match(re);
if(!match)
@@ -463,14 +546,14 @@ function xmldatetime(xml) {
/**
* Encode a string to a url-safe base64 format.
*/
-function safeb64encode(s) {
+function safeB64Encode(s) {
return btoa(s).replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '');
}
/**
* Decode a url-safe base64 encoded string.
*/
-function safeb64decode(s) {
+function safeB64Decode(s) {
return atob((s.replace(/\-/g, '+').replace(/\_/g, '/') + '===').substring(0, s.length + (s.length % 4)));
}
@@ -497,7 +580,7 @@ function uuid4() {
/**
* Convert an hexadecimal string to ascii.
*/
-function hex2ascii(x) {
+function hex2Ascii(x) {
var a = '';
for(var i = 0; i < x.length; i += 2)
a += String.fromCharCode(parseInt(x.substr(i, 2), 16));
@@ -512,7 +595,7 @@ function hex2ascii(x) {
* Set the car of a list.
*/
function setcar(l, v) {
- l[0] = v;
+ l.car = v;
return l;
}
@@ -520,7 +603,7 @@ function setcar(l, v) {
* Set the cadr of a list.
*/
function setcadr(l, v) {
- l[1] = v;
+ l.cdr.car = v;
return l;
}
@@ -528,35 +611,104 @@ function setcadr(l, v) {
* Set the caddr of a list.
*/
function setcaddr(l, v) {
- l[2] = v;
+ l.cdr.cdr.car = v;
return l;
}
/**
- * Append the elements of a list to a list.
+ * Set the cdr of a list.
*/
-function setappend(a, b) {
- if (isNull(b))
+function setcdr(a, b) {
+ a.cdr = b;
return a;
- a.push(car(b));
- return setappend(a, cdr(b));
}
/**
- * Set the cdr of a list.
+ * Set the contents of a list.
*/
-function setcdr(a, b) {
- a.length = 1;
- return setappend(a, b);
+function setList(a, b) {
+ if(b == a)
+ return a;
+ a.car = b.car;
+ a.cdr = b.cdr;
+ return a;
}
/**
- * Set the contents of a list.
+ * Append the elements of a list to a list.
*/
-function setlist(a, b) {
- if (b == a)
- return b;
- a.length = 0;
- return setappend(a, b);
+function setAppend(a, b) {
+ if(b.cdr == null)
+ return a;
+ return setList(a, append(a, b));
}
+/**
+ * Uncomment to run the tests.
+ */
+/*
+(function testUtil() {
+ console.log('Testing...');
+
+ assert(car(cons(1, nil)) == 1);
+ assert(car(mklist(1)) == 1);
+ assert(cadr(mklist(1, 2)) == 2);
+
+ assert(0 == length(nil));
+ assert(1 == length(mklist(1)));
+ assert(2 == length(cons(1, mklist(2))));
+
+ assert(car(append(mklist(1), mklist(2))) == 1);
+ assert(car(cdr(append(mklist(1), mklist(2)))) == 2);
+ assert(car(cdr(cdr(append(mklist(1), mklist(2, 3))))) == 3);
+ assert(isNull(cdr(cdr(cdr(append(mklist(1), mklist(2, 3)))))));
+ assert(last(mklist(1, 2, 3)) == 3);
+ assert('' + mklist(1, 2, 3) == '(1 2 3)');
+
+ function square(v) { return v * v; }
+ assert(isNull(map(square, nil)));
+ var m = map(square, mklist(2, 3));
+ assert(car(m) == 4);
+ assert(car(cdr(m)) == 9);
+
+ function add(x, y) { return x + y; }
+ assert(reduce(add, 0, mklist(1, 2, 3)) == 6);
+
+ function isPositive(x) { return x >= 0; }
+ assert(car(filter(isPositive, mklist(1, -1, 2, -2))) == 1);
+ assert(cadr(filter(isPositive, mklist(1, -1, 2, -2))) == 2);
+
+ assert(isNull(reverse(nil)));
+ assert(car(reverse(mklist(1, 2, 3))) == 3);
+ assert(cadr(reverse(mklist(1, 2, 3))) == 2);
+
+ var l = mklist(mklist('x', 'X'), mklist('a', 'A'), mklist('y', 'Y'), mklist('a', 'AA'));
+ assert(car(assoc('a', l)) == 'a');
+ assert(isNull(assoc('z', l)));
+
+ var s = seq(0.0, 1000.0);
+ assert(1001 == length(s));
+ function seqreduce(acc, v) { return acc + 1.0; }
+ assert(1001 == reduce(seqreduce, 0.0, s));
+
+ function compare(a, b) { return a < b? -1 : a == b? 0 : 1; }
+ var l2 = sort(compare, mklist(4, 3, 1, 2));
+ assert(car(l2) == 1);
+ assert(last(l2) == 4);
+
+ var t = new Date();
+ var p = nil;
+ for(var i = 0; i < 100000; i++) {
+ p = cons(i, p);
+ }
+ for(var i = 0; i < 100000; i++) {
+ var x = car(p);
+ p = cdr(p);
+ }
+ console.log('list perf', new Date() - t, 'ms');
+
+ console.log('OK');
+ return true;
+})();
+*/
+