testing/mochitest/tests/MochiKit-1.4.2/MochiKit/Base.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /***
     3 MochiKit.Base 1.4.2
     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.2";
    27 MochiKit.Base.NAME = "MochiKit.Base";
    28 /** @id MochiKit.Base.update */
    29 MochiKit.Base.update = function (self, obj/*, ... */) {
    30     if (self === null || self === undefined) {
    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     _deps: function(module, deps) {
    84         if (!(module in MochiKit)) {
    85             MochiKit[module] = {};
    86         }
    88         if (typeof(dojo) != 'undefined') {
    89             dojo.provide('MochiKit.' + module);
    90         }
    91         for (var i = 0; i < deps.length; i++) {
    92             if (typeof(dojo) != 'undefined') {
    93                 dojo.require('MochiKit.' + deps[i]);
    94             }
    95             if (typeof(JSAN) != 'undefined') {
    96                 JSAN.use('MochiKit.' + deps[i], []);
    97             }
    98             if (!(deps[i] in MochiKit)) {
    99                 throw 'MochiKit.' + module + ' depends on MochiKit.' + deps[i] + '!'
   100             }
   101         }
   102     },
   104     _flattenArray: function (res, lst) {
   105         for (var i = 0; i < lst.length; i++) {
   106             var o = lst[i];
   107             if (o instanceof Array) {
   108                 arguments.callee(res, o);
   109             } else {
   110                 res.push(o);
   111             }
   112         }
   113         return res;
   114     },
   116     /** @id MochiKit.Base.flattenArray */
   117     flattenArray: function (lst) {
   118         return MochiKit.Base._flattenArray([], lst);
   119     },
   121     /** @id MochiKit.Base.flattenArguments */
   122     flattenArguments: function (lst/* ...*/) {
   123         var res = [];
   124         var m = MochiKit.Base;
   125         var args = m.extend(null, arguments);
   126         while (args.length) {
   127             var o = args.shift();
   128             if (o && typeof(o) == "object" && typeof(o.length) == "number") {
   129                 for (var i = o.length - 1; i >= 0; i--) {
   130                     args.unshift(o[i]);
   131                 }
   132             } else {
   133                 res.push(o);
   134             }
   135         }
   136         return res;
   137     },
   139     /** @id MochiKit.Base.extend */
   140     extend: function (self, obj, /* optional */skip) {
   141         // Extend an array with an array-like object starting
   142         // from the skip index
   143         if (!skip) {
   144             skip = 0;
   145         }
   146         if (obj) {
   147             // allow iterable fall-through, but skip the full isArrayLike
   148             // check for speed, this is called often.
   149             var l = obj.length;
   150             if (typeof(l) != 'number' /* !isArrayLike(obj) */) {
   151                 if (typeof(MochiKit.Iter) != "undefined") {
   152                     obj = MochiKit.Iter.list(obj);
   153                     l = obj.length;
   154                 } else {
   155                     throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
   156                 }
   157             }
   158             if (!self) {
   159                 self = [];
   160             }
   161             for (var i = skip; i < l; i++) {
   162                 self.push(obj[i]);
   163             }
   164         }
   165         // This mutates, but it's convenient to return because
   166         // it's often used like a constructor when turning some
   167         // ghetto array-like to a real array
   168         return self;
   169     },
   172     /** @id MochiKit.Base.updatetree */
   173     updatetree: function (self, obj/*, ...*/) {
   174         if (self === null || self === undefined) {
   175             self = {};
   176         }
   177         for (var i = 1; i < arguments.length; i++) {
   178             var o = arguments[i];
   179             if (typeof(o) != 'undefined' && o !== null) {
   180                 for (var k in o) {
   181                     var v = o[k];
   182                     if (typeof(self[k]) == 'object' && typeof(v) == 'object') {
   183                         arguments.callee(self[k], v);
   184                     } else {
   185                         self[k] = v;
   186                     }
   187                 }
   188             }
   189         }
   190         return self;
   191     },
   193     /** @id MochiKit.Base.setdefault */
   194     setdefault: function (self, obj/*, ...*/) {
   195         if (self === null || self === undefined) {
   196             self = {};
   197         }
   198         for (var i = 1; i < arguments.length; i++) {
   199             var o = arguments[i];
   200             for (var k in o) {
   201                 if (!(k in self)) {
   202                     self[k] = o[k];
   203                 }
   204             }
   205         }
   206         return self;
   207     },
   209     /** @id MochiKit.Base.keys */
   210     keys: function (obj) {
   211         var rval = [];
   212         for (var prop in obj) {
   213             rval.push(prop);
   214         }
   215         return rval;
   216     },
   218     /** @id MochiKit.Base.values */
   219     values: function (obj) {
   220         var rval = [];
   221         for (var prop in obj) {
   222             rval.push(obj[prop]);
   223         }
   224         return rval;
   225     },
   227      /** @id MochiKit.Base.items */
   228     items: function (obj) {
   229         var rval = [];
   230         var e;
   231         for (var prop in obj) {
   232             var v;
   233             try {
   234                 v = obj[prop];
   235             } catch (e) {
   236                 continue;
   237             }
   238             rval.push([prop, v]);
   239         }
   240         return rval;
   241     },
   244     _newNamedError: function (module, name, func) {
   245         func.prototype = new MochiKit.Base.NamedError(module.NAME + "." + name);
   246         module[name] = func;
   247     },
   250     /** @id MochiKit.Base.operator */
   251     operator: {
   252         // unary logic operators
   253         /** @id MochiKit.Base.truth */
   254         truth: function (a) { return !!a; },
   255         /** @id MochiKit.Base.lognot */
   256         lognot: function (a) { return !a; },
   257         /** @id MochiKit.Base.identity */
   258         identity: function (a) { return a; },
   260         // bitwise unary operators
   261         /** @id MochiKit.Base.not */
   262         not: function (a) { return ~a; },
   263         /** @id MochiKit.Base.neg */
   264         neg: function (a) { return -a; },
   266         // binary operators
   267         /** @id MochiKit.Base.add */
   268         add: function (a, b) { return a + b; },
   269         /** @id MochiKit.Base.sub */
   270         sub: function (a, b) { return a - b; },
   271         /** @id MochiKit.Base.div */
   272         div: function (a, b) { return a / b; },
   273         /** @id MochiKit.Base.mod */
   274         mod: function (a, b) { return a % b; },
   275         /** @id MochiKit.Base.mul */
   276         mul: function (a, b) { return a * b; },
   278         // bitwise binary operators
   279         /** @id MochiKit.Base.and */
   280         and: function (a, b) { return a & b; },
   281         /** @id MochiKit.Base.or */
   282         or: function (a, b) { return a | b; },
   283         /** @id MochiKit.Base.xor */
   284         xor: function (a, b) { return a ^ b; },
   285         /** @id MochiKit.Base.lshift */
   286         lshift: function (a, b) { return a << b; },
   287         /** @id MochiKit.Base.rshift */
   288         rshift: function (a, b) { return a >> b; },
   289         /** @id MochiKit.Base.zrshift */
   290         zrshift: function (a, b) { return a >>> b; },
   292         // near-worthless built-in comparators
   293         /** @id MochiKit.Base.eq */
   294         eq: function (a, b) { return a == b; },
   295         /** @id MochiKit.Base.ne */
   296         ne: function (a, b) { return a != b; },
   297         /** @id MochiKit.Base.gt */
   298         gt: function (a, b) { return a > b; },
   299         /** @id MochiKit.Base.ge */
   300         ge: function (a, b) { return a >= b; },
   301         /** @id MochiKit.Base.lt */
   302         lt: function (a, b) { return a < b; },
   303         /** @id MochiKit.Base.le */
   304         le: function (a, b) { return a <= b; },
   306         // strict built-in comparators
   307         seq: function (a, b) { return a === b; },
   308         sne: function (a, b) { return a !== b; },
   310         // compare comparators
   311         /** @id MochiKit.Base.ceq */
   312         ceq: function (a, b) { return MochiKit.Base.compare(a, b) === 0; },
   313         /** @id MochiKit.Base.cne */
   314         cne: function (a, b) { return MochiKit.Base.compare(a, b) !== 0; },
   315         /** @id MochiKit.Base.cgt */
   316         cgt: function (a, b) { return MochiKit.Base.compare(a, b) == 1; },
   317         /** @id MochiKit.Base.cge */
   318         cge: function (a, b) { return MochiKit.Base.compare(a, b) != -1; },
   319         /** @id MochiKit.Base.clt */
   320         clt: function (a, b) { return MochiKit.Base.compare(a, b) == -1; },
   321         /** @id MochiKit.Base.cle */
   322         cle: function (a, b) { return MochiKit.Base.compare(a, b) != 1; },
   324         // binary logical operators
   325         /** @id MochiKit.Base.logand */
   326         logand: function (a, b) { return a && b; },
   327         /** @id MochiKit.Base.logor */
   328         logor: function (a, b) { return a || b; },
   329         /** @id MochiKit.Base.contains */
   330         contains: function (a, b) { return b in a; }
   331     },
   333     /** @id MochiKit.Base.forwardCall */
   334     forwardCall: function (func) {
   335         return function () {
   336             return this[func].apply(this, arguments);
   337         };
   338     },
   340     /** @id MochiKit.Base.itemgetter */
   341     itemgetter: function (func) {
   342         return function (arg) {
   343             return arg[func];
   344         };
   345     },
   347     /** @id MochiKit.Base.typeMatcher */
   348     typeMatcher: function (/* typ */) {
   349         var types = {};
   350         for (var i = 0; i < arguments.length; i++) {
   351             var typ = arguments[i];
   352             types[typ] = typ;
   353         }
   354         return function () {
   355             for (var i = 0; i < arguments.length; i++) {
   356                 if (!(typeof(arguments[i]) in types)) {
   357                     return false;
   358                 }
   359             }
   360             return true;
   361         };
   362     },
   364     /** @id MochiKit.Base.isNull */
   365     isNull: function (/* ... */) {
   366         for (var i = 0; i < arguments.length; i++) {
   367             if (arguments[i] !== null) {
   368                 return false;
   369             }
   370         }
   371         return true;
   372     },
   374     /** @id MochiKit.Base.isUndefinedOrNull */
   375     isUndefinedOrNull: function (/* ... */) {
   376         for (var i = 0; i < arguments.length; i++) {
   377             var o = arguments[i];
   378             if (!(typeof(o) == 'undefined' || o === null)) {
   379                 return false;
   380             }
   381         }
   382         return true;
   383     },
   385     /** @id MochiKit.Base.isEmpty */
   386     isEmpty: function (obj) {
   387         return !MochiKit.Base.isNotEmpty.apply(this, arguments);
   388     },
   390     /** @id MochiKit.Base.isNotEmpty */
   391     isNotEmpty: function (obj) {
   392         for (var i = 0; i < arguments.length; i++) {
   393             var o = arguments[i];
   394             if (!(o && o.length)) {
   395                 return false;
   396             }
   397         }
   398         return true;
   399     },
   401     /** @id MochiKit.Base.isArrayLike */
   402     isArrayLike: function () {
   403         for (var i = 0; i < arguments.length; i++) {
   404             var o = arguments[i];
   405             var typ = typeof(o);
   406             if (
   407                 (typ != 'object' && !(typ == 'function' && typeof(o.item) == 'function')) ||
   408                 o === null ||
   409                 typeof(o.length) != 'number' ||
   410                 o.nodeType === 3 ||
   411                 o.nodeType === 4
   412             ) {
   413                 return false;
   414             }
   415         }
   416         return true;
   417     },
   419     /** @id MochiKit.Base.isDateLike */
   420     isDateLike: function () {
   421         for (var i = 0; i < arguments.length; i++) {
   422             var o = arguments[i];
   423             if (typeof(o) != "object" || o === null
   424                     || typeof(o.getTime) != 'function') {
   425                 return false;
   426             }
   427         }
   428         return true;
   429     },
   432     /** @id MochiKit.Base.xmap */
   433     xmap: function (fn/*, obj... */) {
   434         if (fn === null) {
   435             return MochiKit.Base.extend(null, arguments, 1);
   436         }
   437         var rval = [];
   438         for (var i = 1; i < arguments.length; i++) {
   439             rval.push(fn(arguments[i]));
   440         }
   441         return rval;
   442     },
   444     /** @id MochiKit.Base.map */
   445     map: function (fn, lst/*, lst... */) {
   446         var m = MochiKit.Base;
   447         var itr = MochiKit.Iter;
   448         var isArrayLike = m.isArrayLike;
   449         if (arguments.length <= 2) {
   450             // allow an iterable to be passed
   451             if (!isArrayLike(lst)) {
   452                 if (itr) {
   453                     // fast path for map(null, iterable)
   454                     lst = itr.list(lst);
   455                     if (fn === null) {
   456                         return lst;
   457                     }
   458                 } else {
   459                     throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
   460                 }
   461             }
   462             // fast path for map(null, lst)
   463             if (fn === null) {
   464                 return m.extend(null, lst);
   465             }
   466             // disabled fast path for map(fn, lst)
   467             /*
   468             if (false && typeof(Array.prototype.map) == 'function') {
   469                 // Mozilla fast-path
   470                 return Array.prototype.map.call(lst, fn);
   471             }
   472             */
   473             var rval = [];
   474             for (var i = 0; i < lst.length; i++) {
   475                 rval.push(fn(lst[i]));
   476             }
   477             return rval;
   478         } else {
   479             // default for map(null, ...) is zip(...)
   480             if (fn === null) {
   481                 fn = Array;
   482             }
   483             var length = null;
   484             for (i = 1; i < arguments.length; i++) {
   485                 // allow iterables to be passed
   486                 if (!isArrayLike(arguments[i])) {
   487                     if (itr) {
   488                         return itr.list(itr.imap.apply(null, arguments));
   489                     } else {
   490                         throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
   491                     }
   492                 }
   493                 // find the minimum length
   494                 var l = arguments[i].length;
   495                 if (length === null || length > l) {
   496                     length = l;
   497                 }
   498             }
   499             rval = [];
   500             for (i = 0; i < length; i++) {
   501                 var args = [];
   502                 for (var j = 1; j < arguments.length; j++) {
   503                     args.push(arguments[j][i]);
   504                 }
   505                 rval.push(fn.apply(this, args));
   506             }
   507             return rval;
   508         }
   509     },
   511     /** @id MochiKit.Base.xfilter */
   512     xfilter: function (fn/*, obj... */) {
   513         var rval = [];
   514         if (fn === null) {
   515             fn = MochiKit.Base.operator.truth;
   516         }
   517         for (var i = 1; i < arguments.length; i++) {
   518             var o = arguments[i];
   519             if (fn(o)) {
   520                 rval.push(o);
   521             }
   522         }
   523         return rval;
   524     },
   526     /** @id MochiKit.Base.filter */
   527     filter: function (fn, lst, self) {
   528         var rval = [];
   529         // allow an iterable to be passed
   530         var m = MochiKit.Base;
   531         if (!m.isArrayLike(lst)) {
   532             if (MochiKit.Iter) {
   533                 lst = MochiKit.Iter.list(lst);
   534             } else {
   535                 throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
   536             }
   537         }
   538         if (fn === null) {
   539             fn = m.operator.truth;
   540         }
   541         if (typeof(Array.prototype.filter) == 'function') {
   542             // Mozilla fast-path
   543             return Array.prototype.filter.call(lst, fn, self);
   544         } else if (typeof(self) == 'undefined' || self === null) {
   545             for (var i = 0; i < lst.length; i++) {
   546                 var o = lst[i];
   547                 if (fn(o)) {
   548                     rval.push(o);
   549                 }
   550             }
   551         } else {
   552             for (i = 0; i < lst.length; i++) {
   553                 o = lst[i];
   554                 if (fn.call(self, o)) {
   555                     rval.push(o);
   556                 }
   557             }
   558         }
   559         return rval;
   560     },
   563     _wrapDumbFunction: function (func) {
   564         return function () {
   565             // fast path!
   566             switch (arguments.length) {
   567                 case 0: return func();
   568                 case 1: return func(arguments[0]);
   569                 case 2: return func(arguments[0], arguments[1]);
   570                 case 3: return func(arguments[0], arguments[1], arguments[2]);
   571             }
   572             var args = [];
   573             for (var i = 0; i < arguments.length; i++) {
   574                 args.push("arguments[" + i + "]");
   575             }
   576             return eval("(func(" + args.join(",") + "))");
   577         };
   578     },
   580     /** @id MochiKit.Base.methodcaller */
   581     methodcaller: function (func/*, args... */) {
   582         var args = MochiKit.Base.extend(null, arguments, 1);
   583         if (typeof(func) == "function") {
   584             return function (obj) {
   585                 return func.apply(obj, args);
   586             };
   587         } else {
   588             return function (obj) {
   589                 return obj[func].apply(obj, args);
   590             };
   591         }
   592     },
   594     /** @id MochiKit.Base.method */
   595     method: function (self, func) {
   596         var m = MochiKit.Base;
   597         return m.bind.apply(this, m.extend([func, self], arguments, 2));
   598     },
   600     /** @id MochiKit.Base.compose */
   601     compose: function (f1, f2/*, f3, ... fN */) {
   602         var fnlist = [];
   603         var m = MochiKit.Base;
   604         if (arguments.length === 0) {
   605             throw new TypeError("compose() requires at least one argument");
   606         }
   607         for (var i = 0; i < arguments.length; i++) {
   608             var fn = arguments[i];
   609             if (typeof(fn) != "function") {
   610                 throw new TypeError(m.repr(fn) + " is not a function");
   611             }
   612             fnlist.push(fn);
   613         }
   614         return function () {
   615             var args = arguments;
   616             for (var i = fnlist.length - 1; i >= 0; i--) {
   617                 args = [fnlist[i].apply(this, args)];
   618             }
   619             return args[0];
   620         };
   621     },
   623     /** @id MochiKit.Base.bind */
   624     bind: function (func, self/* args... */) {
   625         if (typeof(func) == "string") {
   626             func = self[func];
   627         }
   628         var im_func = func.im_func;
   629         var im_preargs = func.im_preargs;
   630         var im_self = func.im_self;
   631         var m = MochiKit.Base;
   632         if (typeof(func) == "function" && typeof(func.apply) == "undefined") {
   633             // this is for cases where JavaScript sucks ass and gives you a
   634             // really dumb built-in function like alert() that doesn't have
   635             // an apply
   636             func = m._wrapDumbFunction(func);
   637         }
   638         if (typeof(im_func) != 'function') {
   639             im_func = func;
   640         }
   641         if (typeof(self) != 'undefined') {
   642             im_self = self;
   643         }
   644         if (typeof(im_preargs) == 'undefined') {
   645             im_preargs = [];
   646         } else  {
   647             im_preargs = im_preargs.slice();
   648         }
   649         m.extend(im_preargs, arguments, 2);
   650         var newfunc = function () {
   651             var args = arguments;
   652             var me = arguments.callee;
   653             if (me.im_preargs.length > 0) {
   654                 args = m.concat(me.im_preargs, args);
   655             }
   656             var self = me.im_self;
   657             if (!self) {
   658                 self = this;
   659             }
   660             return me.im_func.apply(self, args);
   661         };
   662         newfunc.im_self = im_self;
   663         newfunc.im_func = im_func;
   664         newfunc.im_preargs = im_preargs;
   665         return newfunc;
   666     },
   668     /** @id MochiKit.Base.bindLate */
   669     bindLate: function (func, self/* args... */) {
   670         var m = MochiKit.Base;
   671         if (typeof(func) != "string") {
   672             return m.bind.apply(this, arguments);
   673         }
   674         var im_preargs = m.extend([], arguments, 2);
   675         var newfunc = function () {
   676             var args = arguments;
   677             var me = arguments.callee;
   678             if (me.im_preargs.length > 0) {
   679                 args = m.concat(me.im_preargs, args);
   680             }
   681             var self = me.im_self;
   682             if (!self) {
   683                 self = this;
   684             }
   685             return self[me.im_func].apply(self, args);
   686         };
   687         newfunc.im_self = self;
   688         newfunc.im_func = func;
   689         newfunc.im_preargs = im_preargs;
   690         return newfunc;
   691     },
   693     /** @id MochiKit.Base.bindMethods */
   694     bindMethods: function (self) {
   695         var bind = MochiKit.Base.bind;
   696         for (var k in self) {
   697             var func = self[k];
   698             if (typeof(func) == 'function') {
   699                 self[k] = bind(func, self);
   700             }
   701         }
   702     },
   704     /** @id MochiKit.Base.registerComparator */
   705     registerComparator: function (name, check, comparator, /* optional */ override) {
   706         MochiKit.Base.comparatorRegistry.register(name, check, comparator, override);
   707     },
   709     _primitives: {'boolean': true, 'string': true, 'number': true},
   711     /** @id MochiKit.Base.compare */
   712     compare: function (a, b) {
   713         if (a == b) {
   714             return 0;
   715         }
   716         var aIsNull = (typeof(a) == 'undefined' || a === null);
   717         var bIsNull = (typeof(b) == 'undefined' || b === null);
   718         if (aIsNull && bIsNull) {
   719             return 0;
   720         } else if (aIsNull) {
   721             return -1;
   722         } else if (bIsNull) {
   723             return 1;
   724         }
   725         var m = MochiKit.Base;
   726         // bool, number, string have meaningful comparisons
   727         var prim = m._primitives;
   728         if (!(typeof(a) in prim && typeof(b) in prim)) {
   729             try {
   730                 return m.comparatorRegistry.match(a, b);
   731             } catch (e) {
   732                 if (e != m.NotFound) {
   733                     throw e;
   734                 }
   735             }
   736         }
   737         if (a < b) {
   738             return -1;
   739         } else if (a > b) {
   740             return 1;
   741         }
   742         // These types can't be compared
   743         var repr = m.repr;
   744         throw new TypeError(repr(a) + " and " + repr(b) + " can not be compared");
   745     },
   747     /** @id MochiKit.Base.compareDateLike */
   748     compareDateLike: function (a, b) {
   749         return MochiKit.Base.compare(a.getTime(), b.getTime());
   750     },
   752     /** @id MochiKit.Base.compareArrayLike */
   753     compareArrayLike: function (a, b) {
   754         var compare = MochiKit.Base.compare;
   755         var count = a.length;
   756         var rval = 0;
   757         if (count > b.length) {
   758             rval = 1;
   759             count = b.length;
   760         } else if (count < b.length) {
   761             rval = -1;
   762         }
   763         for (var i = 0; i < count; i++) {
   764             var cmp = compare(a[i], b[i]);
   765             if (cmp) {
   766                 return cmp;
   767             }
   768         }
   769         return rval;
   770     },
   772     /** @id MochiKit.Base.registerRepr */
   773     registerRepr: function (name, check, wrap, /* optional */override) {
   774         MochiKit.Base.reprRegistry.register(name, check, wrap, override);
   775     },
   777     /** @id MochiKit.Base.repr */
   778     repr: function (o) {
   779         if (typeof(o) == "undefined") {
   780             return "undefined";
   781         } else if (o === null) {
   782             return "null";
   783         }
   784         try {
   785             if (typeof(o.__repr__) == 'function') {
   786                 return o.__repr__();
   787             } else if (typeof(o.repr) == 'function' && o.repr != arguments.callee) {
   788                 return o.repr();
   789             }
   790             return MochiKit.Base.reprRegistry.match(o);
   791         } catch (e) {
   792             if (typeof(o.NAME) == 'string' && (
   793                     o.toString == Function.prototype.toString ||
   794                     o.toString == Object.prototype.toString
   795                 )) {
   796                 return o.NAME;
   797             }
   798         }
   799         try {
   800             var ostring = (o + "");
   801         } catch (e) {
   802             return "[" + typeof(o) + "]";
   803         }
   804         if (typeof(o) == "function") {
   805             ostring = ostring.replace(/^\s+/, "").replace(/\s+/g, " ");
   806             ostring = ostring.replace(/,(\S)/, ", $1");
   807             var idx = ostring.indexOf("{");
   808             if (idx != -1) {
   809                 ostring = ostring.substr(0, idx) + "{...}";
   810             }
   811         }
   812         return ostring;
   813     },
   815     /** @id MochiKit.Base.reprArrayLike */
   816     reprArrayLike: function (o) {
   817         var m = MochiKit.Base;
   818         return "[" + m.map(m.repr, o).join(", ") + "]";
   819     },
   821     /** @id MochiKit.Base.reprString */
   822     reprString: function (o) {
   823         return ('"' + o.replace(/(["\\])/g, '\\$1') + '"'
   824             ).replace(/[\f]/g, "\\f"
   825             ).replace(/[\b]/g, "\\b"
   826             ).replace(/[\n]/g, "\\n"
   827             ).replace(/[\t]/g, "\\t"
   828             ).replace(/[\v]/g, "\\v"
   829             ).replace(/[\r]/g, "\\r");
   830     },
   832     /** @id MochiKit.Base.reprNumber */
   833     reprNumber: function (o) {
   834         return o + "";
   835     },
   837     /** @id MochiKit.Base.registerJSON */
   838     registerJSON: function (name, check, wrap, /* optional */override) {
   839         MochiKit.Base.jsonRegistry.register(name, check, wrap, override);
   840     },
   843     /** @id MochiKit.Base.evalJSON */
   844     evalJSON: function () {
   845         return eval("(" + MochiKit.Base._filterJSON(arguments[0]) + ")");
   846     },
   848     _filterJSON: function (s) {
   849         var m = s.match(/^\s*\/\*(.*)\*\/\s*$/);
   850         if (m) {
   851             return m[1];
   852         }
   853         return s;
   854     },
   856     /** @id MochiKit.Base.serializeJSON */
   857     serializeJSON: function (o) {
   858         var objtype = typeof(o);
   859         if (objtype == "number" || objtype == "boolean") {
   860             return o + "";
   861         } else if (o === null) {
   862             return "null";
   863         } else if (objtype == "string") {
   864             var res = "";
   865             for (var i = 0; i < o.length; i++) {
   866                 var c = o.charAt(i);
   867                 if (c == '\"') {
   868                     res += '\\"';
   869                 } else if (c == '\\') {
   870                     res += '\\\\';
   871                 } else if (c == '\b') {
   872                     res += '\\b';
   873                 } else if (c == '\f') {
   874                     res += '\\f';
   875                 } else if (c == '\n') {
   876                     res += '\\n';
   877                 } else if (c == '\r') {
   878                     res += '\\r';
   879                 } else if (c == '\t') {
   880                     res += '\\t';
   881                 } else if (o.charCodeAt(i) <= 0x1F) {
   882                     var hex = o.charCodeAt(i).toString(16);
   883                     if (hex.length < 2) {
   884                         hex = '0' + hex;
   885                     }
   886                     res += '\\u00' + hex.toUpperCase();
   887                 } else {
   888                     res += c;
   889                 }
   890             }
   891             return '"' + res + '"';
   892         }
   893         // recurse
   894         var me = arguments.callee;
   895         // short-circuit for objects that support "json" serialization
   896         // if they return "self" then just pass-through...
   897         var newObj;
   898         if (typeof(o.__json__) == "function") {
   899             newObj = o.__json__();
   900             if (o !== newObj) {
   901                 return me(newObj);
   902             }
   903         }
   904         if (typeof(o.json) == "function") {
   905             newObj = o.json();
   906             if (o !== newObj) {
   907                 return me(newObj);
   908             }
   909         }
   910         // array
   911         if (objtype != "function" && typeof(o.length) == "number") {
   912             var res = [];
   913             for (var i = 0; i < o.length; i++) {
   914                 var val = me(o[i]);
   915                 if (typeof(val) != "string") {
   916                     // skip non-serializable values
   917                     continue;
   918                 }
   919                 res.push(val);
   920             }
   921             return "[" + res.join(", ") + "]";
   922         }
   923         // look in the registry
   924         var m = MochiKit.Base;
   925         try {
   926             newObj = m.jsonRegistry.match(o);
   927             if (o !== newObj) {
   928                 return me(newObj);
   929             }
   930         } catch (e) {
   931             if (e != m.NotFound) {
   932                 // something really bad happened
   933                 throw e;
   934             }
   935         }
   936         // undefined is outside of the spec
   937         if (objtype == "undefined") {
   938             throw new TypeError("undefined can not be serialized as JSON");
   939         }
   940         // it's a function with no adapter, bad
   941         if (objtype == "function") {
   942             return null;
   943         }
   944         // generic object code path
   945         res = [];
   946         for (var k in o) {
   947             var useKey;
   948             if (typeof(k) == "number") {
   949                 useKey = '"' + k + '"';
   950             } else if (typeof(k) == "string") {
   951                 useKey = me(k);
   952             } else {
   953                 // skip non-string or number keys
   954                 continue;
   955             }
   956             val = me(o[k]);
   957             if (typeof(val) != "string") {
   958                 // skip non-serializable values
   959                 continue;
   960             }
   961             res.push(useKey + ":" + val);
   962         }
   963         return "{" + res.join(", ") + "}";
   964     },
   967     /** @id MochiKit.Base.objEqual */
   968     objEqual: function (a, b) {
   969         return (MochiKit.Base.compare(a, b) === 0);
   970     },
   972     /** @id MochiKit.Base.arrayEqual */
   973     arrayEqual: function (self, arr) {
   974         if (self.length != arr.length) {
   975             return false;
   976         }
   977         return (MochiKit.Base.compare(self, arr) === 0);
   978     },
   980     /** @id MochiKit.Base.concat */
   981     concat: function (/* lst... */) {
   982         var rval = [];
   983         var extend = MochiKit.Base.extend;
   984         for (var i = 0; i < arguments.length; i++) {
   985             extend(rval, arguments[i]);
   986         }
   987         return rval;
   988     },
   990     /** @id MochiKit.Base.keyComparator */
   991     keyComparator: function (key/* ... */) {
   992         // fast-path for single key comparisons
   993         var m = MochiKit.Base;
   994         var compare = m.compare;
   995         if (arguments.length == 1) {
   996             return function (a, b) {
   997                 return compare(a[key], b[key]);
   998             };
   999         }
  1000         var compareKeys = m.extend(null, arguments);
  1001         return function (a, b) {
  1002             var rval = 0;
  1003             // keep comparing until something is inequal or we run out of
  1004             // keys to compare
  1005             for (var i = 0; (rval === 0) && (i < compareKeys.length); i++) {
  1006                 var key = compareKeys[i];
  1007                 rval = compare(a[key], b[key]);
  1009             return rval;
  1010         };
  1011     },
  1013     /** @id MochiKit.Base.reverseKeyComparator */
  1014     reverseKeyComparator: function (key) {
  1015         var comparator = MochiKit.Base.keyComparator.apply(this, arguments);
  1016         return function (a, b) {
  1017             return comparator(b, a);
  1018         };
  1019     },
  1021     /** @id MochiKit.Base.partial */
  1022     partial: function (func) {
  1023         var m = MochiKit.Base;
  1024         return m.bind.apply(this, m.extend([func, undefined], arguments, 1));
  1025     },
  1027     /** @id MochiKit.Base.listMinMax */
  1028     listMinMax: function (which, lst) {
  1029         if (lst.length === 0) {
  1030             return null;
  1032         var cur = lst[0];
  1033         var compare = MochiKit.Base.compare;
  1034         for (var i = 1; i < lst.length; i++) {
  1035             var o = lst[i];
  1036             if (compare(o, cur) == which) {
  1037                 cur = o;
  1040         return cur;
  1041     },
  1043     /** @id MochiKit.Base.objMax */
  1044     objMax: function (/* obj... */) {
  1045         return MochiKit.Base.listMinMax(1, arguments);
  1046     },
  1048     /** @id MochiKit.Base.objMin */
  1049     objMin: function (/* obj... */) {
  1050         return MochiKit.Base.listMinMax(-1, arguments);
  1051     },
  1053     /** @id MochiKit.Base.findIdentical */
  1054     findIdentical: function (lst, value, start/* = 0 */, /* optional */end) {
  1055         if (typeof(end) == "undefined" || end === null) {
  1056             end = lst.length;
  1058         if (typeof(start) == "undefined" || start === null) {
  1059             start = 0;
  1061         for (var i = start; i < end; i++) {
  1062             if (lst[i] === value) {
  1063                 return i;
  1066         return -1;
  1067     },
  1069     /** @id MochiKit.Base.mean */
  1070     mean: function(/* lst... */) {
  1071         /* http://www.nist.gov/dads/HTML/mean.html */
  1072         var sum = 0;
  1074         var m = MochiKit.Base;
  1075         var args = m.extend(null, arguments);
  1076         var count = args.length;
  1078         while (args.length) {
  1079             var o = args.shift();
  1080             if (o && typeof(o) == "object" && typeof(o.length) == "number") {
  1081                 count += o.length - 1;
  1082                 for (var i = o.length - 1; i >= 0; i--) {
  1083                     sum += o[i];
  1085             } else {
  1086                 sum += o;
  1090         if (count <= 0) {
  1091             throw new TypeError('mean() requires at least one argument');
  1094         return sum/count;
  1095     },
  1097     /** @id MochiKit.Base.median */
  1098     median: function(/* lst... */) {
  1099         /* http://www.nist.gov/dads/HTML/median.html */
  1100         var data = MochiKit.Base.flattenArguments(arguments);
  1101         if (data.length === 0) {
  1102             throw new TypeError('median() requires at least one argument');
  1104         data.sort(compare);
  1105         if (data.length % 2 == 0) {
  1106             var upper = data.length / 2;
  1107             return (data[upper] + data[upper - 1]) / 2;
  1108         } else {
  1109             return data[(data.length - 1) / 2];
  1111     },
  1113     /** @id MochiKit.Base.findValue */
  1114     findValue: function (lst, value, start/* = 0 */, /* optional */end) {
  1115         if (typeof(end) == "undefined" || end === null) {
  1116             end = lst.length;
  1118         if (typeof(start) == "undefined" || start === null) {
  1119             start = 0;
  1121         var cmp = MochiKit.Base.compare;
  1122         for (var i = start; i < end; i++) {
  1123             if (cmp(lst[i], value) === 0) {
  1124                 return i;
  1127         return -1;
  1128     },
  1130     /** @id MochiKit.Base.nodeWalk */
  1131     nodeWalk: function (node, visitor) {
  1132         var nodes = [node];
  1133         var extend = MochiKit.Base.extend;
  1134         while (nodes.length) {
  1135             var res = visitor(nodes.shift());
  1136             if (res) {
  1137                 extend(nodes, res);
  1140     },
  1143     /** @id MochiKit.Base.nameFunctions */
  1144     nameFunctions: function (namespace) {
  1145         var base = namespace.NAME;
  1146         if (typeof(base) == 'undefined') {
  1147             base = '';
  1148         } else {
  1149             base = base + '.';
  1151         for (var name in namespace) {
  1152             var o = namespace[name];
  1153             if (typeof(o) == 'function' && typeof(o.NAME) == 'undefined') {
  1154                 try {
  1155                     o.NAME = base + name;
  1156                 } catch (e) {
  1157                     // pass
  1161     },
  1164     /** @id MochiKit.Base.queryString */
  1165     queryString: function (names, values) {
  1166         // check to see if names is a string or a DOM element, and if
  1167         // MochiKit.DOM is available.  If so, drop it like it's a form
  1168         // Ugliest conditional in MochiKit?  Probably!
  1169         if (typeof(MochiKit.DOM) != "undefined" && arguments.length == 1
  1170             && (typeof(names) == "string" || (
  1171                 typeof(names.nodeType) != "undefined" && names.nodeType > 0
  1172             ))
  1173         ) {
  1174             var kv = MochiKit.DOM.formContents(names);
  1175             names = kv[0];
  1176             values = kv[1];
  1177         } else if (arguments.length == 1) {
  1178             // Allow the return value of formContents to be passed directly
  1179             if (typeof(names.length) == "number" && names.length == 2) {
  1180                 return arguments.callee(names[0], names[1]);
  1182             var o = names;
  1183             names = [];
  1184             values = [];
  1185             for (var k in o) {
  1186                 var v = o[k];
  1187                 if (typeof(v) == "function") {
  1188                     continue;
  1189                 } else if (MochiKit.Base.isArrayLike(v)){
  1190                     for (var i = 0; i < v.length; i++) {
  1191                         names.push(k);
  1192                         values.push(v[i]);
  1194                 } else {
  1195                     names.push(k);
  1196                     values.push(v);
  1200         var rval = [];
  1201         var len = Math.min(names.length, values.length);
  1202         var urlEncode = MochiKit.Base.urlEncode;
  1203         for (var i = 0; i < len; i++) {
  1204             v = values[i];
  1205             if (typeof(v) != 'undefined' && v !== null) {
  1206                 rval.push(urlEncode(names[i]) + "=" + urlEncode(v));
  1209         return rval.join("&");
  1210     },
  1213     /** @id MochiKit.Base.parseQueryString */
  1214     parseQueryString: function (encodedString, useArrays) {
  1215         // strip a leading '?' from the encoded string
  1216         var qstr = (encodedString.charAt(0) == "?")
  1217             ? encodedString.substring(1)
  1218             : encodedString;
  1219         var pairs = qstr.replace(/\+/g, "%20").split(/\&amp\;|\&\#38\;|\&#x26;|\&/);
  1220         var o = {};
  1221         var decode;
  1222         if (typeof(decodeURIComponent) != "undefined") {
  1223             decode = decodeURIComponent;
  1224         } else {
  1225             decode = unescape;
  1227         if (useArrays) {
  1228             for (var i = 0; i < pairs.length; i++) {
  1229                 var pair = pairs[i].split("=");
  1230                 var name = decode(pair.shift());
  1231                 if (!name) {
  1232                     continue;
  1234                 var arr = o[name];
  1235                 if (!(arr instanceof Array)) {
  1236                     arr = [];
  1237                     o[name] = arr;
  1239                 arr.push(decode(pair.join("=")));
  1241         } else {
  1242             for (i = 0; i < pairs.length; i++) {
  1243                 pair = pairs[i].split("=");
  1244                 var name = pair.shift();
  1245                 if (!name) {
  1246                     continue;
  1248                 o[decode(name)] = decode(pair.join("="));
  1251         return o;
  1253 });
  1255 /** @id MochiKit.Base.AdapterRegistry */
  1256 MochiKit.Base.AdapterRegistry = function () {
  1257     this.pairs = [];
  1258 };
  1260 MochiKit.Base.AdapterRegistry.prototype = {
  1261     /** @id MochiKit.Base.AdapterRegistry.prototype.register */
  1262     register: function (name, check, wrap, /* optional */ override) {
  1263         if (override) {
  1264             this.pairs.unshift([name, check, wrap]);
  1265         } else {
  1266             this.pairs.push([name, check, wrap]);
  1268     },
  1270     /** @id MochiKit.Base.AdapterRegistry.prototype.match */
  1271     match: function (/* ... */) {
  1272         for (var i = 0; i < this.pairs.length; i++) {
  1273             var pair = this.pairs[i];
  1274             if (pair[1].apply(this, arguments)) {
  1275                 return pair[2].apply(this, arguments);
  1278         throw MochiKit.Base.NotFound;
  1279     },
  1281     /** @id MochiKit.Base.AdapterRegistry.prototype.unregister */
  1282     unregister: function (name) {
  1283         for (var i = 0; i < this.pairs.length; i++) {
  1284             var pair = this.pairs[i];
  1285             if (pair[0] == name) {
  1286                 this.pairs.splice(i, 1);
  1287                 return true;
  1290         return false;
  1292 };
  1295 MochiKit.Base.EXPORT = [
  1296     "flattenArray",
  1297     "noop",
  1298     "camelize",
  1299     "counter",
  1300     "clone",
  1301     "extend",
  1302     "update",
  1303     "updatetree",
  1304     "setdefault",
  1305     "keys",
  1306     "values",
  1307     "items",
  1308     "NamedError",
  1309     "operator",
  1310     "forwardCall",
  1311     "itemgetter",
  1312     "typeMatcher",
  1313     "isCallable",
  1314     "isUndefined",
  1315     "isUndefinedOrNull",
  1316     "isNull",
  1317     "isEmpty",
  1318     "isNotEmpty",
  1319     "isArrayLike",
  1320     "isDateLike",
  1321     "xmap",
  1322     "map",
  1323     "xfilter",
  1324     "filter",
  1325     "methodcaller",
  1326     "compose",
  1327     "bind",
  1328     "bindLate",
  1329     "bindMethods",
  1330     "NotFound",
  1331     "AdapterRegistry",
  1332     "registerComparator",
  1333     "compare",
  1334     "registerRepr",
  1335     "repr",
  1336     "objEqual",
  1337     "arrayEqual",
  1338     "concat",
  1339     "keyComparator",
  1340     "reverseKeyComparator",
  1341     "partial",
  1342     "merge",
  1343     "listMinMax",
  1344     "listMax",
  1345     "listMin",
  1346     "objMax",
  1347     "objMin",
  1348     "nodeWalk",
  1349     "zip",
  1350     "urlEncode",
  1351     "queryString",
  1352     "serializeJSON",
  1353     "registerJSON",
  1354     "evalJSON",
  1355     "parseQueryString",
  1356     "findValue",
  1357     "findIdentical",
  1358     "flattenArguments",
  1359     "method",
  1360     "average",
  1361     "mean",
  1362     "median"
  1363 ];
  1365 MochiKit.Base.EXPORT_OK = [
  1366     "nameFunctions",
  1367     "comparatorRegistry",
  1368     "reprRegistry",
  1369     "jsonRegistry",
  1370     "compareDateLike",
  1371     "compareArrayLike",
  1372     "reprArrayLike",
  1373     "reprString",
  1374     "reprNumber"
  1375 ];
  1377 MochiKit.Base._exportSymbols = function (globals, module) {
  1378     if (!MochiKit.__export__) {
  1379         return;
  1381     var all = module.EXPORT_TAGS[":all"];
  1382     for (var i = 0; i < all.length; i++) {
  1383         globals[all[i]] = module[all[i]];
  1385 };
  1387 MochiKit.Base.__new__ = function () {
  1388     // A singleton raised when no suitable adapter is found
  1389     var m = this;
  1391     // convenience
  1392     /** @id MochiKit.Base.noop */
  1393     m.noop = m.operator.identity;
  1395     // Backwards compat
  1396     m.forward = m.forwardCall;
  1397     m.find = m.findValue;
  1399     if (typeof(encodeURIComponent) != "undefined") {
  1400         /** @id MochiKit.Base.urlEncode */
  1401         m.urlEncode = function (unencoded) {
  1402             return encodeURIComponent(unencoded).replace(/\'/g, '%27');
  1403         };
  1404     } else {
  1405         m.urlEncode = function (unencoded) {
  1406             return escape(unencoded
  1407                 ).replace(/\+/g, '%2B'
  1408                 ).replace(/\"/g,'%22'
  1409                 ).rval.replace(/\'/g, '%27');
  1410         };
  1413     /** @id MochiKit.Base.NamedError */
  1414     m.NamedError = function (name) {
  1415         this.message = name;
  1416         this.name = name;
  1417     };
  1418     m.NamedError.prototype = new Error();
  1419     m.update(m.NamedError.prototype, {
  1420         repr: function () {
  1421             if (this.message && this.message != this.name) {
  1422                 return this.name + "(" + m.repr(this.message) + ")";
  1423             } else {
  1424                 return this.name + "()";
  1426         },
  1427         toString: m.forwardCall("repr")
  1428     });
  1430     /** @id MochiKit.Base.NotFound */
  1431     m.NotFound = new m.NamedError("MochiKit.Base.NotFound");
  1434     /** @id MochiKit.Base.listMax */
  1435     m.listMax = m.partial(m.listMinMax, 1);
  1436     /** @id MochiKit.Base.listMin */
  1437     m.listMin = m.partial(m.listMinMax, -1);
  1439     /** @id MochiKit.Base.isCallable */
  1440     m.isCallable = m.typeMatcher('function');
  1441     /** @id MochiKit.Base.isUndefined */
  1442     m.isUndefined = m.typeMatcher('undefined');
  1444     /** @id MochiKit.Base.merge */
  1445     m.merge = m.partial(m.update, null);
  1446     /** @id MochiKit.Base.zip */
  1447     m.zip = m.partial(m.map, null);
  1449     /** @id MochiKit.Base.average */
  1450     m.average = m.mean;
  1452     /** @id MochiKit.Base.comparatorRegistry */
  1453     m.comparatorRegistry = new m.AdapterRegistry();
  1454     m.registerComparator("dateLike", m.isDateLike, m.compareDateLike);
  1455     m.registerComparator("arrayLike", m.isArrayLike, m.compareArrayLike);
  1457     /** @id MochiKit.Base.reprRegistry */
  1458     m.reprRegistry = new m.AdapterRegistry();
  1459     m.registerRepr("arrayLike", m.isArrayLike, m.reprArrayLike);
  1460     m.registerRepr("string", m.typeMatcher("string"), m.reprString);
  1461     m.registerRepr("numbers", m.typeMatcher("number", "boolean"), m.reprNumber);
  1463     /** @id MochiKit.Base.jsonRegistry */
  1464     m.jsonRegistry = new m.AdapterRegistry();
  1466     var all = m.concat(m.EXPORT, m.EXPORT_OK);
  1467     m.EXPORT_TAGS = {
  1468         ":common": m.concat(m.EXPORT_OK),
  1469         ":all": all
  1470     };
  1472     m.nameFunctions(this);
  1474 };
  1476 MochiKit.Base.__new__();
  1478 //
  1479 // XXX: Internet Explorer blows
  1480 //
  1481 if (MochiKit.__export__) {
  1482     compare = MochiKit.Base.compare;
  1483     compose = MochiKit.Base.compose;
  1484     serializeJSON = MochiKit.Base.serializeJSON;
  1485     mean = MochiKit.Base.mean;
  1486     median = MochiKit.Base.median;
  1489 MochiKit.Base._exportSymbols(this, MochiKit.Base);

mercurial