6 // util.choose('a', {a: 'A', b: 'B'}) --> return 'A'
7 // util.choose('a', {a: [console.log, 'foo']}) --> return console.log('foo')
8 function choose(key, options) {
9 var option = options[key];
10 if (option instanceof Array && option[0] instanceof Function)
11 return option[0].apply(this, option.slice(1));
16 // util.debounce(250, key) --> Return a promise. If someone else
17 // calls debounce with the same key, reject the promise. If nobody
18 // else has done so after 250ms, resolve the promise.
19 function debounce(ms, key) {
21 util.debounce.pending = util.debounce.pending || [];
22 util.debounce.pending.map(function(found) {
23 if (!newpending && found.key === key) {
24 // Promise already pending with this key. Reject the old
25 // one, reuse its slot for the new one.
26 window.clearTimeout(found.timer);
27 found.deferred.reject();
33 // No pending promise with this key.
34 newpending = {key: key}
35 util.debounce.pending.push(newpending);
37 newpending.deferred = m.deferred();
39 newpending.timer = window.setTimeout(function() {
40 // Success, no more bouncing. Remove from pending list.
41 util.debounce.pending.map(function(found, i) {
42 if (found === newpending) {
43 util.debounce.pending.splice(i, 1);
44 found.deferred.resolve();
49 return newpending.deferred.promise;
52 // Override mithril's default deferred.onerror, with more error checking
53 var m = require('mithril');
54 m.deferred.onerror = function(e) {
55 if ({}.toString.call(e) === "[object Error]" &&
57 e.constructor.toString() &&
58 e.constructor.toString().match(/ Error/)))