Thu, 15 Jan 2015 15:55:04 +0100
Back out 97036ab72558 which inappropriately compared turds to third parties.
1 /***
3 MochiKit.Base 1.4
5 See <http://mochikit.com/> for documentation, downloads, license, etc.
7 (c) 2005 Bob Ippolito. All rights Reserved.
9 ***/
11 if (typeof(dojo) != 'undefined') {
12 dojo.provide("MochiKit.Base");
13 }
14 if (typeof(MochiKit) == 'undefined') {
15 MochiKit = {};
16 }
17 if (typeof(MochiKit.Base) == 'undefined') {
18 MochiKit.Base = {};
19 }
20 if (typeof(MochiKit.__export__) == "undefined") {
21 MochiKit.__export__ = (MochiKit.__compat__ ||
22 (typeof(JSAN) == 'undefined' && typeof(dojo) == 'undefined')
23 );
24 }
26 MochiKit.Base.VERSION = "1.4";
27 MochiKit.Base.NAME = "MochiKit.Base";
28 /** @id MochiKit.Base.update */
29 MochiKit.Base.update = function (self, obj/*, ... */) {
30 if (self === null) {
31 self = {};
32 }
33 for (var i = 1; i < arguments.length; i++) {
34 var o = arguments[i];
35 if (typeof(o) != 'undefined' && o !== null) {
36 for (var k in o) {
37 self[k] = o[k];
38 }
39 }
40 }
41 return self;
42 };
44 MochiKit.Base.update(MochiKit.Base, {
45 __repr__: function () {
46 return "[" + this.NAME + " " + this.VERSION + "]";
47 },
49 toString: function () {
50 return this.__repr__();
51 },
53 /** @id MochiKit.Base.camelize */
54 camelize: function (selector) {
55 /* from dojo.style.toCamelCase */
56 var arr = selector.split('-');
57 var cc = arr[0];
58 for (var i = 1; i < arr.length; i++) {
59 cc += arr[i].charAt(0).toUpperCase() + arr[i].substring(1);
60 }
61 return cc;
62 },
64 /** @id MochiKit.Base.counter */
65 counter: function (n/* = 1 */) {
66 if (arguments.length === 0) {
67 n = 1;
68 }
69 return function () {
70 return n++;
71 };
72 },
74 /** @id MochiKit.Base.clone */
75 clone: function (obj) {
76 var me = arguments.callee;
77 if (arguments.length == 1) {
78 me.prototype = obj;
79 return new me();
80 }
81 },
83 _flattenArray: function (res, lst) {
84 for (var i = 0; i < lst.length; i++) {
85 var o = lst[i];
86 if (o instanceof Array) {
87 arguments.callee(res, o);
88 } else {
89 res.push(o);
90 }
91 }
92 return res;
93 },
95 /** @id MochiKit.Base.flattenArray */
96 flattenArray: function (lst) {
97 return MochiKit.Base._flattenArray([], lst);
98 },
100 /** @id MochiKit.Base.flattenArguments */
101 flattenArguments: function (lst/* ...*/) {
102 var res = [];
103 var m = MochiKit.Base;
104 var args = m.extend(null, arguments);
105 while (args.length) {
106 var o = args.shift();
107 if (o && typeof(o) == "object" && typeof(o.length) == "number") {
108 for (var i = o.length - 1; i >= 0; i--) {
109 args.unshift(o[i]);
110 }
111 } else {
112 res.push(o);
113 }
114 }
115 return res;
116 },
118 /** @id MochiKit.Base.extend */
119 extend: function (self, obj, /* optional */skip) {
120 // Extend an array with an array-like object starting
121 // from the skip index
122 if (!skip) {
123 skip = 0;
124 }
125 if (obj) {
126 // allow iterable fall-through, but skip the full isArrayLike
127 // check for speed, this is called often.
128 var l = obj.length;
129 if (typeof(l) != 'number' /* !isArrayLike(obj) */) {
130 if (typeof(MochiKit.Iter) != "undefined") {
131 obj = MochiKit.Iter.list(obj);
132 l = obj.length;
133 } else {
134 throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
135 }
136 }
137 if (!self) {
138 self = [];
139 }
140 for (var i = skip; i < l; i++) {
141 self.push(obj[i]);
142 }
143 }
144 // This mutates, but it's convenient to return because
145 // it's often used like a constructor when turning some
146 // ghetto array-like to a real array
147 return self;
148 },
151 /** @id MochiKit.Base.updatetree */
152 updatetree: function (self, obj/*, ...*/) {
153 if (self === null) {
154 self = {};
155 }
156 for (var i = 1; i < arguments.length; i++) {
157 var o = arguments[i];
158 if (typeof(o) != 'undefined' && o !== null) {
159 for (var k in o) {
160 var v = o[k];
161 if (typeof(self[k]) == 'object' && typeof(v) == 'object') {
162 arguments.callee(self[k], v);
163 } else {
164 self[k] = v;
165 }
166 }
167 }
168 }
169 return self;
170 },
172 /** @id MochiKit.Base.setdefault */
173 setdefault: function (self, obj/*, ...*/) {
174 if (self === null) {
175 self = {};
176 }
177 for (var i = 1; i < arguments.length; i++) {
178 var o = arguments[i];
179 for (var k in o) {
180 if (!(k in self)) {
181 self[k] = o[k];
182 }
183 }
184 }
185 return self;
186 },
188 /** @id MochiKit.Base.keys */
189 keys: function (obj) {
190 var rval = [];
191 for (var prop in obj) {
192 rval.push(prop);
193 }
194 return rval;
195 },
197 /** @id MochiKit.Base.values */
198 values: function (obj) {
199 var rval = [];
200 for (var prop in obj) {
201 rval.push(obj[prop]);
202 }
203 return rval;
204 },
206 /** @id MochiKit.Base.items */
207 items: function (obj) {
208 var rval = [];
209 var e;
210 for (var prop in obj) {
211 var v;
212 try {
213 v = obj[prop];
214 } catch (e) {
215 continue;
216 }
217 rval.push([prop, v]);
218 }
219 return rval;
220 },
223 _newNamedError: function (module, name, func) {
224 func.prototype = new MochiKit.Base.NamedError(module.NAME + "." + name);
225 module[name] = func;
226 },
229 /** @id MochiKit.Base.operator */
230 operator: {
231 // unary logic operators
232 /** @id MochiKit.Base.truth */
233 truth: function (a) { return !!a; },
234 /** @id MochiKit.Base.lognot */
235 lognot: function (a) { return !a; },
236 /** @id MochiKit.Base.identity */
237 identity: function (a) { return a; },
239 // bitwise unary operators
240 /** @id MochiKit.Base.not */
241 not: function (a) { return ~a; },
242 /** @id MochiKit.Base.neg */
243 neg: function (a) { return -a; },
245 // binary operators
246 /** @id MochiKit.Base.add */
247 add: function (a, b) { return a + b; },
248 /** @id MochiKit.Base.sub */
249 sub: function (a, b) { return a - b; },
250 /** @id MochiKit.Base.div */
251 div: function (a, b) { return a / b; },
252 /** @id MochiKit.Base.mod */
253 mod: function (a, b) { return a % b; },
254 /** @id MochiKit.Base.mul */
255 mul: function (a, b) { return a * b; },
257 // bitwise binary operators
258 /** @id MochiKit.Base.and */
259 and: function (a, b) { return a & b; },
260 /** @id MochiKit.Base.or */
261 or: function (a, b) { return a | b; },
262 /** @id MochiKit.Base.xor */
263 xor: function (a, b) { return a ^ b; },
264 /** @id MochiKit.Base.lshift */
265 lshift: function (a, b) { return a << b; },
266 /** @id MochiKit.Base.rshift */
267 rshift: function (a, b) { return a >> b; },
268 /** @id MochiKit.Base.zrshift */
269 zrshift: function (a, b) { return a >>> b; },
271 // near-worthless built-in comparators
272 /** @id MochiKit.Base.eq */
273 eq: function (a, b) { return a == b; },
274 /** @id MochiKit.Base.ne */
275 ne: function (a, b) { return a != b; },
276 /** @id MochiKit.Base.gt */
277 gt: function (a, b) { return a > b; },
278 /** @id MochiKit.Base.ge */
279 ge: function (a, b) { return a >= b; },
280 /** @id MochiKit.Base.lt */
281 lt: function (a, b) { return a < b; },
282 /** @id MochiKit.Base.le */
283 le: function (a, b) { return a <= b; },
285 // strict built-in comparators
286 seq: function (a, b) { return a === b; },
287 sne: function (a, b) { return a !== b; },
289 // compare comparators
290 /** @id MochiKit.Base.ceq */
291 ceq: function (a, b) { return MochiKit.Base.compare(a, b) === 0; },
292 /** @id MochiKit.Base.cne */
293 cne: function (a, b) { return MochiKit.Base.compare(a, b) !== 0; },
294 /** @id MochiKit.Base.cgt */
295 cgt: function (a, b) { return MochiKit.Base.compare(a, b) == 1; },
296 /** @id MochiKit.Base.cge */
297 cge: function (a, b) { return MochiKit.Base.compare(a, b) != -1; },
298 /** @id MochiKit.Base.clt */
299 clt: function (a, b) { return MochiKit.Base.compare(a, b) == -1; },
300 /** @id MochiKit.Base.cle */
301 cle: function (a, b) { return MochiKit.Base.compare(a, b) != 1; },
303 // binary logical operators
304 /** @id MochiKit.Base.logand */
305 logand: function (a, b) { return a && b; },
306 /** @id MochiKit.Base.logor */
307 logor: function (a, b) { return a || b; },
308 /** @id MochiKit.Base.contains */
309 contains: function (a, b) { return b in a; }
310 },
312 /** @id MochiKit.Base.forwardCall */
313 forwardCall: function (func) {
314 return function () {
315 return this[func].apply(this, arguments);
316 };
317 },
319 /** @id MochiKit.Base.itemgetter */
320 itemgetter: function (func) {
321 return function (arg) {
322 return arg[func];
323 };
324 },
326 /** @id MochiKit.Base.typeMatcher */
327 typeMatcher: function (/* typ */) {
328 var types = {};
329 for (var i = 0; i < arguments.length; i++) {
330 var typ = arguments[i];
331 types[typ] = typ;
332 }
333 return function () {
334 for (var i = 0; i < arguments.length; i++) {
335 if (!(typeof(arguments[i]) in types)) {
336 return false;
337 }
338 }
339 return true;
340 };
341 },
343 /** @id MochiKit.Base.isNull */
344 isNull: function (/* ... */) {
345 for (var i = 0; i < arguments.length; i++) {
346 if (arguments[i] !== null) {
347 return false;
348 }
349 }
350 return true;
351 },
353 /** @id MochiKit.Base.isUndefinedOrNull */
354 isUndefinedOrNull: function (/* ... */) {
355 for (var i = 0; i < arguments.length; i++) {
356 var o = arguments[i];
357 if (!(typeof(o) == 'undefined' || o === null)) {
358 return false;
359 }
360 }
361 return true;
362 },
364 /** @id MochiKit.Base.isEmpty */
365 isEmpty: function (obj) {
366 return !MochiKit.Base.isNotEmpty.apply(this, arguments);
367 },
369 /** @id MochiKit.Base.isNotEmpty */
370 isNotEmpty: function (obj) {
371 for (var i = 0; i < arguments.length; i++) {
372 var o = arguments[i];
373 if (!(o && o.length)) {
374 return false;
375 }
376 }
377 return true;
378 },
380 /** @id MochiKit.Base.isArrayLike */
381 isArrayLike: function () {
382 for (var i = 0; i < arguments.length; i++) {
383 var o = arguments[i];
384 var typ = typeof(o);
385 if (
386 (typ != 'object' && !(typ == 'function' && typeof(o.item) == 'function')) ||
387 o === null ||
388 typeof(o.length) != 'number' ||
389 o.nodeType === 3
390 ) {
391 return false;
392 }
393 }
394 return true;
395 },
397 /** @id MochiKit.Base.isDateLike */
398 isDateLike: function () {
399 for (var i = 0; i < arguments.length; i++) {
400 var o = arguments[i];
401 if (typeof(o) != "object" || o === null
402 || typeof(o.getTime) != 'function') {
403 return false;
404 }
405 }
406 return true;
407 },
410 /** @id MochiKit.Base.xmap */
411 xmap: function (fn/*, obj... */) {
412 if (fn === null) {
413 return MochiKit.Base.extend(null, arguments, 1);
414 }
415 var rval = [];
416 for (var i = 1; i < arguments.length; i++) {
417 rval.push(fn(arguments[i]));
418 }
419 return rval;
420 },
422 /** @id MochiKit.Base.map */
423 map: function (fn, lst/*, lst... */) {
424 var m = MochiKit.Base;
425 var itr = MochiKit.Iter;
426 var isArrayLike = m.isArrayLike;
427 if (arguments.length <= 2) {
428 // allow an iterable to be passed
429 if (!isArrayLike(lst)) {
430 if (itr) {
431 // fast path for map(null, iterable)
432 lst = itr.list(lst);
433 if (fn === null) {
434 return lst;
435 }
436 } else {
437 throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
438 }
439 }
440 // fast path for map(null, lst)
441 if (fn === null) {
442 return m.extend(null, lst);
443 }
444 // disabled fast path for map(fn, lst)
445 /*
446 if (false && typeof(Array.prototype.map) == 'function') {
447 // Mozilla fast-path
448 return Array.prototype.map.call(lst, fn);
449 }
450 */
451 var rval = [];
452 for (var i = 0; i < lst.length; i++) {
453 rval.push(fn(lst[i]));
454 }
455 return rval;
456 } else {
457 // default for map(null, ...) is zip(...)
458 if (fn === null) {
459 fn = Array;
460 }
461 var length = null;
462 for (i = 1; i < arguments.length; i++) {
463 // allow iterables to be passed
464 if (!isArrayLike(arguments[i])) {
465 if (itr) {
466 return itr.list(itr.imap.apply(null, arguments));
467 } else {
468 throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
469 }
470 }
471 // find the minimum length
472 var l = arguments[i].length;
473 if (length === null || length > l) {
474 length = l;
475 }
476 }
477 rval = [];
478 for (i = 0; i < length; i++) {
479 var args = [];
480 for (var j = 1; j < arguments.length; j++) {
481 args.push(arguments[j][i]);
482 }
483 rval.push(fn.apply(this, args));
484 }
485 return rval;
486 }
487 },
489 /** @id MochiKit.Base.xfilter */
490 xfilter: function (fn/*, obj... */) {
491 var rval = [];
492 if (fn === null) {
493 fn = MochiKit.Base.operator.truth;
494 }
495 for (var i = 1; i < arguments.length; i++) {
496 var o = arguments[i];
497 if (fn(o)) {
498 rval.push(o);
499 }
500 }
501 return rval;
502 },
504 /** @id MochiKit.Base.filter */
505 filter: function (fn, lst, self) {
506 var rval = [];
507 // allow an iterable to be passed
508 var m = MochiKit.Base;
509 if (!m.isArrayLike(lst)) {
510 if (MochiKit.Iter) {
511 lst = MochiKit.Iter.list(lst);
512 } else {
513 throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
514 }
515 }
516 if (fn === null) {
517 fn = m.operator.truth;
518 }
519 if (typeof(Array.prototype.filter) == 'function') {
520 // Mozilla fast-path
521 return Array.prototype.filter.call(lst, fn, self);
522 } else if (typeof(self) == 'undefined' || self === null) {
523 for (var i = 0; i < lst.length; i++) {
524 var o = lst[i];
525 if (fn(o)) {
526 rval.push(o);
527 }
528 }
529 } else {
530 for (i = 0; i < lst.length; i++) {
531 o = lst[i];
532 if (fn.call(self, o)) {
533 rval.push(o);
534 }
535 }
536 }
537 return rval;
538 },
541 _wrapDumbFunction: function (func) {
542 return function () {
543 // fast path!
544 switch (arguments.length) {
545 case 0: return func();
546 case 1: return func(arguments[0]);
547 case 2: return func(arguments[0], arguments[1]);
548 case 3: return func(arguments[0], arguments[1], arguments[2]);
549 }
550 var args = [];
551 for (var i = 0; i < arguments.length; i++) {
552 args.push("arguments[" + i + "]");
553 }
554 return eval("(func(" + args.join(",") + "))");
555 };
556 },
558 /** @id MochiKit.Base.methodcaller */
559 methodcaller: function (func/*, args... */) {
560 var args = MochiKit.Base.extend(null, arguments, 1);
561 if (typeof(func) == "function") {
562 return function (obj) {
563 return func.apply(obj, args);
564 };
565 } else {
566 return function (obj) {
567 return obj[func].apply(obj, args);
568 };
569 }
570 },
572 /** @id MochiKit.Base.method */
573 method: function (self, func) {
574 var m = MochiKit.Base;
575 return m.bind.apply(this, m.extend([func, self], arguments, 2));
576 },
578 /** @id MochiKit.Base.compose */
579 compose: function (f1, f2/*, f3, ... fN */) {
580 var fnlist = [];
581 var m = MochiKit.Base;
582 if (arguments.length === 0) {
583 throw new TypeError("compose() requires at least one argument");
584 }
585 for (var i = 0; i < arguments.length; i++) {
586 var fn = arguments[i];
587 if (typeof(fn) != "function") {
588 throw new TypeError(m.repr(fn) + " is not a function");
589 }
590 fnlist.push(fn);
591 }
592 return function () {
593 var args = arguments;
594 for (var i = fnlist.length - 1; i >= 0; i--) {
595 args = [fnlist[i].apply(this, args)];
596 }
597 return args[0];
598 };
599 },
601 /** @id MochiKit.Base.bind */
602 bind: function (func, self/* args... */) {
603 if (typeof(func) == "string") {
604 func = self[func];
605 }
606 var im_func = func.im_func;
607 var im_preargs = func.im_preargs;
608 var im_self = func.im_self;
609 var m = MochiKit.Base;
610 if (typeof(func) == "function" && typeof(func.apply) == "undefined") {
611 // this is for cases where JavaScript sucks ass and gives you a
612 // really dumb built-in function like alert() that doesn't have
613 // an apply
614 func = m._wrapDumbFunction(func);
615 }
616 if (typeof(im_func) != 'function') {
617 im_func = func;
618 }
619 if (typeof(self) != 'undefined') {
620 im_self = self;
621 }
622 if (typeof(im_preargs) == 'undefined') {
623 im_preargs = [];
624 } else {
625 im_preargs = im_preargs.slice();
626 }
627 m.extend(im_preargs, arguments, 2);
628 var newfunc = function () {
629 var args = arguments;
630 var me = arguments.callee;
631 if (me.im_preargs.length > 0) {
632 args = m.concat(me.im_preargs, args);
633 }
634 var self = me.im_self;
635 if (!self) {
636 self = this;
637 }
638 return me.im_func.apply(self, args);
639 };
640 newfunc.im_self = im_self;
641 newfunc.im_func = im_func;
642 newfunc.im_preargs = im_preargs;
643 return newfunc;
644 },
646 /** @id MochiKit.Base.bindMethods */
647 bindMethods: function (self) {
648 var bind = MochiKit.Base.bind;
649 for (var k in self) {
650 var func = self[k];
651 if (typeof(func) == 'function') {
652 self[k] = bind(func, self);
653 }
654 }
655 },
657 /** @id MochiKit.Base.registerComparator */
658 registerComparator: function (name, check, comparator, /* optional */ override) {
659 MochiKit.Base.comparatorRegistry.register(name, check, comparator, override);
660 },
662 _primitives: {'boolean': true, 'string': true, 'number': true},
664 /** @id MochiKit.Base.compare */
665 compare: function (a, b) {
666 if (a == b) {
667 return 0;
668 }
669 var aIsNull = (typeof(a) == 'undefined' || a === null);
670 var bIsNull = (typeof(b) == 'undefined' || b === null);
671 if (aIsNull && bIsNull) {
672 return 0;
673 } else if (aIsNull) {
674 return -1;
675 } else if (bIsNull) {
676 return 1;
677 }
678 var m = MochiKit.Base;
679 // bool, number, string have meaningful comparisons
680 var prim = m._primitives;
681 if (!(typeof(a) in prim && typeof(b) in prim)) {
682 try {
683 return m.comparatorRegistry.match(a, b);
684 } catch (e) {
685 if (e != m.NotFound) {
686 throw e;
687 }
688 }
689 }
690 if (a < b) {
691 return -1;
692 } else if (a > b) {
693 return 1;
694 }
695 // These types can't be compared
696 var repr = m.repr;
697 throw new TypeError(repr(a) + " and " + repr(b) + " can not be compared");
698 },
700 /** @id MochiKit.Base.compareDateLike */
701 compareDateLike: function (a, b) {
702 return MochiKit.Base.compare(a.getTime(), b.getTime());
703 },
705 /** @id MochiKit.Base.compareArrayLike */
706 compareArrayLike: function (a, b) {
707 var compare = MochiKit.Base.compare;
708 var count = a.length;
709 var rval = 0;
710 if (count > b.length) {
711 rval = 1;
712 count = b.length;
713 } else if (count < b.length) {
714 rval = -1;
715 }
716 for (var i = 0; i < count; i++) {
717 var cmp = compare(a[i], b[i]);
718 if (cmp) {
719 return cmp;
720 }
721 }
722 return rval;
723 },
725 /** @id MochiKit.Base.registerRepr */
726 registerRepr: function (name, check, wrap, /* optional */override) {
727 MochiKit.Base.reprRegistry.register(name, check, wrap, override);
728 },
730 /** @id MochiKit.Base.repr */
731 repr: function (o) {
732 if (typeof(o) == "undefined") {
733 return "undefined";
734 } else if (o === null) {
735 return "null";
736 }
737 try {
738 if (typeof(o.__repr__) == 'function') {
739 return o.__repr__();
740 } else if (typeof(o.repr) == 'function' && o.repr != arguments.callee) {
741 return o.repr();
742 }
743 return MochiKit.Base.reprRegistry.match(o);
744 } catch (e) {
745 if (typeof(o.NAME) == 'string' && (
746 o.toString == Function.prototype.toString ||
747 o.toString == Object.prototype.toString
748 )) {
749 return o.NAME;
750 }
751 }
752 try {
753 var ostring = (o + "");
754 } catch (e) {
755 return "[" + typeof(o) + "]";
756 }
757 if (typeof(o) == "function") {
758 o = ostring.replace(/^\s+/, "");
759 var idx = o.indexOf("{");
760 if (idx != -1) {
761 o = o.substr(0, idx) + "{...}";
762 }
763 }
764 return ostring;
765 },
767 /** @id MochiKit.Base.reprArrayLike */
768 reprArrayLike: function (o) {
769 var m = MochiKit.Base;
770 return "[" + m.map(m.repr, o).join(", ") + "]";
771 },
773 /** @id MochiKit.Base.reprString */
774 reprString: function (o) {
775 return ('"' + o.replace(/(["\\])/g, '\\$1') + '"'
776 ).replace(/[\f]/g, "\\f"
777 ).replace(/[\b]/g, "\\b"
778 ).replace(/[\n]/g, "\\n"
779 ).replace(/[\t]/g, "\\t"
780 ).replace(/[\r]/g, "\\r");
781 },
783 /** @id MochiKit.Base.reprNumber */
784 reprNumber: function (o) {
785 return o + "";
786 },
788 /** @id MochiKit.Base.registerJSON */
789 registerJSON: function (name, check, wrap, /* optional */override) {
790 MochiKit.Base.jsonRegistry.register(name, check, wrap, override);
791 },
794 /** @id MochiKit.Base.evalJSON */
795 evalJSON: function () {
796 return eval("(" + MochiKit.Base._filterJSON(arguments[0]) + ")");
797 },
799 _filterJSON: function (s) {
800 var m = s.match(/^\s*\/\*(.*)\*\/\s*$/);
801 if (m) {
802 return m[1];
803 }
804 return s;
805 },
807 /** @id MochiKit.Base.serializeJSON */
808 serializeJSON: function (o) {
809 var objtype = typeof(o);
810 if (objtype == "number" || objtype == "boolean") {
811 return o + "";
812 } else if (o === null) {
813 return "null";
814 }
815 var m = MochiKit.Base;
816 var reprString = m.reprString;
817 if (objtype == "string") {
818 return reprString(o);
819 }
820 // recurse
821 var me = arguments.callee;
822 // short-circuit for objects that support "json" serialization
823 // if they return "self" then just pass-through...
824 var newObj;
825 if (typeof(o.__json__) == "function") {
826 newObj = o.__json__();
827 if (o !== newObj) {
828 return me(newObj);
829 }
830 }
831 if (typeof(o.json) == "function") {
832 newObj = o.json();
833 if (o !== newObj) {
834 return me(newObj);
835 }
836 }
837 // array
838 if (objtype != "function" && typeof(o.length) == "number") {
839 var res = [];
840 for (var i = 0; i < o.length; i++) {
841 var val = me(o[i]);
842 if (typeof(val) != "string") {
843 val = "undefined";
844 }
845 res.push(val);
846 }
847 return "[" + res.join(", ") + "]";
848 }
849 // look in the registry
850 try {
851 newObj = m.jsonRegistry.match(o);
852 if (o !== newObj) {
853 return me(newObj);
854 }
855 } catch (e) {
856 if (e != m.NotFound) {
857 // something really bad happened
858 throw e;
859 }
860 }
861 // undefined is outside of the spec
862 if (objtype == "undefined") {
863 throw new TypeError("undefined can not be serialized as JSON");
864 }
865 // it's a function with no adapter, bad
866 if (objtype == "function") {
867 return null;
868 }
869 // generic object code path
870 res = [];
871 for (var k in o) {
872 var useKey;
873 if (typeof(k) == "number") {
874 useKey = '"' + k + '"';
875 } else if (typeof(k) == "string") {
876 useKey = reprString(k);
877 } else {
878 // skip non-string or number keys
879 continue;
880 }
881 val = me(o[k]);
882 if (typeof(val) != "string") {
883 // skip non-serializable values
884 continue;
885 }
886 res.push(useKey + ":" + val);
887 }
888 return "{" + res.join(", ") + "}";
889 },
892 /** @id MochiKit.Base.objEqual */
893 objEqual: function (a, b) {
894 return (MochiKit.Base.compare(a, b) === 0);
895 },
897 /** @id MochiKit.Base.arrayEqual */
898 arrayEqual: function (self, arr) {
899 if (self.length != arr.length) {
900 return false;
901 }
902 return (MochiKit.Base.compare(self, arr) === 0);
903 },
905 /** @id MochiKit.Base.concat */
906 concat: function (/* lst... */) {
907 var rval = [];
908 var extend = MochiKit.Base.extend;
909 for (var i = 0; i < arguments.length; i++) {
910 extend(rval, arguments[i]);
911 }
912 return rval;
913 },
915 /** @id MochiKit.Base.keyComparator */
916 keyComparator: function (key/* ... */) {
917 // fast-path for single key comparisons
918 var m = MochiKit.Base;
919 var compare = m.compare;
920 if (arguments.length == 1) {
921 return function (a, b) {
922 return compare(a[key], b[key]);
923 };
924 }
925 var compareKeys = m.extend(null, arguments);
926 return function (a, b) {
927 var rval = 0;
928 // keep comparing until something is inequal or we run out of
929 // keys to compare
930 for (var i = 0; (rval === 0) && (i < compareKeys.length); i++) {
931 var key = compareKeys[i];
932 rval = compare(a[key], b[key]);
933 }
934 return rval;
935 };
936 },
938 /** @id MochiKit.Base.reverseKeyComparator */
939 reverseKeyComparator: function (key) {
940 var comparator = MochiKit.Base.keyComparator.apply(this, arguments);
941 return function (a, b) {
942 return comparator(b, a);
943 };
944 },
946 /** @id MochiKit.Base.partial */
947 partial: function (func) {
948 var m = MochiKit.Base;
949 return m.bind.apply(this, m.extend([func, undefined], arguments, 1));
950 },
952 /** @id MochiKit.Base.listMinMax */
953 listMinMax: function (which, lst) {
954 if (lst.length === 0) {
955 return null;
956 }
957 var cur = lst[0];
958 var compare = MochiKit.Base.compare;
959 for (var i = 1; i < lst.length; i++) {
960 var o = lst[i];
961 if (compare(o, cur) == which) {
962 cur = o;
963 }
964 }
965 return cur;
966 },
968 /** @id MochiKit.Base.objMax */
969 objMax: function (/* obj... */) {
970 return MochiKit.Base.listMinMax(1, arguments);
971 },
973 /** @id MochiKit.Base.objMin */
974 objMin: function (/* obj... */) {
975 return MochiKit.Base.listMinMax(-1, arguments);
976 },
978 /** @id MochiKit.Base.findIdentical */
979 findIdentical: function (lst, value, start/* = 0 */, /* optional */end) {
980 if (typeof(end) == "undefined" || end === null) {
981 end = lst.length;
982 }
983 if (typeof(start) == "undefined" || start === null) {
984 start = 0;
985 }
986 for (var i = start; i < end; i++) {
987 if (lst[i] === value) {
988 return i;
989 }
990 }
991 return -1;
992 },
994 /** @id MochiKit.Base.mean */
995 mean: function(/* lst... */) {
996 /* http://www.nist.gov/dads/HTML/mean.html */
997 var sum = 0;
999 var m = MochiKit.Base;
1000 var args = m.extend(null, arguments);
1001 var count = args.length;
1003 while (args.length) {
1004 var o = args.shift();
1005 if (o && typeof(o) == "object" && typeof(o.length) == "number") {
1006 count += o.length - 1;
1007 for (var i = o.length - 1; i >= 0; i--) {
1008 sum += o[i];
1009 }
1010 } else {
1011 sum += o;
1012 }
1013 }
1015 if (count <= 0) {
1016 throw new TypeError('mean() requires at least one argument');
1017 }
1019 return sum/count;
1020 },
1022 /** @id MochiKit.Base.median */
1023 median: function(/* lst... */) {
1024 /* http://www.nist.gov/dads/HTML/median.html */
1025 var data = MochiKit.Base.flattenArguments(arguments);
1026 if (data.length === 0) {
1027 throw new TypeError('median() requires at least one argument');
1028 }
1029 data.sort(compare);
1030 if (data.length % 2 == 0) {
1031 var upper = data.length / 2;
1032 return (data[upper] + data[upper - 1]) / 2;
1033 } else {
1034 return data[(data.length - 1) / 2];
1035 }
1036 },
1038 /** @id MochiKit.Base.findValue */
1039 findValue: function (lst, value, start/* = 0 */, /* optional */end) {
1040 if (typeof(end) == "undefined" || end === null) {
1041 end = lst.length;
1042 }
1043 if (typeof(start) == "undefined" || start === null) {
1044 start = 0;
1045 }
1046 var cmp = MochiKit.Base.compare;
1047 for (var i = start; i < end; i++) {
1048 if (cmp(lst[i], value) === 0) {
1049 return i;
1050 }
1051 }
1052 return -1;
1053 },
1055 /** @id MochiKit.Base.nodeWalk */
1056 nodeWalk: function (node, visitor) {
1057 var nodes = [node];
1058 var extend = MochiKit.Base.extend;
1059 while (nodes.length) {
1060 var res = visitor(nodes.shift());
1061 if (res) {
1062 extend(nodes, res);
1063 }
1064 }
1065 },
1068 /** @id MochiKit.Base.nameFunctions */
1069 nameFunctions: function (namespace) {
1070 var base = namespace.NAME;
1071 if (typeof(base) == 'undefined') {
1072 base = '';
1073 } else {
1074 base = base + '.';
1075 }
1076 for (var name in namespace) {
1077 var o = namespace[name];
1078 if (typeof(o) == 'function' && typeof(o.NAME) == 'undefined') {
1079 try {
1080 o.NAME = base + name;
1081 } catch (e) {
1082 // pass
1083 }
1084 }
1085 }
1086 },
1089 /** @id MochiKit.Base.queryString */
1090 queryString: function (names, values) {
1091 // check to see if names is a string or a DOM element, and if
1092 // MochiKit.DOM is available. If so, drop it like it's a form
1093 // Ugliest conditional in MochiKit? Probably!
1094 if (typeof(MochiKit.DOM) != "undefined" && arguments.length == 1
1095 && (typeof(names) == "string" || (
1096 typeof(names.nodeType) != "undefined" && names.nodeType > 0
1097 ))
1098 ) {
1099 var kv = MochiKit.DOM.formContents(names);
1100 names = kv[0];
1101 values = kv[1];
1102 } else if (arguments.length == 1) {
1103 // Allow the return value of formContents to be passed directly
1104 if (typeof(names.length) == "number" && names.length == 2) {
1105 return arguments.callee(names[0], names[1]);
1106 }
1107 var o = names;
1108 names = [];
1109 values = [];
1110 for (var k in o) {
1111 var v = o[k];
1112 if (typeof(v) == "function") {
1113 continue;
1114 } else if (typeof(v) != "string" &&
1115 typeof(v.length) == "number") {
1116 for (var i = 0; i < v.length; i++) {
1117 names.push(k);
1118 values.push(v[i]);
1119 }
1120 } else {
1121 names.push(k);
1122 values.push(v);
1123 }
1124 }
1125 }
1126 var rval = [];
1127 var len = Math.min(names.length, values.length);
1128 var urlEncode = MochiKit.Base.urlEncode;
1129 for (var i = 0; i < len; i++) {
1130 v = values[i];
1131 if (typeof(v) != 'undefined' && v !== null) {
1132 rval.push(urlEncode(names[i]) + "=" + urlEncode(v));
1133 }
1134 }
1135 return rval.join("&");
1136 },
1139 /** @id MochiKit.Base.parseQueryString */
1140 parseQueryString: function (encodedString, useArrays) {
1141 // strip a leading '?' from the encoded string
1142 var qstr = (encodedString.charAt(0) == "?")
1143 ? encodedString.substring(1)
1144 : encodedString;
1145 var pairs = qstr.replace(/\+/g, "%20").split(/(\&\;|\&\#38\;|\&|\&)/);
1146 var o = {};
1147 var decode;
1148 if (typeof(decodeURIComponent) != "undefined") {
1149 decode = decodeURIComponent;
1150 } else {
1151 decode = unescape;
1152 }
1153 if (useArrays) {
1154 for (var i = 0; i < pairs.length; i++) {
1155 var pair = pairs[i].split("=");
1156 var name = decode(pair.shift());
1157 if (!name) {
1158 continue;
1159 }
1160 var arr = o[name];
1161 if (!(arr instanceof Array)) {
1162 arr = [];
1163 o[name] = arr;
1164 }
1165 arr.push(decode(pair.join("=")));
1166 }
1167 } else {
1168 for (i = 0; i < pairs.length; i++) {
1169 pair = pairs[i].split("=");
1170 var name = pair.shift();
1171 if (!name) {
1172 continue;
1173 }
1174 o[decode(name)] = decode(pair.join("="));
1175 }
1176 }
1177 return o;
1178 }
1179 });
1181 /** @id MochiKit.Base.AdapterRegistry */
1182 MochiKit.Base.AdapterRegistry = function () {
1183 this.pairs = [];
1184 };
1186 MochiKit.Base.AdapterRegistry.prototype = {
1187 /** @id MochiKit.Base.AdapterRegistry.prototype.register */
1188 register: function (name, check, wrap, /* optional */ override) {
1189 if (override) {
1190 this.pairs.unshift([name, check, wrap]);
1191 } else {
1192 this.pairs.push([name, check, wrap]);
1193 }
1194 },
1196 /** @id MochiKit.Base.AdapterRegistry.prototype.match */
1197 match: function (/* ... */) {
1198 for (var i = 0; i < this.pairs.length; i++) {
1199 var pair = this.pairs[i];
1200 if (pair[1].apply(this, arguments)) {
1201 return pair[2].apply(this, arguments);
1202 }
1203 }
1204 throw MochiKit.Base.NotFound;
1205 },
1207 /** @id MochiKit.Base.AdapterRegistry.prototype.unregister */
1208 unregister: function (name) {
1209 for (var i = 0; i < this.pairs.length; i++) {
1210 var pair = this.pairs[i];
1211 if (pair[0] == name) {
1212 this.pairs.splice(i, 1);
1213 return true;
1214 }
1215 }
1216 return false;
1217 }
1218 };
1221 MochiKit.Base.EXPORT = [
1222 "flattenArray",
1223 "noop",
1224 "camelize",
1225 "counter",
1226 "clone",
1227 "extend",
1228 "update",
1229 "updatetree",
1230 "setdefault",
1231 "keys",
1232 "values",
1233 "items",
1234 "NamedError",
1235 "operator",
1236 "forwardCall",
1237 "itemgetter",
1238 "typeMatcher",
1239 "isCallable",
1240 "isUndefined",
1241 "isUndefinedOrNull",
1242 "isNull",
1243 "isEmpty",
1244 "isNotEmpty",
1245 "isArrayLike",
1246 "isDateLike",
1247 "xmap",
1248 "map",
1249 "xfilter",
1250 "filter",
1251 "methodcaller",
1252 "compose",
1253 "bind",
1254 "bindMethods",
1255 "NotFound",
1256 "AdapterRegistry",
1257 "registerComparator",
1258 "compare",
1259 "registerRepr",
1260 "repr",
1261 "objEqual",
1262 "arrayEqual",
1263 "concat",
1264 "keyComparator",
1265 "reverseKeyComparator",
1266 "partial",
1267 "merge",
1268 "listMinMax",
1269 "listMax",
1270 "listMin",
1271 "objMax",
1272 "objMin",
1273 "nodeWalk",
1274 "zip",
1275 "urlEncode",
1276 "queryString",
1277 "serializeJSON",
1278 "registerJSON",
1279 "evalJSON",
1280 "parseQueryString",
1281 "findValue",
1282 "findIdentical",
1283 "flattenArguments",
1284 "method",
1285 "average",
1286 "mean",
1287 "median"
1288 ];
1290 MochiKit.Base.EXPORT_OK = [
1291 "nameFunctions",
1292 "comparatorRegistry",
1293 "reprRegistry",
1294 "jsonRegistry",
1295 "compareDateLike",
1296 "compareArrayLike",
1297 "reprArrayLike",
1298 "reprString",
1299 "reprNumber"
1300 ];
1302 MochiKit.Base._exportSymbols = function (globals, module) {
1303 if (!MochiKit.__export__) {
1304 return;
1305 }
1306 var all = module.EXPORT_TAGS[":all"];
1307 for (var i = 0; i < all.length; i++) {
1308 globals[all[i]] = module[all[i]];
1309 }
1310 };
1312 MochiKit.Base.__new__ = function () {
1313 // A singleton raised when no suitable adapter is found
1314 var m = this;
1316 // convenience
1317 /** @id MochiKit.Base.noop */
1318 m.noop = m.operator.identity;
1320 // Backwards compat
1321 m.forward = m.forwardCall;
1322 m.find = m.findValue;
1324 if (typeof(encodeURIComponent) != "undefined") {
1325 /** @id MochiKit.Base.urlEncode */
1326 m.urlEncode = function (unencoded) {
1327 return encodeURIComponent(unencoded).replace(/\'/g, '%27');
1328 };
1329 } else {
1330 m.urlEncode = function (unencoded) {
1331 return escape(unencoded
1332 ).replace(/\+/g, '%2B'
1333 ).replace(/\"/g,'%22'
1334 ).rval.replace(/\'/g, '%27');
1335 };
1336 }
1338 /** @id MochiKit.Base.NamedError */
1339 m.NamedError = function (name) {
1340 this.message = name;
1341 this.name = name;
1342 };
1343 m.NamedError.prototype = new Error();
1344 m.update(m.NamedError.prototype, {
1345 repr: function () {
1346 if (this.message && this.message != this.name) {
1347 return this.name + "(" + m.repr(this.message) + ")";
1348 } else {
1349 return this.name + "()";
1350 }
1351 },
1352 toString: m.forwardCall("repr")
1353 });
1355 /** @id MochiKit.Base.NotFound */
1356 m.NotFound = new m.NamedError("MochiKit.Base.NotFound");
1359 /** @id MochiKit.Base.listMax */
1360 m.listMax = m.partial(m.listMinMax, 1);
1361 /** @id MochiKit.Base.listMin */
1362 m.listMin = m.partial(m.listMinMax, -1);
1364 /** @id MochiKit.Base.isCallable */
1365 m.isCallable = m.typeMatcher('function');
1366 /** @id MochiKit.Base.isUndefined */
1367 m.isUndefined = m.typeMatcher('undefined');
1369 /** @id MochiKit.Base.merge */
1370 m.merge = m.partial(m.update, null);
1371 /** @id MochiKit.Base.zip */
1372 m.zip = m.partial(m.map, null);
1374 /** @id MochiKit.Base.average */
1375 m.average = m.mean;
1377 /** @id MochiKit.Base.comparatorRegistry */
1378 m.comparatorRegistry = new m.AdapterRegistry();
1379 m.registerComparator("dateLike", m.isDateLike, m.compareDateLike);
1380 m.registerComparator("arrayLike", m.isArrayLike, m.compareArrayLike);
1382 /** @id MochiKit.Base.reprRegistry */
1383 m.reprRegistry = new m.AdapterRegistry();
1384 m.registerRepr("arrayLike", m.isArrayLike, m.reprArrayLike);
1385 m.registerRepr("string", m.typeMatcher("string"), m.reprString);
1386 m.registerRepr("numbers", m.typeMatcher("number", "boolean"), m.reprNumber);
1388 /** @id MochiKit.Base.jsonRegistry */
1389 m.jsonRegistry = new m.AdapterRegistry();
1391 var all = m.concat(m.EXPORT, m.EXPORT_OK);
1392 m.EXPORT_TAGS = {
1393 ":common": m.concat(m.EXPORT_OK),
1394 ":all": all
1395 };
1397 m.nameFunctions(this);
1399 };
1401 MochiKit.Base.__new__();
1403 //
1404 // XXX: Internet Explorer blows
1405 //
1406 if (MochiKit.__export__) {
1407 compare = MochiKit.Base.compare;
1408 compose = MochiKit.Base.compose;
1409 serializeJSON = MochiKit.Base.serializeJSON;
1410 }
1412 MochiKit.Base._exportSymbols(this, MochiKit.Base);