/*** MochiKit.Base 1.3.1 See for documentation, downloads, license, etc. (c) 2005 Bob Ippolito. All rights Reserved. ***/ if (typeof(dojo) != 'undefined') { dojo.provide("MochiKit.Base"); } if (typeof(MochiKit) == 'undefined') { MochiKit = {}; } if (typeof(MochiKit.Base) == 'undefined') { MochiKit.Base = {}; } MochiKit.Base.VERSION = "1.3.1"; MochiKit.Base.NAME = "MochiKit.Base"; MochiKit.Base.update = function (self, obj/*, ... */) { if (self === null) { self = {}; } for (var i = 1; i < arguments.length; i++) { var o = arguments[i]; if (typeof(o) != 'undefined' && o !== null) { for (var k in o) { self[k] = o[k]; } } } return self; }; MochiKit.Base.update(MochiKit.Base, { __repr__: function () { return "[" + this.NAME + " " + this.VERSION + "]"; }, toString: function () { return this.__repr__(); }, counter: function (n/* = 1 */) { if (arguments.length === 0) { n = 1; } return function () { return n++; }; }, clone: function (obj) { var me = arguments.callee; if (arguments.length == 1) { me.prototype = obj; return new me(); } }, flattenArguments: function (lst/* ...*/) { var res = []; var m = MochiKit.Base; var args = m.extend(null, arguments); while (args.length) { var o = args.shift(); if (o && typeof(o) == "object" && typeof(o.length) == "number") { for (var i = o.length - 1; i >= 0; i--) { args.unshift(o[i]); } } else { res.push(o); } } return res; }, extend: function (self, obj, /* optional */skip) { // Extend an array with an array-like object starting // from the skip index if (!skip) { skip = 0; } if (obj) { // allow iterable fall-through, but skip the full isArrayLike // check for speed, this is called often. var l = obj.length; if (typeof(l) != 'number' /* !isArrayLike(obj) */) { if (typeof(MochiKit.Iter) != "undefined") { obj = MochiKit.Iter.list(obj); l = obj.length; } else { throw new TypeError("Argument not an array-like and MochiKit.Iter not present"); } } if (!self) { self = []; } for (var i = skip; i < l; i++) { self.push(obj[i]); } } // This mutates, but it's convenient to return because // it's often used like a constructor when turning some // ghetto array-like to a real array return self; }, updatetree: function (self, obj/*, ...*/) { if (self === null) { self = {}; } for (var i = 1; i < arguments.length; i++) { var o = arguments[i]; if (typeof(o) != 'undefined' && o !== null) { for (var k in o) { var v = o[k]; if (typeof(self[k]) == 'object' && typeof(v) == 'object') { arguments.callee(self[k], v); } else { self[k] = v; } } } } return self; }, setdefault: function (self, obj/*, ...*/) { if (self === null) { self = {}; } for (var i = 1; i < arguments.length; i++) { var o = arguments[i]; for (var k in o) { if (!(k in self)) { self[k] = o[k]; } } } return self; }, keys: function (obj) { var rval = []; for (var prop in obj) { rval.push(prop); } return rval; }, items: function (obj) { var rval = []; var e; for (var prop in obj) { var v; try { v = obj[prop]; } catch (e) { continue; } rval.push([prop, v]); } return rval; }, _newNamedError: function (module, name, func) { func.prototype = new MochiKit.Base.NamedError(module.NAME + "." + name); module[name] = func; }, operator: { // unary logic operators truth: function (a) { return !!a; }, lognot: function (a) { return !a; }, identity: function (a) { return a; }, // bitwise unary operators not: function (a) { return ~a; }, neg: function (a) { return -a; }, // binary operators add: function (a, b) { return a + b; }, sub: function (a, b) { return a - b; }, div: function (a, b) { return a / b; }, mod: function (a, b) { return a % b; }, mul: function (a, b) { return a * b; }, // bitwise binary operators and: function (a, b) { return a & b; }, or: function (a, b) { return a | b; }, xor: function (a, b) { return a ^ b; }, lshift: function (a, b) { return a << b; }, rshift: function (a, b) { return a >> b; }, zrshift: function (a, b) { return a >>> b; }, // near-worthless built-in comparators eq: function (a, b) { return a == b; }, ne: function (a, b) { return a != b; }, gt: function (a, b) { return a > b; }, ge: function (a, b) { return a >= b; }, lt: function (a, b) { return a < b; }, le: function (a, b) { return a <= b; }, // compare comparators ceq: function (a, b) { return MochiKit.Base.compare(a, b) === 0; }, cne: function (a, b) { return MochiKit.Base.compare(a, b) !== 0; }, cgt: function (a, b) { return MochiKit.Base.compare(a, b) == 1; }, cge: function (a, b) { return MochiKit.Base.compare(a, b) != -1; }, clt: function (a, b) { return MochiKit.Base.compare(a, b) == -1; }, cle: function (a, b) { return MochiKit.Base.compare(a, b) != 1; }, // binary logical operators logand: function (a, b) { return a && b; }, logor: function (a, b) { return a || b; }, contains: function (a, b) { return b in a; } }, forwardCall: function (func) { return function () { return this[func].apply(this, arguments); }; }, itemgetter: function (func) { return function (arg) { return arg[func]; }; }, typeMatcher: function (/* typ */) { var types = {}; for (var i = 0; i < arguments.length; i++) { var typ = arguments[i]; types[typ] = typ; } return function () { for (var i = 0; i < arguments.length; i++) { if (!(typeof(arguments[i]) in types)) { return false; } } return true; }; }, isNull: function (/* ... */) { for (var i = 0; i < arguments.length; i++) { if (arguments[i] !== null) { return false; } } return true; }, isUndefinedOrNull: function (/* ... */) { for (var i = 0; i < arguments.length; i++) { var o = arguments[i]; if (!(typeof(o) == 'undefined' || o === null)) { return false; } } return true; }, isEmpty: function (obj) { return !MochiKit.Base.isNotEmpty.apply(this, arguments); }, isNotEmpty: function (obj) { for (var i = 0; i < arguments.length; i++) { var o = arguments[i]; if (!(o && o.length)) { return false; } } return true; }, isArrayLike: function () { for (var i = 0; i < arguments.length; i++) { var o = arguments[i]; var typ = typeof(o); if ( (typ != 'object' && !(typ == 'function' && typeof(o.item) == 'function')) || o === null || typeof(o.length) != 'number' ) { return false; } } return true; }, isDateLike: function () { for (var i = 0; i < arguments.length; i++) { var o = arguments[i]; if (typeof(o) != "object" || o === null || typeof(o.getTime) != 'function') { return false; } } return true; }, xmap: function (fn/*, obj... */) { if (fn === null) { return MochiKit.Base.extend(null, arguments, 1); } var rval = []; for (var i = 1; i < arguments.length; i++) { rval.push(fn(arguments[i])); } return rval; }, map: function (fn, lst/*, lst... */) { var m = MochiKit.Base; var itr = MochiKit.Iter; var isArrayLike = m.isArrayLike; if (arguments.length <= 2) { // allow an iterable to be passed if (!isArrayLike(lst)) { if (itr) { // fast path for map(null, iterable) lst = itr.list(lst); if (fn === null) { return lst; } } else { throw new TypeError("Argument not an array-like and MochiKit.Iter not present"); } } // fast path for map(null, lst) if (fn === null) { return m.extend(null, lst); } // disabled fast path for map(fn, lst) /* if (false && typeof(Array.prototype.map) == 'function') { // Mozilla fast-path return Array.prototype.map.call(lst, fn); } */ var rval = []; for (var i = 0; i < lst.length; i++) { rval.push(fn(lst[i])); } return rval; } else { // default for map(null, ...) is zip(...) if (fn === null) { fn = Array; } var length = null; for (i = 1; i < arguments.length; i++) { // allow iterables to be passed if (!isArrayLike(arguments[i])) { if (itr) { return itr.list(itr.imap.apply(null, arguments)); } else { throw new TypeError("Argument not an array-like and MochiKit.Iter not present"); } } // find the minimum length var l = arguments[i].length; if (length === null || length > l) { length = l; } } rval = []; for (i = 0; i < length; i++) { var args = []; for (var j = 1; j < arguments.length; j++) { args.push(arguments[j][i]); } rval.push(fn.apply(this, args)); } return rval; } }, xfilter: function (fn/*, obj... */) { var rval = []; if (fn === null) { fn = MochiKit.Base.operator.truth; } for (var i = 1; i < arguments.length; i++) { var o = arguments[i]; if (fn(o)) { rval.push(o); } } return rval; }, filter: function (fn, lst, self) { var rval = []; // allow an iterable to be passed var m = MochiKit.Base; if (!m.isArrayLike(lst)) { if (MochiKit.Iter) { lst = MochiKit.Iter.list(lst); } else { throw new TypeError("Argument not an array-like and MochiKit.Iter not present"); } } if (fn === null) { fn = m.operator.truth; } if (typeof(Array.prototype.filter) == 'function') { // Mozilla fast-path return Array.prototype.filter.call(lst, fn, self); } else if (typeof(self) == 'undefined' || self === null) { for (var i = 0; i < lst.length; i++) { var o = lst[i]; if (fn(o)) { rval.push(o); } } } else { for (i = 0; i < lst.length; i++) { o = lst[i]; if (fn.call(self, o)) { rval.push(o); } } } return rval; }, _wrapDumbFunction: function (func) { return function () { // fast path! switch (arguments.length) { case 0: return func(); case 1: return func(arguments[0]); case 2: return func(arguments[0], arguments[1]); case 3: return func(arguments[0], arguments[1], arguments[2]); } var args = []; for (var i = 0; i < arguments.length; i++) { args.push("arguments[" + i + "]"); } return eval("(func(" + args.join(",") + "))"); }; }, method: function (self, func) { var m = MochiKit.Base; return m.bind.apply(this, m.extend([func, self], arguments, 2)); }, bind: function (func, self/* args... */) { if (typeof(func) == "string") { func = self[func]; } var im_func = func.im_func; var im_preargs = func.im_preargs; var im_self = func.im_self; var m = MochiKit.Base; if (typeof(func) == "function" && typeof(func.apply) == "undefined") { // this is for cases where JavaScript sucks ass and gives you a // really dumb built-in function like alert() that doesn't have // an apply func = m._wrapDumbFunction(func); } if (typeof(im_func) != 'function') { im_func = func; } if (typeof(self) != 'undefined') { im_self = self; } if (typeof(im_preargs) == 'undefined') { im_preargs = []; } else { im_preargs = im_preargs.slice(); } m.extend(im_preargs, arguments, 2); var newfunc = function () { var args = arguments; var me = arguments.callee; if (me.im_preargs.length > 0) { args = m.concat(me.im_preargs, args); } var self = me.im_self; if (!self) { self = this; } return me.im_func.apply(self, args); }; newfunc.im_self = im_self; newfunc.im_func = im_func; newfunc.im_preargs = im_preargs; return newfunc; }, bindMethods: function (self) { var bind = MochiKit.Base.bind; for (var k in self) { var func = self[k]; if (typeof(func) == 'function') { self[k] = bind(func, self); } } }, registerComparator: function (name, check, comparator, /* optional */ override) { MochiKit.Base.comparatorRegistry.register(name, check, comparator, override); }, _primitives: {'boolean': true, 'string': true, 'number': true}, compare: function (a, b) { if (a == b) { return 0; } var aIsNull = (typeof(a) == 'undefined' || a === null); var bIsNull = (typeof(b) == 'undefined' || b === null); if (aIsNull && bIsNull) { return 0; } else if (aIsNull) { return -1; } else if (bIsNull) { return 1; } var m = MochiKit.Base; // bool, number, string have meaningful comparisons var prim = m._primitives; if (!(typeof(a) in prim && typeof(b) in prim)) { try { return m.comparatorRegistry.match(a, b); } catch (e) { if (e != m.NotFound) { throw e; } } } if (a < b) { return -1; } else if (a > b) { return 1; } // These types can't be compared var repr = m.repr; throw new TypeError(repr(a) + " and " + repr(b) + " can not be compared"); }, compareDateLike: function (a, b) { return MochiKit.Base.compare(a.getTime(), b.getTime()); }, compareArrayLike: function (a, b) { var compare = MochiKit.Base.compare; var count = a.length; var rval = 0; if (count > b.length) { rval = 1; count = b.length; } else if (count < b.length) { rval = -1; } for (var i = 0; i < count; i++) { var cmp = compare(a[i], b[i]); if (cmp) { return cmp; } } return rval; }, registerRepr: function (name, check, wrap, /* optional */override) { MochiKit.Base.reprRegistry.register(name, check, wrap, override); }, repr: function (o) { if (typeof(o) == "undefined") { return "undefined"; } else if (o === null) { return "null"; } try { if (typeof(o.__repr__) == 'function') { return o.__repr__(); } else if (typeof(o.repr) == 'function' && o.repr != arguments.callee) { return o.repr(); } return MochiKit.Base.reprRegistry.match(o); } catch (e) { if (typeof(o.NAME) == 'string' && ( o.toString == Function.prototype.toString || o.toString == Object.prototype.toString )) { return o.NAME; } } try { var ostring = (o + ""); } catch (e) { return "[" + typeof(o) + "]"; } if (typeof(o) == "function") { o = ostring.replace(/^\s+/, ""); var idx = o.indexOf("{"); if (idx != -1) { o = o.substr(0, idx) + "{...}"; } } return ostring; }, reprArrayLike: function (o) { var m = MochiKit.Base; return "[" + m.map(m.repr, o).join(", ") + "]"; }, reprString: function (o) { return ('"' + o.replace(/(["\\])/g, '\\$1') + '"' ).replace(/[\f]/g, "\\f" ).replace(/[\b]/g, "\\b" ).replace(/[\n]/g, "\\n" ).replace(/[\t]/g, "\\t" ).replace(/[\r]/g, "\\r"); }, reprNumber: function (o) { return o + ""; }, registerJSON: function (name, check, wrap, /* optional */override) { MochiKit.Base.jsonRegistry.register(name, check, wrap, override); }, evalJSON: function () { return eval("(" + arguments[0] + ")"); }, serializeJSON: function (o) { var objtype = typeof(o); if (objtype == "undefined") { return "undefined"; } else if (objtype == "number" || objtype == "boolean") { return o + ""; } else if (o === null) { return "null"; } var m = MochiKit.Base; var reprString = m.reprString; if (objtype == "string") { return reprString(o); } // recurse var me = arguments.callee; // short-circuit for objects that support "json" serialization // if they return "self" then just pass-through... var newObj; if (typeof(o.__json__) == "function") { newObj = o.__json__(); if (o !== newObj) { return me(newObj); } } if (typeof(o.json) == "function") { newObj = o.json(); if (o !== newObj) { return me(newObj); } } // array if (objtype != "function" && typeof(o.length) == "number") { var res = []; for (var i = 0; i < o.length; i++) { var val = me(o[i]); if (typeof(val) != "string") { val = "undefined"; } res.push(val); } return "[" + res.join(", ") + "]"; } // look in the registry try { newObj = m.jsonRegistry.match(o); return me(newObj); } catch (e) { if (e != m.NotFound) { // something really bad happened throw e; } } // it's a function with no adapter, bad if (objtype == "function") { return null; } // generic object code path res = []; for (var k in o) { var useKey; if (typeof(k) == "number") { useKey = '"' + k + '"'; } else if (typeof(k) == "string") { useKey = reprString(k); } else { // skip non-string or number keys continue; } val = me(o[k]); if (typeof(val) != "string") { // skip non-serializable values continue; } res.push(useKey + ":" + val); } return "{" + res.join(", ") + "}"; }, objEqual: function (a, b) { return (MochiKit.Base.compare(a, b) === 0); }, arrayEqual: function (self, arr) { if (self.length != arr.length) { return false; } return (MochiKit.Base.compare(self, arr) === 0); }, concat: function (/* lst... */) { var rval = []; var extend = MochiKit.Base.extend; for (var i = 0; i < arguments.length; i++) { extend(rval, arguments[i]); } return rval; }, keyComparator: function (key/* ... */) { // fast-path for single key comparisons var m = MochiKit.Base; var compare = m.compare; if (arguments.length == 1) { return function (a, b) { return compare(a[key], b[key]); }; } var compareKeys = m.extend(null, arguments); return function (a, b) { var rval = 0; // keep comparing until something is inequal or we run out of // keys to compare for (var i = 0; (rval === 0) && (i < compareKeys.length); i++) { var key = compareKeys[i]; rval = compare(a[key], b[key]); } return rval; }; }, reverseKeyComparator: function (key) { var comparator = MochiKit.Base.keyComparator.apply(this, arguments); return function (a, b) { return comparator(b, a); }; }, partial: function (func) { var m = MochiKit.Base; return m.bind.apply(this, m.extend([func, undefined], arguments, 1)); }, listMinMax: function (which, lst) { if (lst.length === 0) { return null; } var cur = lst[0]; var compare = MochiKit.Base.compare; for (var i = 1; i < lst.length; i++) { var o = lst[i]; if (compare(o, cur) == which) { cur = o; } } return cur; }, objMax: function (/* obj... */) { return MochiKit.Base.listMinMax(1, arguments); }, objMin: function (/* obj... */) { return MochiKit.Base.listMinMax(-1, arguments); }, findIdentical: function (lst, value, start/* = 0 */, /* optional */end) { if (typeof(end) == "undefined" || end === null) { end = lst.length; } for (var i = (start || 0); i < end; i++) { if (lst[i] === value) { return i; } } return -1; }, findValue: function (lst, value, start/* = 0 */, /* optional */end) { if (typeof(end) == "undefined" || end === null) { end = lst.length; } var cmp = MochiKit.Base.compare; for (var i = (start || 0); i < end; i++) { if (cmp(lst[i], value) === 0) { return i; } } return -1; }, nodeWalk: function (node, visitor) { var nodes = [node]; var extend = MochiKit.Base.extend; while (nodes.length) { var res = visitor(nodes.shift()); if (res) { extend(nodes, res); } } }, nameFunctions: function (namespace) { var base = namespace.NAME; if (typeof(base) == 'undefined') { base = ''; } else { base = base + '.'; } for (var name in namespace) { var o = namespace[name]; if (typeof(o) == 'function' && typeof(o.NAME) == 'undefined') { try { o.NAME = base + name; } catch (e) { // pass } } } }, queryString: function (names, values) { // check to see if names is a string or a DOM element, and if // MochiKit.DOM is available. If so, drop it like it's a form // Ugliest conditional in MochiKit? Probably! if (typeof(MochiKit.DOM) != "undefined" && arguments.length == 1 && (typeof(names) == "string" || ( typeof(names.nodeType) != "undefined" && names.nodeType > 0 )) ) { var kv = MochiKit.DOM.formContents(names); names = kv[0]; values = kv[1]; } else if (arguments.length == 1) { var o = names; names = []; values = []; for (var k in o) { var v = o[k]; if (typeof(v) != "function") { names.push(k); values.push(v); } } } var rval = []; var len = Math.min(names.length, values.length); var urlEncode = MochiKit.Base.urlEncode; for (var i = 0; i < len; i++) { v = values[i]; if (typeof(v) != 'undefined' && v !== null) { rval.push(urlEncode(names[i]) + "=" + urlEncode(v)); } } return rval.join("&"); }, parseQueryString: function (encodedString, useArrays) { var pairs = encodedString.replace(/\+/g, "%20").split("&"); var o = {}; var decode; if (typeof(decodeURIComponent) != "undefined") { decode = decodeURIComponent; } else { decode = unescape; } if (useArrays) { for (var i = 0; i < pairs.length; i++) { var pair = pairs[i].split("="); var name = decode(pair[0]); var arr = o[name]; if (!(arr instanceof Array)) { arr = []; o[name] = arr; } arr.push(decode(pair[1])); } } else { for (i = 0; i < pairs.length; i++) { pair = pairs[i].split("="); o[decode(pair[0])] = decode(pair[1]); } } return o; } }); MochiKit.Base.AdapterRegistry = function () { this.pairs = []; }; MochiKit.Base.AdapterRegistry.prototype = { register: function (name, check, wrap, /* optional */ override) { if (override) { this.pairs.unshift([name, check, wrap]); } else { this.pairs.push([name, check, wrap]); } }, match: function (/* ... */) { for (var i = 0; i < this.pairs.length; i++) { var pair = this.pairs[i]; if (pair[1].apply(this, arguments)) { return pair[2].apply(this, arguments); } } throw MochiKit.Base.NotFound; }, unregister: function (name) { for (var i = 0; i < this.pairs.length; i++) { var pair = this.pairs[i]; if (pair[0] == name) { this.pairs.splice(i, 1); return true; } } return false; } }; MochiKit.Base.EXPORT = [ "counter", "clone", "extend", "update", "updatetree", "setdefault", "keys", "items", "NamedError", "operator", "forwardCall", "itemgetter", "typeMatcher", "isCallable", "isUndefined", "isUndefinedOrNull", "isNull", "isEmpty", "isNotEmpty", "isArrayLike", "isDateLike", "xmap", "map", "xfilter", "filter", "bind", "bindMethods", "NotFound", "AdapterRegistry", "registerComparator", "compare", "registerRepr", "repr", "objEqual", "arrayEqual", "concat", "keyComparator", "reverseKeyComparator", "partial", "merge", "listMinMax", "listMax", "listMin", "objMax", "objMin", "nodeWalk", "zip", "urlEncode", "queryString", "serializeJSON", "registerJSON", "evalJSON", "parseQueryString", "findValue", "findIdentical", "flattenArguments", "method" ]; MochiKit.Base.EXPORT_OK = [ "nameFunctions", "comparatorRegistry", "reprRegistry", "jsonRegistry", "compareDateLike", "compareArrayLike", "reprArrayLike", "reprString", "reprNumber" ]; MochiKit.Base._exportSymbols = function (globals, module) { if (typeof(MochiKit.__export__) == "undefined") { MochiKit.__export__ = (MochiKit.__compat__ || (typeof(JSAN) == 'undefined' && typeof(dojo) == 'undefined') ); } if (!MochiKit.__export__) { return; } var all = module.EXPORT_TAGS[":all"]; for (var i = 0; i < all.length; i++) { globals[all[i]] = module[all[i]]; } }; MochiKit.Base.__new__ = function () { // A singleton raised when no suitable adapter is found var m = this; // Backwards compat m.forward = m.forwardCall; m.find = m.findValue; if (typeof(encodeURIComponent) != "undefined") { m.urlEncode = function (unencoded) { return encodeURIComponent(unencoded).replace(/\'/g, '%27'); }; } else { m.urlEncode = function (unencoded) { return escape(unencoded ).replace(/\+/g, '%2B' ).replace(/\"/g,'%22' ).rval.replace(/\'/g, '%27'); }; } m.NamedError = function (name) { this.message = name; this.name = name; }; m.NamedError.prototype = new Error(); m.update(m.NamedError.prototype, { repr: function () { if (this.message && this.message != this.name) { return this.name + "(" + m.repr(this.message) + ")"; } else { return this.name + "()"; } }, toString: m.forwardCall("repr") }); m.NotFound = new m.NamedError("MochiKit.Base.NotFound"); m.listMax = m.partial(m.listMinMax, 1); m.listMin = m.partial(m.listMinMax, -1); m.isCallable = m.typeMatcher('function'); m.isUndefined = m.typeMatcher('undefined'); m.merge = m.partial(m.update, null); m.zip = m.partial(m.map, null); m.comparatorRegistry = new m.AdapterRegistry(); m.registerComparator("dateLike", m.isDateLike, m.compareDateLike); m.registerComparator("arrayLike", m.isArrayLike, m.compareArrayLike); m.reprRegistry = new m.AdapterRegistry(); m.registerRepr("arrayLike", m.isArrayLike, m.reprArrayLike); m.registerRepr("string", m.typeMatcher("string"), m.reprString); m.registerRepr("numbers", m.typeMatcher("number", "boolean"), m.reprNumber); m.jsonRegistry = new m.AdapterRegistry(); var all = m.concat(m.EXPORT, m.EXPORT_OK); m.EXPORT_TAGS = { ":common": m.concat(m.EXPORT_OK), ":all": all }; m.nameFunctions(this); }; MochiKit.Base.__new__(); // // XXX: Internet Explorer blows // if (!MochiKit.__compat__) { compare = MochiKit.Base.compare; } MochiKit.Base._exportSymbols(this, MochiKit.Base);