/js/stdlib.js
JavaScript | 2443 lines | 2014 code | 425 blank | 4 comment | 411 complexity | f79784df606caed8dff9ab1b700c7115 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- JS.MethodChain = function(base) {
- var queue = [],
- baseObject = base || {};
-
- this.____ = function(method, args) {
- queue.push({func: method, args: args});
- };
-
- this.fire = function(base) {
- return JS.MethodChain.fire(queue, base || baseObject);
- };
- };
- JS.MethodChain.fire = function(queue, object) {
- var method, property, i, n;
- loop: for (i = 0, n = queue.length; i < n; i++) {
- method = queue[i];
- if (object instanceof JS.MethodChain) {
- object.____(method.func, method.args);
- continue;
- }
- switch (typeof method.func) {
- case 'string': property = object[method.func]; break;
- case 'function': property = method.func; break;
- case 'object': object = method.func; continue loop; break;
- }
- object = (typeof property === 'function')
- ? property.apply(object, method.args)
- : property;
- }
- return object;
- };
- JS.MethodChain.prototype = {
- _: function() {
- var base = arguments[0],
- args, i, n;
-
- switch (typeof base) {
- case 'object': case 'function':
- args = [];
- for (i = 1, n = arguments.length; i < n; i++) args.push(arguments[i]);
- this.____(base, args);
- }
- return this;
- },
-
- toFunction: function() {
- var chain = this;
- return function(object) { return chain.fire(object); };
- }
- };
- JS.MethodChain.reserved = (function() {
- var names = [], key;
- for (key in new JS.MethodChain) names.push(key);
- return new RegExp('^(?:' + names.join('|') + ')$');
- })();
- JS.MethodChain.addMethod = function(name) {
- if (this.reserved.test(name)) return;
- var func = this.prototype[name] = function() {
- this.____(name, arguments);
- return this;
- };
- func.displayName = 'MethodChain#' + name;
- };
- JS.MethodChain.displayName = 'MethodChain';
- JS.MethodChain.addMethods = function(object) {
- var methods = [], property, i;
-
- for (property in object)
- Number(property) !== property && methods.push(property);
-
- if (object instanceof Array) {
- i = object.length;
- while (i--)
- typeof object[i] === 'string' && methods.push(object[i]);
- }
- i = methods.length;
- while (i--) this.addMethod(methods[i]);
-
- object.prototype &&
- this.addMethods(object.prototype);
- };
- it = its = function() { return new JS.MethodChain; };
- JS.Module.methodAdded(function(name) {
- JS.MethodChain.addMethod(name);
- });
- JS.Kernel.include({
- wait: function(time) {
- var chain = new JS.MethodChain;
-
- typeof time === 'number' &&
- setTimeout(chain.fire.bind(chain, this), time * 1000);
-
- this.forEach && typeof time === 'function' &&
- this.forEach(function() {
- setTimeout(chain.fire.bind(chain, arguments[0]), time.apply(this, arguments) * 1000);
- });
-
- return chain;
- },
-
- _: function() {
- var base = arguments[0],
- args = [],
- i, n;
-
- for (i = 1, n = arguments.length; i < n; i++) args.push(arguments[i]);
- return (typeof base === 'object' && base) ||
- (typeof base === 'function' && base.apply(this, args)) ||
- this;
- }
- }, true);
- JS.MethodChain.addMethods([
- "abbr", "abs", "accept", "acceptCharset", "accesskey", "acos", "action", "addEventListener",
- "adjacentNode", "align", "alignWithTop", "alink", "alt", "anchor", "appendChild", "appendedNode",
- "apply", "archive", "arguments", "arity", "asin", "atan", "atan2", "attrNode", "attributes",
- "axis", "background", "bgcolor", "big", "blink", "blur", "bold", "border", "call", "caller",
- "ceil", "cellpadding", "cellspacing", "char", "charAt", "charCodeAt", "charoff", "charset",
- "checked", "childNodes", "cite", "className", "classid", "clear", "click", "clientHeight",
- "clientLeft", "clientTop", "clientWidth", "cloneNode", "code", "codebase", "codetype", "color",
- "cols", "colspan", "compact", "concat", "content", "coords", "cos", "data", "datetime", "declare",
- "deep", "defer", "dir", "disabled", "dispatchEvent", "enctype", "event", "every", "exec", "exp",
- "face", "filter", "firstChild", "fixed", "floor", "focus", "fontcolor", "fontsize", "forEach",
- "frame", "frameborder", "fromCharCode", "getAttribute", "getAttributeNS", "getAttributeNode",
- "getAttributeNodeNS", "getDate", "getDay", "getElementsByTagName", "getElementsByTagNameNS",
- "getFullYear", "getHours", "getMilliseconds", "getMinutes", "getMonth", "getSeconds", "getTime",
- "getTimezoneOffset", "getUTCDate", "getUTCDay", "getUTCFullYear", "getUTCHours",
- "getUTCMilliseconds", "getUTCMinutes", "getUTCMonth", "getUTCSeconds", "getYear", "global",
- "handler", "hasAttribute", "hasAttributeNS", "hasAttributes", "hasChildNodes", "hasOwnProperty",
- "headers", "height", "href", "hreflang", "hspace", "htmlFor", "httpEquiv", "id", "ignoreCase",
- "index", "indexOf", "innerHTML", "input", "insertBefore", "insertedNode", "isPrototypeOf", "ismap",
- "italics", "join", "label", "lang", "language", "lastChild", "lastIndex", "lastIndexOf", "length",
- "link", "listener", "localName", "log", "longdesc", "map", "marginheight", "marginwidth", "match",
- "max", "maxlength", "media", "method", "min", "multiline", "multiple", "name", "namespace",
- "namespaceURI", "nextSibling", "node", "nodeName", "nodeType", "nodeValue", "nohref", "noresize",
- "normalize", "noshade", "now", "nowrap", "object", "offsetHeight", "offsetLeft", "offsetParent",
- "offsetTop", "offsetWidth", "onblur", "onchange", "onclick", "ondblclick", "onfocus", "onkeydown",
- "onkeypress", "onkeyup", "onload", "onmousedown", "onmousemove", "onmouseout", "onmouseover",
- "onmouseup", "onreset", "onselect", "onsubmit", "onunload", "ownerDocument", "parentNode", "parse",
- "pop", "pow", "prefix", "previousSibling", "profile", "prompt", "propertyIsEnumerable", "push",
- "random", "readonly", "reduce", "reduceRight", "rel", "removeAttribute", "removeAttributeNS",
- "removeAttributeNode", "removeChild", "removeEventListener", "removedNode", "replace",
- "replaceChild", "replacedNode", "rev", "reverse", "round", "rows", "rowspan", "rules", "scheme",
- "scope", "scrollHeight", "scrollIntoView", "scrollLeft", "scrollTop", "scrollWidth", "scrolling",
- "search", "selected", "setAttribute", "setAttributeNS", "setAttributeNode", "setAttributeNodeNS",
- "setDate", "setFullYear", "setHours", "setMilliseconds", "setMinutes", "setMonth", "setSeconds",
- "setTime", "setUTCDate", "setUTCFullYear", "setUTCHours", "setUTCMilliseconds", "setUTCMinutes",
- "setUTCMonth", "setUTCSeconds", "setYear", "shape", "shift", "sin", "size", "slice", "small",
- "some", "sort", "source", "span", "splice", "split", "sqrt", "src", "standby", "start", "strike",
- "style", "sub", "substr", "substring", "summary", "sup", "tabIndex", "tabindex", "tagName", "tan",
- "target", "test", "text", "textContent", "title", "toArray", "toFunction", "toGMTString",
- "toLocaleDateString", "toLocaleFormat", "toLocaleString", "toLocaleTimeString", "toLowerCase",
- "toSource", "toString", "toUTCString", "toUpperCase", "type", "unshift", "unwatch", "useCapture",
- "usemap", "valign", "value", "valueOf", "valuetype", "version", "vlink", "vspace", "watch", "width"
- ]);
- JS.Package = new JS.Class('Package', {
- initialize: function(loader) {
- this._loader = loader;
- this._deps = [];
- this._uses = [];
- this._names = [];
- this._waiters = [];
- this._loading = false;
- },
-
- addDependency: function(pkg) {
- if (JS.indexOf(this._deps, pkg) === -1) this._deps.push(pkg);
- },
-
- addSoftDependency: function(pkg) {
- if (JS.indexOf(this._uses, pkg) === -1) this._uses.push(pkg);
- },
-
- _getPackage: function(list, index) {
- var pkg = list[index];
- if (typeof pkg === 'string') pkg = list[index] = this.klass.getByName(pkg);
- return pkg;
- },
-
- addName: function(name) {
- if (!this.contains(name)) this._names.push(name);
- },
-
- contains: function(name) {
- return JS.indexOf(this._names, name) !== -1;
- },
-
- depsComplete: function(deps) {
- deps = deps || this._deps;
- var n = deps.length, dep;
- while (n--) {
- if (!this._getPackage(deps, n).isComplete()) return false;
- }
- return true;
- },
-
- isComplete: function() {
- return this.isLoaded() &&
- this.depsComplete(this._deps) &&
- this.depsComplete(this._uses);
- },
-
- isLoaded: function(withExceptions) {
- if (this._isLoaded) return true;
-
- var names = this._names,
- n = names.length,
- object;
-
- while (n--) {
- object = this.klass.getObject(names[n]);
- if (object !== undefined) continue;
- if (withExceptions)
- throw new Error('Expected package at ' + this._loader + ' to define ' + names[n]);
- else
- return false;
- }
- return this._isLoaded = true;
- },
-
- readyToLoad: function() {
- return !this.isLoaded() && this.depsComplete();
- },
-
- expand: function(list) {
- var deps = list || [], dep, n;
- n = this._deps.length;
- while (n--) this._getPackage(this._deps, n).expand(deps);
- if (JS.indexOf(deps, this) === -1) deps.push(this);
- n = this._uses.length;
- while (n--) this._getPackage(this._uses, n).expand(deps);
- return deps;
- },
-
- onload: function(block) {
- this._onload = block;
- },
-
- load: function(callback, context) {
- var self = this, handler, fireCallbacks;
-
- handler = function() {
- self._loading = false;
- callback.call(context || null);
- };
-
- if (this.isLoaded()) return setTimeout(handler, 1);
-
- this._waiters.push(handler);
- if (this._loading) return;
-
- fireCallbacks = function() {
- if (JS.isFn(self._onload)) self._onload();
- self.isLoaded(true);
- for (var i = 0, n = self._waiters.length; i < n; i++) self._waiters[i]();
- self._waiters = [];
- };
-
- this._loading = true;
-
- JS.isFn(this._loader)
- ? this._loader(fireCallbacks)
- : this.klass.Loader.loadFile(this._loader, fireCallbacks);
- },
-
- toString: function() {
- return 'Package:' + this._names[0];
- },
-
- extend: {
- _store: {},
- _env: this,
-
- getByPath: function(loader) {
- var path = loader.toString();
- return this._store[path] || (this._store[path] = new this(loader));
- },
-
- getByName: function(name) {
- for (var path in this._store) {
- if (this._store[path].contains(name))
- return this._store[path];
- }
- throw new Error('Could not find package containing ' + name);
- },
-
- getObject: function(name) {
- var object = this._env,
- parts = name.split('.'), part;
-
- while (part = parts.shift()) object = (object||{})[part];
- return object;
- },
-
- expand: function(list) {
- var packages = [], i, n;
- for (i = 0, n = list.length; i < n; i++)
- list[i].expand(packages);
- return packages;
- },
-
- load: function(list, counter, callback) {
- var ready = [],
- deferred = [],
- n = list.length,
- pkg;
-
- while (n--) {
- pkg = list[n];
- if (pkg.isComplete())
- counter -= 1;
- else
- (pkg.readyToLoad() ? ready : deferred).push(pkg);
- }
-
- if (counter === 0) return callback();
-
- n = ready.length;
- while (n--) ready[n].load(function() {
- this.load(deferred, --counter, callback);
- }, this);
- }
- }
- });
- JS.Package.extend({
- DomLoader: {
- usable: function() {
- return !!JS.Package.getObject('window.document.getElementsByTagName');
- },
-
- __FILE__: function() {
- var scripts = document.getElementsByTagName('script');
- return scripts[scripts.length - 1].src;
- },
-
- loadFile: function(path, fireCallbacks) {
- var self = this,
- tag = document.createElement('script');
-
- tag.type = 'text/javascript';
- tag.src = path;
-
- tag.onload = tag.onreadystatechange = function() {
- var state = tag.readyState, status = tag.status;
- if ( !state || state === 'loaded' || state === 'complete' || (state === 4 && status === 200) ) {
- fireCallbacks();
- tag.onload = tag.onreadystatechange = self._K;
- tag = null;
- }
- };
- ;;; window.console && console.info('Loading ' + path);
- document.getElementsByTagName('head')[0].appendChild(tag);
- },
-
- _K: function() {}
- },
-
- ServerLoader: {
- usable: function() {
- return JS.isFn(JS.Package.getObject('load')) &&
- JS.isFn(JS.Package.getObject('version'));
- },
-
- setup: function() {
- var self = this;
- load = (function(origLoad) {
- return function() {
- self._currentPath = arguments[0];
- return origLoad.apply(JS.Package._env, arguments);
- };
- })(load);
- },
-
- __FILE__: function() {
- return this._currentPath;
- },
-
- loadFile: function(path, fireCallbacks) {
- load(path);
- fireCallbacks();
- }
- }
- });
- (function() {
- var candidates = [ JS.Package.DomLoader,
- JS.Package.ServerLoader ],
-
- n = candidates.length,
- i, candidate;
-
- for (i = 0; i < n; i++) {
- candidate = candidates[i];
- if (candidate.usable()) {
- JS.Package.Loader = candidate;
- if (candidate.setup) candidate.setup();
- break;
- }
- }
- })();
- JS.Package.extend({
- DSL: {
- __FILE__: function() {
- return JS.Package.Loader.__FILE__();
- },
-
- pkg: function(name, path) {
- var pkg = path
- ? JS.Package.getByPath(path)
- : JS.Package.getByName(name);
- pkg.addName(name);
- return new JS.Package.Description(pkg);
- },
-
- file: function(path) {
- var pkg = JS.Package.getByPath(path);
- return new JS.Package.Description(pkg);
- },
-
- load: function(path, fireCallbacks) {
- JS.Package.loadFile(path, fireCallbacks);
- }
- },
-
- Description: new JS.Class({
- initialize: function(pkg) {
- this._pkg = pkg;
- },
-
- _batch: function(method, args) {
- var n = args.length, method = this._pkg[method], i;
- for (i = 0; i < n; i++) method.call(this._pkg, args[i]);
- return this;
- },
-
- provides: function() {
- return this._batch('addName', arguments);
- },
-
- requires: function() {
- return this._batch('addDependency', arguments);
- },
-
- uses: function() {
- return this._batch('addSoftDependency', arguments);
- },
-
- setup: function(block) {
- this._pkg.onload(block);
- return this;
- }
- })
- });
- JS.Package.DSL.loader = JS.Package.DSL.file;
- JS.Packages = function(declaration) {
- declaration.call(JS.Package.DSL);
- };
-
- JS.require = function() {
- var args = JS.array(arguments),
- requirements = [];
-
- while (typeof args[0] === 'string') requirements.push(JS.Package.getByName(args.shift()));
- requirements = JS.Package.expand(requirements);
-
- var fired = false, handler = function() {
- if (fired) return;
- fired = true;
- args[0] && args[0].call(args[1] || null);
- };
-
- JS.Package.load(requirements, requirements.length, handler);
- };
- require = JS.require;
- JS.Comparable = new JS.Module('Comparable', {
- extend: {
- ClassMethods: new JS.Module({
- compare: function(one, another) {
- return one.compareTo(another);
- }
- }),
-
- included: function(base) {
- base.extend(this.ClassMethods);
- }
- },
-
- lt: function(other) {
- return this.compareTo(other) < 0;
- },
-
- lte: function(other) {
- return this.compareTo(other) < 1;
- },
-
- gt: function(other) {
- return this.compareTo(other) > 0;
- },
-
- gte: function(other) {
- return this.compareTo(other) > -1;
- },
-
- eq: function(other) {
- return this.compareTo(other) === 0;
- },
-
- between: function(a, b) {
- return this.gte(a) && this.lte(b);
- }
- });
- JS.Enumerable = new JS.Module('Enumerable', {
- extend: {
- forEach: function(block, context) {
- if (!block) return new JS.Enumerator(this, 'forEach');
- for (var i = 0, n = this.length; i < n; i++) {
- if (this[i] !== undefined)
- block.call(context || null, this[i]);
- }
- return this;
- },
-
- isComparable: function(list) {
- return list.all(function(item) { return JS.isFn(item.compareTo) });
- },
-
- areEqual: function(one, another) {
- return one.equals
- ? one.equals(another)
- : (one === another);
- },
-
- Collection: new JS.Class({
- initialize: function(array) {
- this.length = 0;
- var push = Array.prototype.push;
- JS.Enumerable.forEach.call(array, function(item) {
- push.call(this, item);
- }, this);
- }
- })
- },
-
- all: function(block, context) {
- block = JS.Enumerable.toFn(block);
- var truth = true;
- this.forEach(function(item) {
- truth = truth && (block ? block.apply(context || null, arguments) : item);
- });
- return !!truth;
- },
-
- any: function(block, context) {
- block = JS.Enumerable.toFn(block);
- var truth = false;
- this.forEach(function(item) {
- truth = truth || (block ? block.apply(context || null, arguments) : item);
- });
- return !!truth;
- },
-
- count: function(block, context) {
- if (JS.isFn(this.size)) return this.size();
- var count = 0, object = block;
-
- if (block && !JS.isFn(block))
- block = function(x) { return JS.Enumerable.areEqual(x, object) };
-
- this.forEach(function() {
- if (!block || block.apply(context || null, arguments))
- count += 1;
- });
- return count;
- },
-
- cycle: function(n, block, context) {
- if (!block) return this.enumFor('cycle', n);
- block = JS.Enumerable.toFn(block);
- while (n--) this.forEach(block, context);
- },
-
- drop: function(n) {
- var entries = [];
- this.forEachWithIndex(function(item, i) {
- if (i >= n) entries.push(item);
- });
- return entries;
- },
-
- dropWhile: function(block, context) {
- if (!block) return this.enumFor('dropWhile');
- block = JS.Enumerable.toFn(block);
-
- var entries = [],
- drop = true;
-
- this.forEach(function(item) {
- if (drop) drop = drop && block.apply(context || null, arguments);
- if (!drop) entries.push(item);
- });
- return entries;
- },
-
- forEachCons: function(n, block, context) {
- if (!block) return this.enumFor('forEachCons', n);
- block = JS.Enumerable.toFn(block);
-
- var entries = this.toArray(),
- size = entries.length,
- limit = size - n,
- i;
-
- for (i = 0; i <= limit; i++)
- block.call(context || null, entries.slice(i, i+n));
-
- return this;
- },
-
- forEachSlice: function(n, block, context) {
- if (!block) return this.enumFor('forEachSlice', n);
- block = JS.Enumerable.toFn(block);
-
- var entries = this.toArray(),
- size = entries.length,
- m = Math.ceil(size/n),
- i;
-
- for (i = 0; i < m; i++)
- block.call(context || null, entries.slice(i*n, (i+1)*n));
-
- return this;
- },
-
- forEachWithIndex: function(offset, block, context) {
- if (JS.isFn(offset)) {
- context = block;
- block = offset;
- offset = 0;
- }
- offset = offset || 0;
-
- if (!block) return this.enumFor('forEachWithIndex', offset);
- block = JS.Enumerable.toFn(block);
-
- return this.forEach(function(item) {
- var result = block.call(context || null, item, offset);
- offset += 1;
- return result;
- });
- },
-
- forEachWithObject: function(object, block, context) {
- if (!block) return this.enumFor('forEachWithObject', object);
- block = JS.Enumerable.toFn(block);
-
- this.forEach(function() {
- var args = [object].concat(JS.array(arguments));
- block.apply(context || null, args);
- });
- return object;
- },
-
- find: function(block, context) {
- if (!block) return this.enumFor('find');
- block = JS.Enumerable.toFn(block);
-
- var needle = {}, K = needle;
- this.forEach(function(item) {
- if (needle !== K) return;
- needle = block.apply(context || null, arguments) ? item : needle;
- });
- return needle === K ? null : needle;
- },
-
- findIndex: function(needle, context) {
- if (needle === undefined) return this.enumFor('findIndex');
-
- var index = null,
- block = JS.isFn(needle);
-
- this.forEachWithIndex(function(item, i) {
- if (index !== null) return;
- if (JS.Enumerable.areEqual(needle, item) || (block && needle.apply(context || null, arguments)))
- index = i;
- });
- return index;
- },
-
- first: function(n) {
- var entries = this.toArray();
- return (n === undefined) ? entries[0] : entries.slice(0,n);
- },
-
- grep: function(pattern, block, context) {
- block = JS.Enumerable.toFn(block);
- var results = [];
- this.forEach(function(item) {
- var match = JS.isFn(pattern.match) ? pattern.match(item) : pattern(item);
- if (!match) return;
- if (block) item = block.apply(context || null, arguments);
- results.push(item);
- });
- return results;
- },
-
- groupBy: function(block, context) {
- if (!block) return this.enumFor('groupBy');
- block = JS.Enumerable.toFn(block);
-
- var hash = new JS.Hash();
- this.forEach(function(item) {
- var value = block.apply(context || null, arguments);
- if (!hash.hasKey(value)) hash.store(value, []);
- hash.get(value).push(item);
- });
- return hash;
- },
-
- inject: function(memo, block, context) {
- var args = JS.array(arguments),
- counter = 0,
- K = {};
-
- switch (args.length) {
- case 1: memo = K;
- block = args[0];
- break;
-
- case 2: if (JS.isFn(memo)) {
- memo = K;
- block = args[0];
- context = args[1];
- }
- }
- block = JS.Enumerable.toFn(block);
-
- this.forEach(function(item) {
- if (!counter++ && memo === K) return memo = item;
- var args = [memo].concat(JS.array(arguments));
- memo = block.apply(context || null, args);
- });
- return memo;
- },
-
- map: function(block, context) {
- if (!block) return this.enumFor('map');
- block = JS.Enumerable.toFn(block);
-
- var map = [];
- this.forEach(function() {
- map.push(block.apply(context || null, arguments));
- });
- return map;
- },
-
- max: function(block, context) {
- return this.minmax(block, context)[1];
- },
-
- maxBy: function(block, context) {
- if (!block) return this.enumFor('maxBy');
- return this.minmaxBy(block, context)[1];
- },
-
- member: function(needle) {
- return this.any(function(item) { return JS.Enumerable.areEqual(item, needle) });
- },
-
- min: function(block, context) {
- return this.minmax(block, context)[0];
- },
-
- minBy: function(block, context) {
- if (!block) return this.enumFor('minBy');
- return this.minmaxBy(block, context)[0];
- },
-
- minmax: function(block, context) {
- var list = this.sort(block, context);
- return [list[0], list[list.length - 1]];
- },
-
- minmaxBy: function(block, context) {
- if (!block) return this.enumFor('minmaxBy');
- var list = this.sortBy(block, context);
- return [list[0], list[list.length - 1]];
- },
-
- none: function(block, context) {
- return !this.any(block, context);
- },
-
- one: function(block, context) {
- block = JS.Enumerable.toFn(block);
- var count = 0;
- this.forEach(function(item) {
- if (block ? block.apply(context || null, arguments) : item) count += 1;
- });
- return count === 1;
- },
-
- partition: function(block, context) {
- if (!block) return this.enumFor('partition');
- block = JS.Enumerable.toFn(block);
-
- var ayes = [], noes = [];
- this.forEach(function(item) {
- (block.apply(context || null, arguments) ? ayes : noes).push(item);
- });
- return [ayes, noes];
- },
-
- reject: function(block, context) {
- if (!block) return this.enumFor('reject');
- block = JS.Enumerable.toFn(block);
-
- var map = [];
- this.forEach(function(item) {
- if (!block.apply(context || null, arguments)) map.push(item);
- });
- return map;
- },
-
- reverseForEach: function(block, context) {
- if (!block) return this.enumFor('reverseForEach');
- block = JS.Enumerable.toFn(block);
-
- var entries = this.toArray(),
- n = entries.length;
-
- while (n--) block.call(context || null, entries[n]);
- return this;
- },
-
- select: function(block, context) {
- if (!block) return this.enumFor('select');
- block = JS.Enumerable.toFn(block);
-
- var map = [];
- this.forEach(function(item) {
- if (block.apply(context || null, arguments)) map.push(item);
- });
- return map;
- },
-
- sort: function(block, context) {
- var comparable = JS.Enumerable.isComparable(this),
- entries = this.toArray();
-
- block = block || (comparable
- ? function(a,b) { return a.compareTo(b); }
- : null);
- return block
- ? entries.sort(function(a,b) { return block.call(context || null, a, b); })
- : entries.sort();
- },
-
- sortBy: function(block, context) {
- if (!block) return this.enumFor('sortBy');
- block = JS.Enumerable.toFn(block);
-
- var util = JS.Enumerable,
- map = new util.Collection(this.map(block, context)),
- comparable = util.isComparable(map);
-
- return new util.Collection(map.zip(this).sort(function(a, b) {
- a = a[0]; b = b[0];
- return comparable ? a.compareTo(b) : (a < b ? -1 : (a > b ? 1 : 0));
- })).map(function(item) { return item[1]; });
- },
-
- take: function(n) {
- var entries = [];
- this.forEachWithIndex(function(item, i) {
- if (i < n) entries.push(item);
- });
- return entries;
- },
-
- takeWhile: function(block, context) {
- if (!block) return this.enumFor('takeWhile');
- block = JS.Enumerable.toFn(block);
-
- var entries = [],
- take = true;
- this.forEach(function(item) {
- if (take) take = take && block.apply(context || null, arguments);
- if (take) entries.push(item);
- });
- return entries;
- },
-
- toArray: function() {
- return this.drop(0);
- },
-
- zip: function() {
- var util = JS.Enumerable,
- args = [],
- counter = 0,
- n = arguments.length,
- block, context;
-
- if (JS.isFn(arguments[n-1])) {
- block = arguments[n-1]; context = {};
- }
- if (JS.isFn(arguments[n-2])) {
- block = arguments[n-2]; context = arguments[n-1];
- }
- util.forEach.call(arguments, function(arg) {
- if (arg === block || arg === context) return;
- if (arg.toArray) arg = arg.toArray();
- if (JS.isType(arg, Array)) args.push(arg);
- });
- var results = this.map(function(item) {
- var zip = [item];
- util.forEach.call(args, function(arg) {
- zip.push(arg[counter] === undefined ? null : arg[counter]);
- });
- return ++counter && zip;
- });
- if (!block) return results;
- util.forEach.call(results, block, context);
- }
- });
-
- // http://developer.mozilla.org/en/docs/index.php?title=Core_JavaScript_1.5_Reference:Global_Objects:Array&oldid=58326
- JS.Enumerable.include({
- forEach: JS.Enumerable.forEach,
- collect: JS.Enumerable.instanceMethod('map'),
- detect: JS.Enumerable.instanceMethod('find'),
- entries: JS.Enumerable.instanceMethod('toArray'),
- every: JS.Enumerable.instanceMethod('all'),
- findAll: JS.Enumerable.instanceMethod('select'),
- filter: JS.Enumerable.instanceMethod('select'),
- some: JS.Enumerable.instanceMethod('any'),
-
- extend: {
- toFn: function(object) {
- if (!object) return object;
- if (object.toFunction) return object.toFunction();
- if (this.OPS[object]) return this.OPS[object];
- if (JS.isType(object, 'string') || JS.isType(object, String))
- return function() {
- var args = JS.array(arguments),
- target = args.shift(),
- method = target[object];
- return JS.isFn(method) ? method.apply(target, args) : method;
- };
- return object;
- },
-
- OPS: {
- '+': function(a,b) { return a + b },
- '-': function(a,b) { return a - b },
- '*': function(a,b) { return a * b },
- '/': function(a,b) { return a / b },
- '%': function(a,b) { return a % b },
- '^': function(a,b) { return a ^ b },
- '&': function(a,b) { return a & b },
- '&&': function(a,b) { return a && b },
- '|': function(a,b) { return a | b },
- '||': function(a,b) { return a || b },
- '==': function(a,b) { return a == b },
- '!=': function(a,b) { return a != b },
- '>': function(a,b) { return a > b },
- '>=': function(a,b) { return a >= b },
- '<': function(a,b) { return a < b },
- '<=': function(a,b) { return a <= b },
- '===': function(a,b) { return a === b },
- '!==': function(a,b) { return a !== b },
- '[]': function(a,b) { return a[b] },
- '()': function(a,b) { return a(b) }
- },
-
- Enumerator: new JS.Class({
- include: JS.Enumerable,
-
- extend: {
- DEFAULT_METHOD: 'forEach'
- },
-
- initialize: function(object, method, args) {
- this._object = object;
- this._method = method || this.klass.DEFAULT_METHOD;
- this._args = (args || []).slice();
- },
-
- forEach: function(block, context) {
- if (!block) return this;
- var args = this._args.slice();
- args.push(block);
- if (context) args.push(context);
- return this._object[this._method].apply(this._object, args);
- },
-
- cons: JS.Enumerable.instanceMethod('forEachCons'),
- reverse: JS.Enumerable.instanceMethod('reverseForEach'),
- slice: JS.Enumerable.instanceMethod('forEachSlice'),
- withIndex: JS.Enumerable.instanceMethod('forEachWithIndex'),
- withObject: JS.Enumerable.instanceMethod('forEachWithObject')
- })
- }
- }, false);
- JS.Enumerable.Collection.include(JS.Enumerable, true);
- JS.Kernel.include({
- enumFor: function(method) {
- var args = JS.array(arguments),
- method = args.shift();
- return new JS.Enumerable.Enumerator(this, method, args);
- }
- }, false);
- JS.Kernel.define('toEnum', JS.Kernel.instanceMethod('enumFor'), true);
- JS.LinkedList = new JS.Class('LinkedList', {
- include: JS.Enumerable || {},
-
- initialize: function(array, useNodes) {
- this.length = 0;
- this.first = this.last = null;
- if (!array) return;
- for (var i = 0, n = array.length; i < n; i++)
- this.push( useNodes ? new this.klass.Node(array[i]) : array[i] );
- },
-
- forEach: function(block, context) {
- if (!block) return this.enumFor('forEach');
- block = JS.Enumerable.toFn(block);
-
- var node = this.first,
- next, i, n;
-
- for (i = 0, n = this.length; i < n; i++) {
- next = node.next;
- block.call(context || null, node, i);
- if (node === this.last) break;
- node = next;
- }
- return this;
- },
-
- at: function(n) {
- if (n < 0 || n >= this.length) return undefined;
- var node = this.first;
- while (n--) node = node.next;
- return node;
- },
-
- pop: function() {
- return this.length ? this.remove(this.last) : undefined;
- },
-
- shift: function() {
- return this.length ? this.remove(this.first) : undefined;
- },
-
- // stubs - should be implemented by concrete list types
- insertAfter: function() {},
- push: function() {},
- remove: function() {},
-
- extend: {
- Node: new JS.Class({
- initialize: function(data) {
- this.data = data;
- this.prev = this.next = this.list = null;
- }
- })
- }
- });
- JS.LinkedList.Doubly = new JS.Class('LinkedList.Doubly', JS.LinkedList, {
- insertAt: function(n, newNode) {
- if (n < 0 || n >= this.length) return;
- this.insertBefore(this.at(n), newNode);
- },
-
- unshift: function(newNode) {
- this.length > 0
- ? this.insertBefore(this.first, newNode)
- : this.push(newNode);
- },
-
- insertBefore: function() {}
- });
- JS.LinkedList.insertTemplate = function(prev, next, pos) {
- return function(node, newNode) {
- if (node.list !== this) return;
- newNode[prev] = node;
- newNode[next] = node[next];
- node[next] = (node[next][prev] = newNode);
- if (newNode[prev] === this[pos]) this[pos] = newNode;
- newNode.list = this;
- this.length++;
- };
- };
- JS.LinkedList.Doubly.Circular = new JS.Class('LinkedList.Doubly.Circular', JS.LinkedList.Doubly, {
- insertAfter: JS.LinkedList.insertTemplate('prev', 'next', 'last'),
- insertBefore: JS.LinkedList.insertTemplate('next', 'prev', 'first'),
-
- push: function(newNode) {
- if (this.length)
- return this.insertAfter(this.last, newNode);
-
- this.first = this.last =
- newNode.prev = newNode.next = newNode;
-
- newNode.list = this;
- this.length = 1;
- },
-
- remove: function(removed) {
- if (removed.list !== this || this.length === 0) return null;
- if (this.length > 1) {
- removed.prev.next = removed.next;
- removed.next.prev = removed.prev;
- if (removed === this.first) this.first = removed.next;
- if (removed === this.last) this.last = removed.prev;
- } else {
- this.first = this.last = null;
- }
- removed.prev = removed.next = removed.list = null;
- this.length--;
- return removed;
- }
- });
- JS.Hash = new JS.Class('Hash', {
- include: JS.Enumerable || {},
-
- extend: {
- Pair: new JS.Class({
- include: JS.Comparable || {},
-
- setKey: function(key) {
- this[0] = this.key = key;
- },
-
- hasKey: function(key) {
- var my = this.key;
- return my.equals ? my.equals(key) : my === key;
- },
-
- setValue: function(value) {
- this[1] = this.value = value;
- },
-
- hasValue: function(value) {
- var my = this.value;
- return my.equals ? my.equals(value) : my === value;
- },
-
- compareTo: function(other) {
- return this.key.compareTo
- ? this.key.compareTo(other.key)
- : (this.key < other.key ? -1 : (this.key > other.key ? 1 : 0));
- },
-
- hash: function() {
- var key = JS.Hash.codeFor(this.key),
- value = JS.Hash.codeFor(this.value);
-
- return [key, value].sort().join('');
- }
- }),
-
- codeFor: function(object) {
- if (typeof object !== 'object') return String(object);
- return JS.isFn(object.hash)
- ? object.hash()
- : object.toString();
- }
- },
-
- initialize: function(object) {
- this.clear();
- if (!JS.isType(object, Array)) return this.setDefault(object);
- for (var i = 0, n = object.length; i < n; i += 2)
- this.store(object[i], object[i+1]);
- },
-
- forEach: function(block, context) {
- if (!block) return this.enumFor('forEach');
- block = JS.Enumerable.toFn(block);
-
- var hash, bucket, i;
-
- for (hash in this._buckets) {
- if (!this._buckets.hasOwnProperty(hash)) continue;
- bucket = this._buckets[hash];
- i = bucket.length;
- while (i--) block.call(context || null, bucket[i]);
- }
- return this;
- },
-
- _bucketForKey: function(key, createIfAbsent) {
- var hash = this.klass.codeFor(key),
- bucket = this._buckets[hash];
-
- if (!bucket && createIfAbsent)
- bucket = this._buckets[hash] = [];
-
- return bucket;
- },
-
- _indexInBucket: function(bucket, key) {
- var i = bucket.length,
- ident = !!this._compareByIdentity;
-
- while (i--) {
- if (ident ? (bucket[i].key === key) : bucket[i].hasKey(key))
- return i;
- }
- return -1;
- },
-
- assoc: function(key, createIfAbsent) {
- var bucket, index, pair;
-
- bucket = this._bucketForKey(key, createIfAbsent);
- if (!bucket) return null;
-
- index = this._indexInBucket(bucket, key);
- if (index > -1) return bucket[index];
- if (!createIfAbsent) return null;
-
- this.size += 1; this.length += 1;
- pair = new this.klass.Pair;
- pair.setKey(key);
- bucket.push(pair);
- return pair;
- },
-
- rassoc: function(value) {
- var key = this.key(value);
- return key ? this.assoc(key) : null;
- },
-
- clear: function() {
- this._buckets = {};
- this.length = this.size = 0;
- },
-
- compareByIdentity: function() {
- this._compareByIdentity = true;
- },
-
- comparesByIdentity: function() {
- return !!this._compareByIdentity;
- },
-
- setDefault: function(value) {
- this._default = value;
- return this;
- },
-
- getDefault: function(key) {
- return JS.isFn(this._default)
- ? this._default(this, key)
- : (this._default || null);
- },
-
- equals: function(other) {
- if (!JS.isType(other, JS.Hash) || this.length !== other.length)
- return false;
- var result = true;
- this.forEach(function(pair) {
- if (!result) return;
- var otherPair = other.assoc(pair.key);
- if (otherPair === null || !otherPair.hasValue(pair.value)) result = false;
- });
- return result;
- },
-
- hash: function() {
- var hashes = [];
- this.forEach(function(pair) { hashes.push(pair.hash()) });
- return hashes.sort().join('');
- },
-
- fetch: function(key, defaultValue) {
- var pair = this.assoc(key);
- if (pair) return pair.value;
-
- if (defaultValue === undefined) throw new Error('key not found');
- if (JS.isFn(defaultValue)) return defaultValue(key);
- return defaultValue;
- },
-
- forEachKey: function(block, context) {
- if (!block) return this.enumFor('forEachKey');
- block = JS.Enumerable.toFn(block);
-
- this.forEach(function(pair) {
- block.call(context || null, pair.key);
- });
- return this;
- },
-
- forEachPair: function(block, context) {
- if (!block) return this.enumFor('forEachPair');
- block = JS.Enumerable.toFn(block);
-
- this.forEach(function(pair) {
- block.call(context || null, pair.key, pair.value);
- });
- return this;
- },
-
- forEachValue: function(block, context) {
- if (!block) return this.enumFor('forEachValue');
- block = JS.Enumerable.toFn(block);
-
- this.forEach(function(pair) {
- block.call(context || null, pair.value);
- });
- return this;
- },
-
- get: function(key) {
- var pair = this.assoc(key);
- return pair ? pair.value : this.getDefault(key);
- },
-
- hasKey: function(key) {
- return !!this.assoc(key);
- },
-
- hasValue: function(value) {
- var has = false, ident = !!this._compareByIdentity;
- this.forEach(function(pair) {
- if ((value.equals && !ident) ? value.equals(pair.value) : value === pair.value)
- has = true;
- });
- return has;
- },
-
- invert: function() {
- var hash = new this.klass;
- this.forEach(function(pair) {
- hash.store(pair.value, pair.key);
- });
- return hash;
- },
-
- isEmpty: function() {
- for (var hash in this._buckets) {
- if (this._buckets.hasOwnProperty(hash) && this._buckets[hash].length > 0)
- return false;
- }
- return true;
- },
-
- key: function(value) {
- var result = null;
- this.forEach(function(pair) {
- if (value.equals ? value.equals(pair.value) : (value === pair.value))
- result = pair.key;
- });
- return result;
- },
-
- keys: function() {
- var keys = [];
- this.forEach(function(pair) { keys.push(pair.key) });
- return keys;
- },
-
- merge: function(hash, block, context) {
- var newHash = new this.klass;
- newHash.update(this);
- newHash.update(hash, block, context);
- return newHash;
- },
-
- rehash: function() {
- var temp = new this.klass;
- temp._buckets = this._buckets;
- this.clear();
- this.update(temp);
- },
-
- remove: function(key, block) {
- if (block === undefined) block = null;
- var bucket, index, result;
-
- bucket = this._bucketForKey(key);
- if (!bucket) return JS.isFn(block) ? this.fetch(key, block) : this.getDefault(key);
-
- index = this._indexInBucket(bucket, key);
- if (index < 0) return JS.isFn(block) ? this.fetch(key, block) : this.getDefault(key);
-
- result = bucket[index].value;
- bucket.splice(index, 1);
- this.size -= 1;
- this.length -= 1;
-
- if (bucket.length === 0)
- delete this._buckets[this.klass.codeFor(key)];
-
- return result;
- },
-
- removeIf: function(block, context) {
- if (!block) return this.enumFor('removeIf');
- block = JS.Enumerable.toFn(block);
-
- this.forEach(function(pair) {
- if (block.call(context || null, pair))
- this.remove(pair.key);
- }, this);
- return this;
- },
-
- replace: function(hash) {
- this.clear();
- this.update(hash);
- },
-
- shift: function() {
- var keys = this.keys();
- if (keys.length === 0) return this.getDefault();
- var pair = this.assoc(keys[0]);
- this.remove(pair.key);
- return pair;
- },
-
- store: function(key, value) {
- this.assoc(key, true).setValue(value);
- return value;
- },
-
- update: function(hash, block, context) {
- var blockGiven = JS.isFn(block);
- hash.forEach(function(pair) {
- var key = pair.key, value = pair.value;
- if (blockGiven && this.hasKey(key))
- value = block.call(context || null, key, this.get(key), value);
- this.store(key, value);
- }, this);
- },
-
- values: function() {
- var values = [];
- this.forEach(function(pair) { values.push(pair.value) });
- return values;
- },
-
- valuesAt: function() {
- var i = arguments.length, results = [];
- while (i--) results.push(this.get(arguments[i]));
- return results;
- }
- });
- JS.Hash.include({
- includes: JS.Hash.instanceMethod('hasKey'),
- index: JS.Hash.instanceMethod('key'),
- put: JS.Hash.instanceMethod('store')
- }, true);
- JS.Set = new JS.Class('Set', {
- extend: {
- forEach: function(list, block, context) {
- if (!list || !block) return;
- if (list.forEach) return list.forEach(block, context);
- for (var i = 0, n = list.length; i < n; i++) {
- if (list[i] !== undefined)
- block.call(context || null, list[i], i);
- }
- }
- },
-
- include: JS.Enumerable || {},
-
- initialize: function(list, block, context) {
- this.clear();
- if (block) this.klass.forEach(list, function(item) {
- this.add(block.call(context || null, item));
- }, this);
- else this.merge(list);
- },
-
- forEach: function(block, context) {
- if (!block) return this.enumFor('forEach');
- block = JS.Enumerable.toFn(block);
-
- this.klass.forEach(this._members, block, context);
- return this;
- },
-
- add: function(item) {
- if (this.contains(item)) return false;
- this._members.push(item);
- this.length = this.size = this._members.length;
- return true;
- },
-
- classify: function(block, context) {
- if (!block) return this.enumFor('classify');
- block = JS.Enumerable.toFn(block);
-
- var classes = new JS.Hash();
- this.forEach(function(item) {
- var value = block.call(context || null, item);
- if (!classes.hasKey(value)) classes.store(value, new this.klass);
- classes.get(value).add(item);
- }, this);
- return classes;
- },
-
- clear: function() {
- this._members = [];
- this.length = this.size = 0;
- },
-
- complement: function(other) {
- var set = new this.klass;
- this.klass.forEach(other, function(item) {
- if (!this.contains(item)) set.add(item);
- }, this);
- return set;
- },
-
- contains: function(item) {
- return this._indexOf(item) !== -1;
- },
-
- difference: function(other) {
- other = JS.isType(other, JS.Set) ? other : new JS.Set(other);
- var set = new this.klass;
- this.forEach(function(item) {
- if (!other.contains(item)) set.add(item);
- });
- return set;
- },
-
- divide: function(block, context) {
- if (!block) return this.enumFor('divide');
- block = JS.Enumerable.toFn(block);
-
- var classes = this.classify(block, context),
- sets = new this.klass;
-
- classes.forEachValue(sets.method('add'));
- return sets;
- },
-
- equals: function(other) {
- if (this.length !== other.length || !JS.isType(other, JS.Set)) return false;
- var result = true;
- this.forEach(function(item) {
- if (!result) return;
- if (!other.contains(item)) result = false;
- });
- return result;
- },
-
- hash: function() {
- var hashes = [];
- this.forEach(function(object) { hashes.push(JS.Hash.codeFor(object)) });
- return hashes.sort().join('');
- },
-
- flatten: function(set) {
- var copy = new this.klass;
- copy._members = this._members;
- if (!set) { set = this; set.clear(); }
- copy.forEach(function(item) {
- if (JS.isType(item, JS.Set)) item.flatten(set);
- else set.add(item);
- });
- return set;
- },
-
- intersection: function(other) {
- var set = new this.klass;
- this.klass.forEach(other, function(item) {
- if (this.contains(item)) set.add(item);
- }, this);
- return set;
- },
-
- isEmpty: function() {
- return this._members.length === 0;
- },
-
- isProperSubset: function(other) {
- return this._members.length < other._members.length && this.isSubset(other);
- },
-
- isProperSuperset: function(other) {
- return this._members.length > other._members.length && this.isSuperset(other);
- },
-
- isSubset: function(other) {
- var result = true;
- this.forEach(function(item) {
- if (!result) return;
- if (!other.contains(item)) result = false;
- });
- return result;
- },
-
- isSuperset: function(other) {
- return other.isSubset(this);
- },
-
- merge: function(list) {
- this.klass.forEach(list, function(item) { this.add(item) }, this);
- },
-
- product: function(other) {
- var pairs = new JS.Set;
- this.forEach(function(item) {
- this.klass.forEach(other, function(partner) {
- pairs.add([item, partner]);
- });
- }, this);
- return pairs;
- },
-
- rebuild: function() {
- var members = this._members;
- this.clear();
- this.merge(members);
- },
-
- remove: function(item) {
- var index = this._indexOf(item);
- if (index === -1) return;
- this._members.splice(index, 1);
- this.length = this.size = this._members.length;
- },
-
- removeIf: function(block, context) {
- if (!block) return this.enumFor('removeIf');
- block = JS.Enumerable.toFn(block);
-
- var members = this._members,
- i = members.length;
-
- while (i--) {
- if (block.call(context || null, members[i]))
- this.remove(members[i]);
- }
- return this;
- },
-
- replace: function(other) {
- this.clear();
- this.merge(other);
- },
-
- subtract: function(list) {
- this.klass.forEach(list, function(item) {
- this.remove(item);
- }, this);
- },
-
- union: function(other) {
- var set = new this.klass;
- set.merge(this);
- set.merge(other);
- return set;
- },
-
- xor: function(other) {
- var set = new JS.Set(other);
- this.forEach(function(item) {
- set[set.contains(item) ? 'remove' : 'add'](item);
- });
- return set;
- },
-
- _indexOf: function(item) {
- var i = this._members.length,
- equal = JS.Enumerable.areEqual;
-
- while (i--) {
- if (equal(item, this._members[i])) return i;
- }
- return -1;
- }
- });
- JS.Set.include({
- n: JS.Set.instanceMethod('intersection'),
- u: JS.Set.instanceMethod('union'),
- x: JS.Set.instanceMethod('product')
- }, false);
- JS.SortedSet = new JS.Class('SortedSet', JS.Set, {
- extend: {
- compare: function(one, another) {
- return JS.isType(one, Object)
- ? one.compareTo(another)
- : (one < another ? -1 : (one > another ? 1 : 0));
- }
- },
-
- add: function(item) {
- var point = this._indexOf(item, true);
- if (point === null) return;
- this._members.splice(point, 0, item);
- this.length = this.size = this._members.length;
- },
-
- _indexOf: function(item, insertionPoint) {
- var items = this._members,
- n = items.length,
- i = 0,
- d = n,
- compare = this.klass.compare,
- equal = JS.Enumerable.areEqual,
- found;
-
- if (n === 0) return insertionPoint ? 0 : -1;
-
- if (compare(item, items[0]) < 1) { d = 0; i = 0; }
- if (compare(item, items[n-1]) > 0) { d = 0; i = n; }
-
- while (!equal(item, items[i]) && d > 0.5) {
- d = d / 2;
- i += (compare(item, items[i]) > 0 ? 1 : -1) * Math.round(d);
- if (i > 0 && compare(item, items[i-1]) > 0 && compare(item, items[i]) < 1) d = 0;
- }
-
- // The pointer will end up at the start of any homogenous section. Step
- // through the section until we find the needle or until the section ends.
- while (items[i] && !equal(item, items[i]) &&
- compare(item, items[i]) === 0) i += 1;
-
- found = equal(item, items[i]);
- return insertionPoint
- ? (found ? null : i)
- : (found ? i : -1);
- }
- });
- JS.HashSet = new JS.Class('HashSet', JS.Set, {
- forEach: function(block, context) {
- if (!block) return this.enumFor('forEach');
- block = JS.Enumerable.toFn(block);
-
- this._members.forEachKey(block, context);
- return this;
- },
-
- add: function(item) {
- if (this.contains(item)) return false;
- this._members.store(item, true);
- this.length = this.size = this._members.length;
- return true;
- },
-
- clear: function() {
- this._members = new JS.Hash();
- this.size = this.length = 0;
- },
-
- contains: function(item) {
- return this._members.hasKey(item);
- },
-
- rebuild: function() {
- this._members.rehash();
- this.length = this.size = this._members.length;
- },
-
- remove: function(item) {
- this._members.remove(item);
- this.length = this.size = this._members.length;
- },
-
- removeIf: function(block, context) {
- if (!block) return this.enumFor('removeIf');
- block = JS.Enumerable.toFn(block);
-
- this._members.removeIf(fu…
Large files files are truncated, but you can click here to view the full file