Base.js 35 KB

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