1676 lines
49 KiB
JavaScript
1676 lines
49 KiB
JavaScript
/*
|
|
base2 - copyright 2007-2011, Dean Edwards
|
|
http://code.google.com/p/base2/
|
|
http://www.opensource.org/licenses/mit-license.php
|
|
|
|
Contributors:
|
|
Doeke Zanstra
|
|
*/
|
|
|
|
var base2 = {
|
|
name: "base2",
|
|
version: "1.0.2",
|
|
exports:
|
|
"Base,Package,Abstract,Module,Enumerable,Map,Collection,RegGrp," +
|
|
"Undefined,Null,This,True,False,assignID,detect,global",
|
|
namespace: ""
|
|
};
|
|
|
|
new function(_no_shrink_) { /////////////// BEGIN: CLOSURE ///////////////
|
|
|
|
// =========================================================================
|
|
// base2/header.js
|
|
// =========================================================================
|
|
|
|
var Undefined = K(), Null = K(null), True = K(true), False = K(false), This = function(){return this};
|
|
|
|
var global = This();
|
|
var base2 = global.base2;
|
|
|
|
// private
|
|
var _FORMAT = /%([1-9])/g;
|
|
var _LTRIM = /^\s\s*/;
|
|
var _RTRIM = /\s\s*$/;
|
|
var _RESCAPE = /([\/()[\]{}|*+-.,^$?\\])/g; // safe regular expressions
|
|
var _BASE = /try/.test(detect) ? /\bbase\b/ : /.*/; // some platforms don't allow decompilation
|
|
var _HIDDEN = ["constructor", "toString", "valueOf"]; // only override these when prototyping
|
|
var _MSIE_NATIVE_FUNCTION = detect("(jscript)") ?
|
|
new RegExp("^" + rescape(isNaN).replace(/isNaN/, "\\w+") + "$") : {test: False};
|
|
|
|
var _counter = 1;
|
|
var _slice = Array.prototype.slice;
|
|
|
|
_Function_forEach(); // make sure this is initialised
|
|
|
|
function assignID(object) {
|
|
// Assign a unique ID to an object.
|
|
if (!object.base2ID) object.base2ID = "b2_" + _counter++;
|
|
return object.base2ID;
|
|
};
|
|
|
|
// =========================================================================
|
|
// base2/Base.js
|
|
// =========================================================================
|
|
|
|
// http://dean.edwards.name/weblog/2006/03/base/
|
|
|
|
var _subclass = function(_instance, _static) {
|
|
// Build the prototype.
|
|
base2.__prototyping = this.prototype;
|
|
var _prototype = new this;
|
|
if (_instance) extend(_prototype, _instance);
|
|
delete base2.__prototyping;
|
|
|
|
// Create the wrapper for the constructor function.
|
|
var _constructor = _prototype.constructor;
|
|
function _class() {
|
|
// Don't call the constructor function when prototyping.
|
|
if (!base2.__prototyping) {
|
|
if (this.constructor == arguments.callee || this.__constructing) {
|
|
// Instantiation.
|
|
this.__constructing = true;
|
|
_constructor.apply(this, arguments);
|
|
delete this.__constructing;
|
|
} else {
|
|
// Casting.
|
|
return extend(arguments[0], _prototype);
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
_prototype.constructor = _class;
|
|
|
|
// Build the static interface.
|
|
for (var i in Base) _class[i] = this[i];
|
|
_class.ancestor = this;
|
|
_class.base = Undefined;
|
|
//_class.init = Undefined;
|
|
if (_static) extend(_class, _static);
|
|
_class.prototype = _prototype;
|
|
if (_class.init) _class.init();
|
|
|
|
// introspection (removed when packed)
|
|
;;; _class["#implements"] = [];
|
|
;;; _class["#implemented_by"] = [];
|
|
|
|
return _class;
|
|
};
|
|
|
|
var Base = _subclass.call(Object, {
|
|
constructor: function() {
|
|
if (arguments.length > 0) {
|
|
this.extend(arguments[0]);
|
|
}
|
|
},
|
|
|
|
base: function() {
|
|
// Call this method from any other method to invoke the current method's ancestor (super).
|
|
},
|
|
|
|
extend: delegate(extend)
|
|
}, Base = {
|
|
ancestorOf: function(klass) {
|
|
return _ancestorOf(this, klass);
|
|
},
|
|
|
|
extend: _subclass,
|
|
|
|
forEach: function(object, block, context) {
|
|
_Function_forEach(this, object, block, context);
|
|
},
|
|
|
|
implement: function(source) {
|
|
if (typeof source == "function") {
|
|
;;; if (_ancestorOf(Base, source)) {
|
|
// introspection (removed when packed)
|
|
;;; this["#implements"].push(source);
|
|
;;; source["#implemented_by"].push(this);
|
|
;;; }
|
|
source = source.prototype;
|
|
}
|
|
// Add the interface using the extend() function.
|
|
extend(this.prototype, source);
|
|
return this;
|
|
}
|
|
});
|
|
|
|
// =========================================================================
|
|
// base2/Package.js
|
|
// =========================================================================
|
|
|
|
var Package = Base.extend({
|
|
constructor: function(_private, _public) {
|
|
this.extend(_public);
|
|
if (this.init) this.init();
|
|
|
|
if (this.name && this.name != "base2") {
|
|
if (!this.parent) this.parent = base2;
|
|
this.parent.addName(this.name, this);
|
|
this.namespace = format("var %1=%2;", this.name, String2.slice(this, 1, -1));
|
|
}
|
|
|
|
if (_private) {
|
|
// This next line gets round a bug in old Mozilla browsers
|
|
var JSNamespace = base2.JavaScript ? base2.JavaScript.namespace : "";
|
|
// This string should be evaluated immediately after creating a Package object.
|
|
_private.imports = Array2.reduce(csv(this.imports), function(namespace, name) {
|
|
var ns = lookup(name) || lookup("JavaScript." + name);
|
|
;;; assert(ns, format("Object not found: '%1'.", name), ReferenceError);
|
|
return namespace += ns.namespace;
|
|
}, "var base2=(function(){return this.base2})();" + base2.namespace + JSNamespace) + lang.namespace;
|
|
|
|
// This string should be evaluated after you have created all of the objects
|
|
// that are being exported.
|
|
_private.exports = Array2.reduce(csv(this.exports), function(namespace, name) {
|
|
var fullName = this.name + "." + name;
|
|
this.namespace += "var " + name + "=" + fullName + ";";
|
|
return namespace += "if(!" + fullName + ")" + fullName + "=" + name + ";";
|
|
}, "", this) + "this._label_" + this.name + "();";
|
|
|
|
var pkg = this;
|
|
var packageName = String2.slice(this, 1, -1);
|
|
_private["_label_" + this.name] = function() {
|
|
Package.forEach (pkg, function(object, name) {
|
|
if (object && object.ancestorOf == Base.ancestorOf) {
|
|
object.toString = K(format("[%1.%2]", packageName, name));
|
|
if (object.prototype.toString == Base.prototype.toString) {
|
|
object.prototype.toString = K(format("[object %1.%2]", packageName, name));
|
|
}
|
|
}
|
|
});
|
|
};
|
|
}
|
|
|
|
function lookup(names) {
|
|
names = names.split(".");
|
|
var value = base2, i = 0;
|
|
while (value && names[i] != null) {
|
|
value = value[names[i++]];
|
|
}
|
|
return value;
|
|
};
|
|
},
|
|
|
|
exports: "",
|
|
imports: "",
|
|
name: "",
|
|
namespace: "",
|
|
parent: null,
|
|
|
|
addName: function(name, value) {
|
|
if (!this[name]) {
|
|
this[name] = value;
|
|
this.exports += "," + name;
|
|
this.namespace += format("var %1=%2.%1;", name, this.name);
|
|
}
|
|
},
|
|
|
|
addPackage: function(name) {
|
|
this.addName(name, new Package(null, {name: name, parent: this}));
|
|
},
|
|
|
|
toString: function() {
|
|
return format("[%1]", this.parent ? String2.slice(this.parent, 1, -1) + "." + this.name : this.name);
|
|
}
|
|
});
|
|
|
|
// =========================================================================
|
|
// base2/Abstract.js
|
|
// =========================================================================
|
|
|
|
var Abstract = Base.extend({
|
|
constructor: function() {
|
|
throw new TypeError("Abstract class cannot be instantiated.");
|
|
}
|
|
});
|
|
|
|
// =========================================================================
|
|
// base2/Module.js
|
|
// =========================================================================
|
|
|
|
var _moduleCount = 0;
|
|
|
|
var Module = Abstract.extend(null, {
|
|
namespace: "",
|
|
|
|
extend: function(_interface, _static) {
|
|
// Extend a module to create a new module.
|
|
var module = this.base();
|
|
var index = _moduleCount++;
|
|
module.namespace = "";
|
|
module.partial = this.partial;
|
|
module.toString = K("[base2.Module[" + index + "]]");
|
|
Module[index] = module;
|
|
// Inherit class methods.
|
|
module.implement(this);
|
|
// Implement module (instance AND static) methods.
|
|
if (_interface) module.implement(_interface);
|
|
// Implement static properties and methods.
|
|
if (_static) {
|
|
extend(module, _static);
|
|
if (module.init) module.init();
|
|
}
|
|
return module;
|
|
},
|
|
|
|
forEach: function(block, context) {
|
|
_Function_forEach (Module, this.prototype, function(method, name) {
|
|
if (typeOf(method) == "function") {
|
|
block.call(context, this[name], name, this);
|
|
}
|
|
}, this);
|
|
},
|
|
|
|
implement: function(_interface) {
|
|
var module = this;
|
|
var id = module.toString().slice(1, -1);
|
|
if (typeof _interface == "function") {
|
|
if (!_ancestorOf(_interface, module)) {
|
|
this.base(_interface);
|
|
}
|
|
if (_ancestorOf(Module, _interface)) {
|
|
// Implement static methods.
|
|
for (var name in _interface) {
|
|
if (module[name] === undefined) {
|
|
var property = _interface[name];
|
|
if (typeof property == "function" && property.call && _interface.prototype[name]) {
|
|
property = _staticModuleMethod(_interface, name);
|
|
}
|
|
module[name] = property;
|
|
}
|
|
}
|
|
module.namespace += _interface.namespace.replace(/base2\.Module\[\d+\]/g, id);
|
|
}
|
|
} else {
|
|
// Add static interface.
|
|
extend(module, _interface);
|
|
// Add instance interface.
|
|
_extendModule(module, _interface);
|
|
}
|
|
return module;
|
|
},
|
|
|
|
partial: function() {
|
|
var module = Module.extend();
|
|
var id = module.toString().slice(1, -1);
|
|
// partial methods are already bound so remove the binding to speed things up
|
|
module.namespace = this.namespace.replace(/(\w+)=b[^\)]+\)/g, "$1=" + id + ".$1");
|
|
this.forEach(function(method, name) {
|
|
module[name] = partial(bind(method, module));
|
|
});
|
|
return module;
|
|
}
|
|
});
|
|
|
|
function _extendModule(module, _interface) {
|
|
var proto = module.prototype;
|
|
var id = module.toString().slice(1, -1);
|
|
for (var name in _interface) {
|
|
var property = _interface[name], namespace = "";
|
|
if (name.charAt(0) == "@") { // object detection
|
|
if (detect(name.slice(1))) _extendModule(module, property);
|
|
} else if (!proto[name]) {
|
|
if (name == name.toUpperCase()) {
|
|
namespace = "var " + name + "=" + id + "." + name + ";";
|
|
} else if (typeof property == "function" && property.call) {
|
|
namespace = "var " + name + "=base2.lang.bind('" + name + "'," + id + ");";
|
|
proto[name] = _moduleMethod(module, name);
|
|
;;; proto[name]._module = module; // introspection
|
|
}
|
|
if (module.namespace.indexOf(namespace) == -1) {
|
|
module.namespace += namespace;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
function _staticModuleMethod(module, name) {
|
|
return function() {
|
|
return module[name].apply(module, arguments);
|
|
};
|
|
};
|
|
|
|
function _moduleMethod(module, name) {
|
|
return function() {
|
|
var args = _slice.call(arguments);
|
|
args.unshift(this);
|
|
return module[name].apply(module, args);
|
|
};
|
|
};
|
|
|
|
// =========================================================================
|
|
// base2/Enumerable.js
|
|
// =========================================================================
|
|
|
|
var Enumerable = Module.extend({
|
|
every: function(object, test, context) {
|
|
var result = true;
|
|
try {
|
|
forEach (object, function(value, key) {
|
|
result = test.call(context, value, key, object);
|
|
if (!result) throw StopIteration;
|
|
});
|
|
} catch (error) {
|
|
if (error != StopIteration) throw error;
|
|
}
|
|
return !!result; // cast to boolean
|
|
},
|
|
|
|
filter: function(object, test, context) {
|
|
var i = 0;
|
|
return this.reduce(object, function(result, value, key) {
|
|
if (test.call(context, value, key, object)) {
|
|
result[i++] = value;
|
|
}
|
|
return result;
|
|
}, []);
|
|
},
|
|
|
|
invoke: function(object, method) {
|
|
// Apply a method to each item in the enumerated object.
|
|
var args = _slice.call(arguments, 2);
|
|
return this.map(object, (typeof method == "function") ? function(item) {
|
|
return item == null ? undefined : method.apply(item, args);
|
|
} : function(item) {
|
|
return item == null ? undefined : item[method].apply(item, args);
|
|
});
|
|
},
|
|
|
|
map: function(object, block, context) {
|
|
var result = [], i = 0;
|
|
forEach (object, function(value, key) {
|
|
result[i++] = block.call(context, value, key, object);
|
|
});
|
|
return result;
|
|
},
|
|
|
|
pluck: function(object, key) {
|
|
return this.map(object, function(item) {
|
|
return item == null ? undefined : item[key];
|
|
});
|
|
},
|
|
|
|
reduce: function(object, block, result, context) {
|
|
var initialised = arguments.length > 2;
|
|
forEach (object, function(value, key) {
|
|
if (initialised) {
|
|
result = block.call(context, result, value, key, object);
|
|
} else {
|
|
result = value;
|
|
initialised = true;
|
|
}
|
|
});
|
|
return result;
|
|
},
|
|
|
|
some: function(object, test, context) {
|
|
return !this.every(object, not(test), context);
|
|
}
|
|
});
|
|
|
|
// =========================================================================
|
|
// base2/Map.js
|
|
// =========================================================================
|
|
|
|
// http://wiki.ecmascript.org/doku.php?id=proposals:dictionary
|
|
|
|
var _HASH = "#";
|
|
|
|
var Map = Base.extend({
|
|
constructor: function(values) {
|
|
if (values) this.merge(values);
|
|
},
|
|
|
|
clear: function() {
|
|
for (var key in this) if (key.indexOf(_HASH) == 0) {
|
|
delete this[key];
|
|
}
|
|
},
|
|
|
|
copy: function() {
|
|
base2.__prototyping = true; // not really prototyping but it stops [[construct]] being called
|
|
var copy = new this.constructor;
|
|
delete base2.__prototyping;
|
|
for (var i in this) if (this[i] !== copy[i]) {
|
|
copy[i] = this[i];
|
|
}
|
|
return copy;
|
|
},
|
|
|
|
forEach: function(block, context) {
|
|
for (var key in this) if (key.indexOf(_HASH) == 0) {
|
|
block.call(context, this[key], key.slice(1), this);
|
|
}
|
|
},
|
|
|
|
get: function(key) {
|
|
return this[_HASH + key];
|
|
},
|
|
|
|
getKeys: function() {
|
|
return this.map(II);
|
|
},
|
|
|
|
getValues: function() {
|
|
return this.map(I);
|
|
},
|
|
|
|
// Ancient browsers throw an error if we use "in" as an operator.
|
|
has: function(key) {
|
|
/*@cc_on @*/
|
|
/*@if (@_jscript_version < 5.5)
|
|
return $Legacy.has(this, _HASH + key);
|
|
@else @*/
|
|
return _HASH + key in this;
|
|
/*@end @*/
|
|
},
|
|
|
|
merge: function(values) {
|
|
var put = flip(this.put);
|
|
forEach (arguments, function(values) {
|
|
forEach (values, put, this);
|
|
}, this);
|
|
return this;
|
|
},
|
|
|
|
put: function(key, value) {
|
|
// create the new entry (or overwrite the old entry).
|
|
this[_HASH + key] = value;
|
|
},
|
|
|
|
remove: function(key) {
|
|
delete this[_HASH + key];
|
|
},
|
|
|
|
size: function() {
|
|
// this is expensive because we are not storing the keys
|
|
var size = 0;
|
|
for (var key in this) if (key.indexOf(_HASH) == 0) size++;
|
|
return size;
|
|
},
|
|
|
|
union: function(values) {
|
|
return this.merge.apply(this.copy(), arguments);
|
|
}
|
|
});
|
|
|
|
Map.implement(Enumerable);
|
|
|
|
Map.prototype.filter = function(test, context) {
|
|
return this.reduce(function(result, value, key) {
|
|
if (!test.call(context, value, key, this)) {
|
|
result.remove(key);
|
|
}
|
|
return result;
|
|
}, this.copy(), this);
|
|
};
|
|
|
|
// =========================================================================
|
|
// base2/Collection.js
|
|
// =========================================================================
|
|
|
|
// A Map that is more array-like (accessible by index).
|
|
|
|
// Collection classes have a special (optional) property: Item
|
|
// The Item property points to a constructor function.
|
|
// Members of the collection must be an instance of Item.
|
|
|
|
// The static create() method is responsible for all construction of collection items.
|
|
// Instance methods that add new items (add, put, insertAt, putAt) pass *all* of their arguments
|
|
// to the static create() method. If you want to modify the way collection items are
|
|
// created then you only need to override this method for custom collections.
|
|
|
|
var _KEYS = "~";
|
|
|
|
var Collection = Map.extend({
|
|
constructor: function(values) {
|
|
this[_KEYS] = new Array2;
|
|
this.base(values);
|
|
},
|
|
|
|
add: function(key, item) {
|
|
// Duplicates not allowed using add().
|
|
// But you can still overwrite entries using put().
|
|
assert(!this.has(key), "Duplicate key '" + key + "'.");
|
|
this.put.apply(this, arguments);
|
|
},
|
|
|
|
clear: function() {
|
|
this.base();
|
|
this[_KEYS].length = 0;
|
|
},
|
|
|
|
copy: function() {
|
|
var copy = this.base();
|
|
copy[_KEYS] = this[_KEYS].copy();
|
|
return copy;
|
|
},
|
|
|
|
forEach: function(block, context) {
|
|
var keys = this[_KEYS];
|
|
var length = keys.length;
|
|
for (var i = 0; i < length; i++) {
|
|
block.call(context, this[_HASH + keys[i]], keys[i], this);
|
|
}
|
|
},
|
|
|
|
getAt: function(index) {
|
|
var key = this[_KEYS].item(index);
|
|
return (key === undefined) ? undefined : this[_HASH + key];
|
|
},
|
|
|
|
getKeys: function() {
|
|
return this[_KEYS].copy();
|
|
},
|
|
|
|
indexOf: function(key) {
|
|
return this[_KEYS].indexOf(String(key));
|
|
},
|
|
|
|
insertAt: function(index, key, item) {
|
|
assert(this[_KEYS].item(index) !== undefined, "Index out of bounds.");
|
|
assert(!this.has(key), "Duplicate key '" + key + "'.");
|
|
this[_KEYS].insertAt(index, String(key));
|
|
this[_HASH + key] = null; // placeholder
|
|
this.put.apply(this, _slice.call(arguments, 1));
|
|
},
|
|
|
|
item: function(keyOrIndex) {
|
|
return this[typeof keyOrIndex == "number" ? "getAt" : "get"](keyOrIndex);
|
|
},
|
|
|
|
put: function(key, item) {
|
|
if (!this.has(key)) {
|
|
this[_KEYS].push(String(key));
|
|
}
|
|
var klass = this.constructor;
|
|
if (klass.Item && !instanceOf(item, klass.Item)) {
|
|
item = klass.create.apply(klass, arguments);
|
|
}
|
|
this[_HASH + key] = item;
|
|
},
|
|
|
|
putAt: function(index, item) {
|
|
arguments[0] = this[_KEYS].item(index);
|
|
assert(arguments[0] !== undefined, "Index out of bounds.");
|
|
this.put.apply(this, arguments);
|
|
},
|
|
|
|
remove: function(key) {
|
|
// The remove() method of the Array object can be slow so check if the key exists first.
|
|
if (this.has(key)) {
|
|
this[_KEYS].remove(String(key));
|
|
delete this[_HASH + key];
|
|
}
|
|
},
|
|
|
|
removeAt: function(index) {
|
|
var key = this[_KEYS].item(index);
|
|
if (key !== undefined) {
|
|
this[_KEYS].removeAt(index);
|
|
delete this[_HASH + key];
|
|
}
|
|
},
|
|
|
|
reverse: function() {
|
|
this[_KEYS].reverse();
|
|
return this;
|
|
},
|
|
|
|
size: function() {
|
|
return this[_KEYS].length;
|
|
},
|
|
|
|
slice: function(start, end) {
|
|
var sliced = this.copy();
|
|
if (arguments.length > 0) {
|
|
var keys = this[_KEYS], removed = keys;
|
|
sliced[_KEYS] = Array2(_slice.apply(keys, arguments));
|
|
if (sliced[_KEYS].length) {
|
|
removed = removed.slice(0, start);
|
|
if (arguments.length > 1) {
|
|
removed = removed.concat(keys.slice(end));
|
|
}
|
|
}
|
|
for (var i = 0; i < removed.length; i++) {
|
|
delete sliced[_HASH + removed[i]];
|
|
}
|
|
}
|
|
return sliced;
|
|
},
|
|
|
|
sort: function(compare) { // optimised (refers to _HASH)
|
|
if (compare) {
|
|
this[_KEYS].sort(bind(function(key1, key2) {
|
|
return compare(this[_HASH + key1], this[_HASH + key2], key1, key2);
|
|
}, this));
|
|
} else this[_KEYS].sort();
|
|
return this;
|
|
},
|
|
|
|
toString: function() {
|
|
return "(" + (this[_KEYS] || "") + ")";
|
|
}
|
|
}, {
|
|
Item: null, // If specified, all members of the collection must be instances of Item.
|
|
|
|
create: function(key, item) {
|
|
return this.Item ? new this.Item(key, item) : item;
|
|
},
|
|
|
|
extend: function(_instance, _static) {
|
|
var klass = this.base(_instance);
|
|
klass.create = this.create;
|
|
if (_static) extend(klass, _static);
|
|
if (!klass.Item) {
|
|
klass.Item = this.Item;
|
|
} else if (typeof klass.Item != "function") {
|
|
klass.Item = (this.Item || Base).extend(klass.Item);
|
|
}
|
|
if (klass.init) klass.init();
|
|
return klass;
|
|
}
|
|
});
|
|
|
|
// =========================================================================
|
|
// base2/RegGrp.js
|
|
// =========================================================================
|
|
|
|
// A collection of regular expressions and their associated replacement values.
|
|
// A Base class for creating parsers.
|
|
|
|
var _RG_BACK_REF = /\\(\d+)/g,
|
|
_RG_ESCAPE_CHARS = /\\./g,
|
|
_RG_ESCAPE_BRACKETS = /\(\?[:=!]|\[[^\]]+\]/g,
|
|
_RG_BRACKETS = /\(/g,
|
|
_RG_LOOKUP = /\$(\d+)/,
|
|
_RG_LOOKUP_SIMPLE = /^\$\d+$/;
|
|
|
|
var RegGrp = Collection.extend({
|
|
constructor: function(values, ignoreCase) {
|
|
this.base(values);
|
|
this.ignoreCase = !!ignoreCase;
|
|
},
|
|
|
|
ignoreCase: false,
|
|
|
|
exec: function(string, override) { // optimised (refers to _HASH/_KEYS)
|
|
string += ""; // type-safe
|
|
var items = this, keys = this[_KEYS];
|
|
if (!keys.length) return string;
|
|
if (override == RegGrp.IGNORE) override = 0;
|
|
return string.replace(new RegExp(this, this.ignoreCase ? "gi" : "g"), function(match) {
|
|
var item, offset = 1, i = 0;
|
|
// Loop through the RegGrp items.
|
|
while ((item = items[_HASH + keys[i++]])) {
|
|
var next = offset + item.length + 1;
|
|
if (arguments[offset]) { // do we have a result?
|
|
var replacement = override == null ? item.replacement : override;
|
|
switch (typeof replacement) {
|
|
case "function":
|
|
return replacement.apply(items, _slice.call(arguments, offset, next));
|
|
case "number":
|
|
return arguments[offset + replacement];
|
|
default:
|
|
return replacement;
|
|
}
|
|
}
|
|
offset = next;
|
|
}
|
|
return match;
|
|
});
|
|
},
|
|
|
|
insertAt: function(index, expression, replacement) {
|
|
if (instanceOf(expression, RegExp)) {
|
|
arguments[1] = expression.source;
|
|
}
|
|
return base(this, arguments);
|
|
},
|
|
|
|
test: function(string) {
|
|
// The slow way to do it. Hopefully, this isn't called too often. :-)
|
|
return this.exec(string) != string;
|
|
},
|
|
|
|
toString: function() {
|
|
var offset = 1;
|
|
return "(" + this.map(function(item) {
|
|
// Fix back references.
|
|
var expression = (item + "").replace(_RG_BACK_REF, function(match, index) {
|
|
return "\\" + (offset + Number(index));
|
|
});
|
|
offset += item.length + 1;
|
|
return expression;
|
|
}).join(")|(") + ")";
|
|
}
|
|
}, {
|
|
IGNORE: "$0",
|
|
|
|
init: function() {
|
|
forEach ("add,get,has,put,remove".split(","), function(name) {
|
|
_override(this, name, function(expression) {
|
|
if (instanceOf(expression, RegExp)) {
|
|
arguments[0] = expression.source;
|
|
}
|
|
return base(this, arguments);
|
|
});
|
|
}, this.prototype);
|
|
},
|
|
|
|
Item: {
|
|
constructor: function(expression, replacement) {
|
|
if (replacement == null) replacement = RegGrp.IGNORE;
|
|
else if (replacement.replacement != null) replacement = replacement.replacement;
|
|
else if (typeof replacement != "function") replacement = String(replacement);
|
|
|
|
// does the pattern use sub-expressions?
|
|
if (typeof replacement == "string" && _RG_LOOKUP.test(replacement)) {
|
|
// a simple lookup? (e.g. "$2")
|
|
if (_RG_LOOKUP_SIMPLE.test(replacement)) {
|
|
// store the index (used for fast retrieval of matched strings)
|
|
replacement = parseInt(replacement.slice(1));
|
|
} else { // a complicated lookup (e.g. "Hello $2 $1")
|
|
// build a function to do the lookup
|
|
// Improved version by Alexei Gorkov:
|
|
var Q = '"';
|
|
replacement = replacement
|
|
.replace(/\\/g, "\\\\")
|
|
.replace(/"/g, "\\x22")
|
|
.replace(/\n/g, "\\n")
|
|
.replace(/\r/g, "\\r")
|
|
.replace(/\$(\d+)/g, Q + "+(arguments[$1]||" + Q+Q + ")+" + Q)
|
|
.replace(/(['"])\1\+(.*)\+\1\1$/, "$1");
|
|
replacement = new Function("return " + Q + replacement + Q);
|
|
}
|
|
}
|
|
|
|
this.length = RegGrp.count(expression);
|
|
this.replacement = replacement;
|
|
this.toString = K(expression + "");
|
|
},
|
|
|
|
length: 0,
|
|
replacement: ""
|
|
},
|
|
|
|
count: function(expression) {
|
|
// Count the number of sub-expressions in a RegExp/RegGrp.Item.
|
|
expression = (expression + "").replace(_RG_ESCAPE_CHARS, "").replace(_RG_ESCAPE_BRACKETS, "");
|
|
return match(expression, _RG_BRACKETS).length;
|
|
}
|
|
});
|
|
|
|
// =========================================================================
|
|
// lang/package.js
|
|
// =========================================================================
|
|
|
|
var lang = {
|
|
name: "lang",
|
|
version: base2.version,
|
|
exports: "assert,assertArity,assertType,base,bind,copy,extend,forEach,format,instanceOf,match,pcopy,rescape,trim,typeOf",
|
|
namespace: "" // fixed later
|
|
};
|
|
|
|
// =========================================================================
|
|
// lang/assert.js
|
|
// =========================================================================
|
|
|
|
function assert(condition, message, ErrorClass) {
|
|
if (!condition) {
|
|
throw new (ErrorClass || Error)(message || "Assertion failed.");
|
|
}
|
|
};
|
|
|
|
function assertArity(args, arity, message) {
|
|
if (arity == null) arity = args.callee.length;
|
|
if (args.length < arity) {
|
|
throw new SyntaxError(message || "Not enough arguments.");
|
|
}
|
|
};
|
|
|
|
function assertType(object, type, message) {
|
|
if (type && (typeof type == "function" ? !instanceOf(object, type) : typeOf(object) != type)) {
|
|
throw new TypeError(message || "Invalid type.");
|
|
}
|
|
};
|
|
|
|
// =========================================================================
|
|
// lang/copy.js
|
|
// =========================================================================
|
|
|
|
function copy(object) {
|
|
// a quick copy
|
|
var copy = {};
|
|
for (var i in object) {
|
|
copy[i] = object[i];
|
|
}
|
|
return copy;
|
|
};
|
|
|
|
function pcopy(object) {
|
|
// Doug Crockford / Richard Cornford
|
|
_dummy.prototype = object;
|
|
return new _dummy;
|
|
};
|
|
|
|
function _dummy(){};
|
|
|
|
// =========================================================================
|
|
// lang/extend.js
|
|
// =========================================================================
|
|
|
|
function base(object, args) {
|
|
return object.base.apply(object, args);
|
|
};
|
|
|
|
function extend(object, source) { // or extend(object, key, value)
|
|
if (object && source) {
|
|
if (arguments.length > 2) { // Extending with a key/value pair.
|
|
var key = source;
|
|
source = {};
|
|
source[key] = arguments[2];
|
|
}
|
|
var proto = global[(typeof source == "function" ? "Function" : "Object")].prototype;
|
|
// Add constructor, toString etc
|
|
if (base2.__prototyping) {
|
|
var i = _HIDDEN.length, key;
|
|
while ((key = _HIDDEN[--i])) {
|
|
var value = source[key];
|
|
if (value != proto[key]) {
|
|
if (_BASE.test(value)) {
|
|
_override(object, key, value)
|
|
} else {
|
|
object[key] = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Copy each of the source object's properties to the target object.
|
|
for (key in source) {
|
|
if (proto[key] === undefined) {
|
|
var value = source[key];
|
|
// Object detection.
|
|
if (key.charAt(0) == "@") {
|
|
if (detect(key.slice(1))) extend(object, value);
|
|
} else {
|
|
// Check for method overriding.
|
|
var ancestor = object[key];
|
|
if (ancestor && typeof value == "function") {
|
|
if (value != ancestor) {
|
|
if (_BASE.test(value)) {
|
|
_override(object, key, value);
|
|
} else {
|
|
value.ancestor = ancestor;
|
|
object[key] = value;
|
|
}
|
|
}
|
|
} else {
|
|
object[key] = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return object;
|
|
};
|
|
|
|
function _ancestorOf(ancestor, fn) {
|
|
// Check if a function is in another function's inheritance chain.
|
|
while (fn) {
|
|
if (!fn.ancestor) return false;
|
|
fn = fn.ancestor;
|
|
if (fn == ancestor) return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
function _override(object, name, method) {
|
|
// Override an existing method.
|
|
var ancestor = object[name];
|
|
var superObject = base2.__prototyping; // late binding for prototypes
|
|
if (superObject && ancestor != superObject[name]) superObject = null;
|
|
function _base() {
|
|
var previous = this.base;
|
|
this.base = superObject ? superObject[name] : ancestor;
|
|
var returnValue = method.apply(this, arguments);
|
|
this.base = previous;
|
|
return returnValue;
|
|
};
|
|
_base.method = method;
|
|
_base.ancestor = ancestor;
|
|
object[name] = _base;
|
|
// introspection (removed when packed)
|
|
;;; _base.toString = K(method + "");
|
|
};
|
|
|
|
// =========================================================================
|
|
// lang/forEach.js
|
|
// =========================================================================
|
|
|
|
// http://dean.edwards.name/weblog/2006/07/enum/
|
|
|
|
if (typeof StopIteration == "undefined") {
|
|
StopIteration = new Error("StopIteration");
|
|
}
|
|
|
|
function forEach(object, block, context, fn) {
|
|
if (object == null) return;
|
|
if (!fn) {
|
|
if (typeof object == "function" && object.call) {
|
|
// Functions are a special case.
|
|
fn = Function;
|
|
} else if (typeof object.forEach == "function" && object.forEach != arguments.callee) {
|
|
// The object implements a custom forEach method.
|
|
object.forEach(block, context);
|
|
return;
|
|
} else if (typeof object.length == "number") {
|
|
// The object is array-like.
|
|
_Array_forEach(object, block, context);
|
|
return;
|
|
}
|
|
}
|
|
_Function_forEach(fn || Object, object, block, context);
|
|
};
|
|
|
|
forEach.csv = function(string, block, context) {
|
|
forEach (csv(string), block, context);
|
|
};
|
|
|
|
forEach.detect = function(object, block, context) {
|
|
forEach (object, function(value, key) {
|
|
if (key.charAt(0) == "@") { // object detection
|
|
if (detect(key.slice(1))) forEach (value, arguments.callee);
|
|
} else block.call(context, value, key, object);
|
|
});
|
|
};
|
|
|
|
// These are the two core enumeration methods. All other forEach methods
|
|
// eventually call one of these two.
|
|
|
|
function _Array_forEach(array, block, context) {
|
|
if (array == null) array = global;
|
|
var length = array.length || 0, i; // preserve length
|
|
if (typeof array == "string") {
|
|
for (i = 0; i < length; i++) {
|
|
block.call(context, array.charAt(i), i, array);
|
|
}
|
|
} else { // Cater for sparse arrays.
|
|
for (i = 0; i < length; i++) {
|
|
/*@cc_on @*/
|
|
/*@if (@_jscript_version < 5.2)
|
|
if ($Legacy.has(array, i))
|
|
@else @*/
|
|
if (i in array)
|
|
/*@end @*/
|
|
block.call(context, array[i], i, array);
|
|
}
|
|
}
|
|
};
|
|
|
|
function _Function_forEach(fn, object, block, context) {
|
|
// http://code.google.com/p/base2/issues/detail?id=10
|
|
|
|
// Run the test for Safari's buggy enumeration.
|
|
var Temp = function(){this.i=1};
|
|
Temp.prototype = {i:1};
|
|
var count = 0;
|
|
for (var i in new Temp) count++;
|
|
|
|
// Overwrite the main function the first time it is called.
|
|
_Function_forEach = (count > 1) ? function(fn, object, block, context) {
|
|
// Safari fix (pre version 3)
|
|
var processed = {};
|
|
for (var key in object) {
|
|
if (!processed[key] && fn.prototype[key] === undefined) {
|
|
processed[key] = true;
|
|
block.call(context, object[key], key, object);
|
|
}
|
|
}
|
|
} : function(fn, object, block, context) {
|
|
// Enumerate an object and compare its keys with fn's prototype.
|
|
for (var key in object) {
|
|
if (fn.prototype[key] === undefined) {
|
|
block.call(context, object[key], key, object);
|
|
}
|
|
}
|
|
};
|
|
|
|
_Function_forEach(fn, object, block, context);
|
|
};
|
|
|
|
// =========================================================================
|
|
// lang/instanceOf.js
|
|
// =========================================================================
|
|
|
|
function instanceOf(object, klass) {
|
|
// Handle exceptions where the target object originates from another frame.
|
|
// This is handy for JSON parsing (amongst other things).
|
|
|
|
if (typeof klass != "function") {
|
|
throw new TypeError("Invalid 'instanceOf' operand.");
|
|
}
|
|
|
|
if (object == null) return false;
|
|
|
|
/*@cc_on
|
|
// COM objects don't have a constructor
|
|
if (typeof object.constructor != "function") {
|
|
return typeOf(object) == typeof klass.prototype.valueOf();
|
|
}
|
|
@*/
|
|
if (object.constructor == klass) return true;
|
|
if (klass.ancestorOf) return klass.ancestorOf(object.constructor);
|
|
/*@if (@_jscript_version < 5.1)
|
|
// do nothing
|
|
@else @*/
|
|
if (object instanceof klass) return true;
|
|
/*@end @*/
|
|
|
|
// If the class is a base2 class then it would have passed the test above.
|
|
if (Base.ancestorOf == klass.ancestorOf) return false;
|
|
|
|
// base2 objects can only be instances of Object.
|
|
if (Base.ancestorOf == object.constructor.ancestorOf) return klass == Object;
|
|
|
|
switch (klass) {
|
|
case Array: // This is the only troublesome one.
|
|
return !!(typeof object == "object" && object.join && object.splice);
|
|
case Function:
|
|
return typeOf(object) == "function";
|
|
case RegExp:
|
|
return typeof object.constructor.$1 == "string";
|
|
case Date:
|
|
return !!object.getTimezoneOffset;
|
|
case String:
|
|
case Number:
|
|
case Boolean:
|
|
return typeOf(object) == typeof klass.prototype.valueOf();
|
|
case Object:
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
// =========================================================================
|
|
// lang/typeOf.js
|
|
// =========================================================================
|
|
|
|
// http://wiki.ecmascript.org/doku.php?id=proposals:typeof
|
|
|
|
function typeOf(object) {
|
|
var type = typeof object;
|
|
switch (type) {
|
|
case "object":
|
|
return object == null
|
|
? "null"
|
|
: typeof object.constructor == "undefined" // COM object
|
|
? _MSIE_NATIVE_FUNCTION.test(object)
|
|
? "function"
|
|
: type
|
|
: typeof object.constructor.prototype.valueOf(); // underlying type
|
|
case "function":
|
|
return typeof object.call == "function" ? type : "object";
|
|
default:
|
|
return type;
|
|
}
|
|
};
|
|
|
|
// =========================================================================
|
|
// JavaScript/package.js
|
|
// =========================================================================
|
|
|
|
var JavaScript = {
|
|
name: "JavaScript",
|
|
version: base2.version,
|
|
exports: "Array2,Date2,Function2,String2",
|
|
namespace: "", // fixed later
|
|
|
|
bind: function(host) {
|
|
var top = global;
|
|
global = host;
|
|
forEach.csv(this.exports, function(name2) {
|
|
var name = name2.slice(0, -1);
|
|
extend(host[name], this[name2]);
|
|
this[name2](host[name].prototype); // cast
|
|
}, this);
|
|
global = top;
|
|
return host;
|
|
}
|
|
};
|
|
|
|
function _createObject2(Native, constructor, generics, extensions) {
|
|
// Clone native objects and extend them.
|
|
|
|
// Create a Module that will contain all the new methods.
|
|
var INative = Module.extend();
|
|
var id = INative.toString().slice(1, -1);
|
|
// http://developer.mozilla.org/en/docs/New_in_JavaScript_1.6#Array_and_String_generics
|
|
forEach.csv(generics, function(name) {
|
|
INative[name] = unbind(Native.prototype[name]);
|
|
INative.namespace += format("var %1=%2.%1;", name, id);
|
|
});
|
|
forEach (_slice.call(arguments, 3), INative.implement, INative);
|
|
|
|
// create a faux constructor that augments the native object
|
|
var Native2 = function() {
|
|
return INative(this.constructor == INative ? constructor.apply(null, arguments) : arguments[0]);
|
|
};
|
|
Native2.prototype = INative.prototype;
|
|
|
|
// Remove methods that are already implemented.
|
|
for (var name in INative) {
|
|
if (name != "prototype" && Native[name]) {
|
|
delete INative.prototype[name];
|
|
}
|
|
Native2[name] = INative[name];
|
|
}
|
|
Native2.ancestor = Object;
|
|
delete Native2.extend;
|
|
|
|
// remove "lang.bind.."
|
|
Native2.namespace = Native2.namespace.replace(/(var (\w+)=)[^,;]+,([^\)]+)\)/g, "$1$3.$2");
|
|
|
|
return Native2;
|
|
};
|
|
|
|
// =========================================================================
|
|
// JavaScript/~/Date.js
|
|
// =========================================================================
|
|
|
|
// Fix Date.get/setYear() (IE5-7)
|
|
|
|
if ((new Date).getYear() > 1900) {
|
|
Date.prototype.getYear = function() {
|
|
return this.getFullYear() - 1900;
|
|
};
|
|
Date.prototype.setYear = function(year) {
|
|
return this.setFullYear(year + 1900);
|
|
};
|
|
}
|
|
|
|
// https://bugs.webkit.org/show_bug.cgi?id=9532
|
|
|
|
var _testDate = new Date(Date.UTC(2006, 1, 20));
|
|
_testDate.setUTCDate(15);
|
|
if (_testDate.getUTCHours() != 0) {
|
|
forEach.csv("FullYear,Month,Date,Hours,Minutes,Seconds,Milliseconds", function(type) {
|
|
extend(Date.prototype, "setUTC" + type, function() {
|
|
var value = base(this, arguments);
|
|
if (value >= 57722401000) {
|
|
value -= 3600000;
|
|
this.setTime(value);
|
|
}
|
|
return value;
|
|
});
|
|
});
|
|
}
|
|
|
|
// =========================================================================
|
|
// JavaScript/~/Function.js
|
|
// =========================================================================
|
|
|
|
// Some browsers don't define this.
|
|
|
|
Function.prototype.prototype = {};
|
|
|
|
// =========================================================================
|
|
// JavaScript/~/String.js
|
|
// =========================================================================
|
|
|
|
// A KHTML bug.
|
|
|
|
if ("".replace(/^/, K("$$")) == "$") {
|
|
extend(String.prototype, "replace", function(expression, replacement) {
|
|
if (typeof replacement == "function") {
|
|
var fn = replacement;
|
|
replacement = function() {
|
|
return String(fn.apply(null, arguments)).split("$").join("$$");
|
|
};
|
|
}
|
|
return this.base(expression, replacement);
|
|
});
|
|
}
|
|
|
|
// =========================================================================
|
|
// JavaScript/Array2.js
|
|
// =========================================================================
|
|
|
|
var Array2 = _createObject2(
|
|
Array,
|
|
Array,
|
|
"concat,join,pop,push,reverse,shift,slice,sort,splice,unshift", // generics
|
|
Enumerable, {
|
|
combine: function(keys, values) {
|
|
// Combine two arrays to make a hash.
|
|
if (!values) values = keys;
|
|
return Array2.reduce(keys, function(hash, key, index) {
|
|
hash[key] = values[index];
|
|
return hash;
|
|
}, {});
|
|
},
|
|
|
|
contains: function(array, item) {
|
|
return Array2.indexOf(array, item) != -1;
|
|
},
|
|
|
|
copy: function(array) {
|
|
var copy = _slice.call(array);
|
|
if (!copy.swap) Array2(copy); // cast to Array2
|
|
return copy;
|
|
},
|
|
|
|
flatten: function(array) {
|
|
var i = 0;
|
|
return Array2.reduce(array, function(result, item) {
|
|
if (Array2.like(item)) {
|
|
Array2.reduce(item, arguments.callee, result);
|
|
} else {
|
|
result[i++] = item;
|
|
}
|
|
return result;
|
|
}, []);
|
|
},
|
|
|
|
forEach: _Array_forEach,
|
|
|
|
indexOf: function(array, item, fromIndex) {
|
|
var length = array.length;
|
|
if (fromIndex == null) {
|
|
fromIndex = 0;
|
|
} else if (fromIndex < 0) {
|
|
fromIndex = Math.max(0, length + fromIndex);
|
|
}
|
|
for (var i = fromIndex; i < length; i++) {
|
|
if (array[i] === item) return i;
|
|
}
|
|
return -1;
|
|
},
|
|
|
|
insertAt: function(array, index, item) {
|
|
Array2.splice(array, index, 0, item);
|
|
return item;
|
|
},
|
|
|
|
item: function(array, index) {
|
|
if (index < 0) index += array.length; // starting from the end
|
|
return array[index];
|
|
},
|
|
|
|
lastIndexOf: function(array, item, fromIndex) {
|
|
var length = array.length;
|
|
if (fromIndex == null) {
|
|
fromIndex = length - 1;
|
|
} else if (fromIndex < 0) {
|
|
fromIndex = Math.max(0, length + fromIndex);
|
|
}
|
|
for (var i = fromIndex; i >= 0; i--) {
|
|
if (array[i] === item) return i;
|
|
}
|
|
return -1;
|
|
},
|
|
|
|
map: function(array, block, context) {
|
|
var result = [];
|
|
Array2.forEach (array, function(item, index) {
|
|
result[index] = block.call(context, item, index, array);
|
|
});
|
|
return result;
|
|
},
|
|
|
|
remove: function(array, item) {
|
|
var index = Array2.indexOf(array, item);
|
|
if (index != -1) Array2.removeAt(array, index);
|
|
},
|
|
|
|
removeAt: function(array, index) {
|
|
Array2.splice(array, index, 1);
|
|
},
|
|
|
|
swap: function(array, index1, index2) {
|
|
if (index1 < 0) index1 += array.length; // starting from the end
|
|
if (index2 < 0) index2 += array.length;
|
|
var temp = array[index1];
|
|
array[index1] = array[index2];
|
|
array[index2] = temp;
|
|
return array;
|
|
}
|
|
}
|
|
);
|
|
|
|
Array2.reduce = Enumerable.reduce; // Mozilla does not implement the thisObj argument
|
|
|
|
Array2.like = function(object) {
|
|
// is the object like an array?
|
|
return typeOf(object) == "object" && typeof object.length == "number";
|
|
};
|
|
|
|
// introspection (removed when packed)
|
|
;;; Enumerable["#implemented_by"].pop();
|
|
;;; Enumerable["#implemented_by"].push(Array2);
|
|
|
|
// =========================================================================
|
|
// JavaScript/Date2.js
|
|
// =========================================================================
|
|
|
|
// http://developer.mozilla.org/es4/proposals/date_and_time.html
|
|
|
|
// big, ugly, regular expression
|
|
var _DATE_PATTERN = /^((-\d+|\d{4,})(-(\d{2})(-(\d{2}))?)?)?T((\d{2})(:(\d{2})(:(\d{2})(\.(\d{1,3})(\d)?\d*)?)?)?)?(([+-])(\d{2})(:(\d{2}))?|Z)?$/;
|
|
var _DATE_PARTS = { // indexes to the sub-expressions of the RegExp above
|
|
FullYear: 2,
|
|
Month: 4,
|
|
Date: 6,
|
|
Hours: 8,
|
|
Minutes: 10,
|
|
Seconds: 12,
|
|
Milliseconds: 14
|
|
};
|
|
var _TIMEZONE_PARTS = { // idem, but without the getter/setter usage on Date object
|
|
Hectomicroseconds: 15, // :-P
|
|
UTC: 16,
|
|
Sign: 17,
|
|
Hours: 18,
|
|
Minutes: 20
|
|
};
|
|
|
|
var _TRIM_ZEROES = /(((00)?:0+)?:0+)?\.0+$/;
|
|
var _TRIM_TIMEZONE = /(T[0-9:.]+)$/;
|
|
|
|
var Date2 = _createObject2(
|
|
Date,
|
|
function(yy, mm, dd, h, m, s, ms) {
|
|
switch (arguments.length) {
|
|
case 0: return new Date;
|
|
case 1: return typeof yy == "number" ? new Date(yy) : Date2.parse(yy);
|
|
default: return new Date(yy, mm, arguments.length == 2 ? 1 : dd, h || 0, m || 0, s || 0, ms || 0);
|
|
}
|
|
}, "", {
|
|
toISOString: function(date) {
|
|
var string = "####-##-##T##:##:##.###";
|
|
for (var part in _DATE_PARTS) {
|
|
string = string.replace(/#+/, function(digits) {
|
|
var value = date["getUTC" + part]();
|
|
if (part == "Month") value++; // js month starts at zero
|
|
return ("000" + value).slice(-digits.length); // pad
|
|
});
|
|
}
|
|
// remove trailing zeroes, and remove UTC timezone, when time's absent
|
|
return string.replace(_TRIM_ZEROES, "").replace(_TRIM_TIMEZONE, "$1Z");
|
|
}
|
|
}
|
|
);
|
|
|
|
delete Date2.forEach;
|
|
|
|
Date2.now = function() {
|
|
return (new Date).valueOf(); // milliseconds since the epoch
|
|
};
|
|
|
|
Date2.parse = function(string, defaultDate) {
|
|
if (arguments.length > 1) {
|
|
assertType(defaultDate, "number", "default date should be of type 'number'.")
|
|
}
|
|
// parse ISO date
|
|
var parts = match(string, _DATE_PATTERN);
|
|
if (parts.length) {
|
|
if (parts[_DATE_PARTS.Month]) parts[_DATE_PARTS.Month]--; // js months start at zero
|
|
// round milliseconds on 3 digits
|
|
if (parts[_TIMEZONE_PARTS.Hectomicroseconds] >= 5) parts[_DATE_PARTS.Milliseconds]++;
|
|
var date = new Date(defaultDate || 0);
|
|
var prefix = parts[_TIMEZONE_PARTS.UTC] || parts[_TIMEZONE_PARTS.Hours] ? "UTC" : "";
|
|
for (var part in _DATE_PARTS) {
|
|
var value = parts[_DATE_PARTS[part]];
|
|
if (!value) continue; // empty value
|
|
// set a date part
|
|
date["set" + prefix + part](value);
|
|
// make sure that this setting does not overflow
|
|
if (date["get" + prefix + part]() != parts[_DATE_PARTS[part]]) {
|
|
return NaN;
|
|
}
|
|
}
|
|
// timezone can be set, without time being available
|
|
// without a timezone, local timezone is respected
|
|
if (parts[_TIMEZONE_PARTS.Hours]) {
|
|
var hours = Number(parts[_TIMEZONE_PARTS.Sign] + parts[_TIMEZONE_PARTS.Hours]);
|
|
var minutes = Number(parts[_TIMEZONE_PARTS.Sign] + (parts[_TIMEZONE_PARTS.Minutes] || 0));
|
|
date.setUTCMinutes(date.getUTCMinutes() + (hours * 60) + minutes);
|
|
}
|
|
return date.valueOf();
|
|
} else {
|
|
return Date.parse(string);
|
|
}
|
|
};
|
|
|
|
// =========================================================================
|
|
// JavaScript/String2.js
|
|
// =========================================================================
|
|
|
|
var String2 = _createObject2(
|
|
String,
|
|
function(string) {
|
|
return new String(arguments.length == 0 ? "" : string);
|
|
},
|
|
"charAt,charCodeAt,concat,indexOf,lastIndexOf,match,replace,search,slice,split,substr,substring,toLowerCase,toUpperCase",
|
|
{
|
|
csv: csv,
|
|
format: format,
|
|
rescape: rescape,
|
|
trim: trim
|
|
}
|
|
);
|
|
|
|
delete String2.forEach;
|
|
|
|
// http://blog.stevenlevithan.com/archives/faster-trim-javascript
|
|
function trim(string) {
|
|
return String(string).replace(_LTRIM, "").replace(_RTRIM, "");
|
|
};
|
|
|
|
function csv(string) {
|
|
return string ? (string + "").split(/\s*,\s*/) : [];
|
|
};
|
|
|
|
function format(string) {
|
|
// Replace %n with arguments[n].
|
|
// e.g. format("%1 %2%3 %2a %1%3", "she", "se", "lls");
|
|
// ==> "she sells sea shells"
|
|
// Only %1 - %9 supported.
|
|
var args = arguments;
|
|
var pattern = new RegExp("%([1-" + (arguments.length - 1) + "])", "g");
|
|
return (string + "").replace(pattern, function(match, index) {
|
|
return args[index];
|
|
});
|
|
};
|
|
|
|
function match(string, expression) {
|
|
// Same as String.match() except that this function will return an empty
|
|
// array if there is no match.
|
|
return (string + "").match(expression) || [];
|
|
};
|
|
|
|
function rescape(string) {
|
|
// Make a string safe for creating a RegExp.
|
|
return (string + "").replace(_RESCAPE, "\\$1");
|
|
};
|
|
|
|
// =========================================================================
|
|
// JavaScript/Function2.js
|
|
// =========================================================================
|
|
|
|
var Function2 = _createObject2(
|
|
Function,
|
|
Function,
|
|
"", {
|
|
I: I,
|
|
II: II,
|
|
K: K,
|
|
bind: bind,
|
|
compose: compose,
|
|
delegate: delegate,
|
|
flip: flip,
|
|
not: not,
|
|
partial: partial,
|
|
unbind: unbind
|
|
}
|
|
);
|
|
|
|
function I(i) { // return first argument
|
|
return i;
|
|
};
|
|
|
|
function II(i, ii) { // return second argument
|
|
return ii;
|
|
};
|
|
|
|
function K(k) {
|
|
return function() {
|
|
return k;
|
|
};
|
|
};
|
|
|
|
function bind(fn, context) {
|
|
var lateBound = typeof fn != "function";
|
|
if (arguments.length > 2) {
|
|
var args = _slice.call(arguments, 2);
|
|
return function() {
|
|
return (lateBound ? context[fn] : fn).apply(context, args.concat.apply(args, arguments));
|
|
};
|
|
} else { // faster if there are no additional arguments
|
|
return function() {
|
|
return (lateBound ? context[fn] : fn).apply(context, arguments);
|
|
};
|
|
}
|
|
};
|
|
|
|
function compose() {
|
|
var fns = _slice.call(arguments);
|
|
return function() {
|
|
var i = fns.length, result = fns[--i].apply(this, arguments);
|
|
while (i--) result = fns[i].call(this, result);
|
|
return result;
|
|
};
|
|
};
|
|
|
|
function delegate(fn, context) {
|
|
return function() {
|
|
var args = _slice.call(arguments);
|
|
args.unshift(this);
|
|
return fn.apply(context, args);
|
|
};
|
|
};
|
|
|
|
function flip(fn) {
|
|
return function() {
|
|
return fn.apply(this, Array2.swap(arguments, 0, 1));
|
|
};
|
|
};
|
|
|
|
function not(fn) {
|
|
return function() {
|
|
return !fn.apply(this, arguments);
|
|
};
|
|
};
|
|
|
|
function partial(fn) {
|
|
var args = _slice.call(arguments, 1);
|
|
// based on Oliver Steele's version
|
|
return function() {
|
|
var specialised = args.concat(), i = 0, j = 0;
|
|
while (i < args.length && j < arguments.length) {
|
|
if (specialised[i] === undefined) specialised[i] = arguments[j++];
|
|
i++;
|
|
}
|
|
while (j < arguments.length) {
|
|
specialised[i++] = arguments[j++];
|
|
}
|
|
if (Array2.contains(specialised, undefined)) {
|
|
specialised.unshift(fn);
|
|
return partial.apply(null, specialised);
|
|
}
|
|
return fn.apply(this, specialised);
|
|
};
|
|
};
|
|
|
|
function unbind(fn) {
|
|
return function(context) {
|
|
return fn.apply(context, _slice.call(arguments, 1));
|
|
};
|
|
};
|
|
|
|
// =========================================================================
|
|
// base2/detect.js
|
|
// =========================================================================
|
|
|
|
function detect() {
|
|
// Two types of detection:
|
|
// 1. Object detection
|
|
// e.g. detect("(java)");
|
|
// e.g. detect("!(document.addEventListener)");
|
|
// 2. Platform detection (browser sniffing)
|
|
// e.g. detect("MSIE");
|
|
// e.g. detect("MSIE|opera");
|
|
|
|
var jscript = NaN/*@cc_on||@_jscript_version@*/; // http://dean.edwards.name/weblog/2007/03/sniff/#comment85164
|
|
var javaEnabled = global.java ? true : false;
|
|
if (global.navigator) { // browser
|
|
var MSIE = /MSIE[\d.]+/g;
|
|
var element = document.createElement("span");
|
|
// Close up the space between name and version number.
|
|
// e.g. MSIE 6 -> MSIE6
|
|
var userAgent = navigator.userAgent.replace(/([a-z])[\s\/](\d)/gi, "$1$2");
|
|
// Fix opera's (and others) user agent string.
|
|
if (!jscript) userAgent = userAgent.replace(MSIE, "");
|
|
if (MSIE.test(userAgent)) userAgent = userAgent.match(MSIE)[0] + " " + userAgent.replace(MSIE, "");
|
|
base2.userAgent = navigator.platform + " " + userAgent.replace(/like \w+/gi, "");
|
|
javaEnabled &= navigator.javaEnabled();
|
|
//} else if (java) { // rhino
|
|
// var System = java.lang.System;
|
|
// base2.userAgent = "Rhino " + System.getProperty("os.arch") + " " + System.getProperty("os.name") + " " + System.getProperty("os.version");
|
|
//} else if (jscript) { // Windows Scripting Host
|
|
// base2.userAgent = "WSH";
|
|
}
|
|
|
|
var _cache = {};
|
|
detect = function(expression) {
|
|
if (_cache[expression] == null) {
|
|
var returnValue = false, test = expression;
|
|
var not = test.charAt(0) == "!";
|
|
if (not) test = test.slice(1);
|
|
if (test.charAt(0) == "(") {
|
|
try {
|
|
returnValue = new Function("element,jscript,java,global", "return !!" + test)(element, jscript, javaEnabled, global);
|
|
} catch (ex) {
|
|
// the test failed
|
|
}
|
|
} else {
|
|
// Browser sniffing.
|
|
returnValue = new RegExp("(" + test + ")", "i").test(base2.userAgent);
|
|
}
|
|
_cache[expression] = !!(not ^ returnValue);
|
|
}
|
|
return _cache[expression];
|
|
};
|
|
|
|
return detect(arguments[0]);
|
|
};
|
|
|
|
// =========================================================================
|
|
// base2/init.js
|
|
// =========================================================================
|
|
|
|
base2 = global.base2 = new Package(this, base2);
|
|
var exports = this.exports;
|
|
|
|
lang = new Package(this, lang);
|
|
exports += this.exports;
|
|
|
|
JavaScript = new Package(this, JavaScript);
|
|
eval(exports + this.exports);
|
|
|
|
lang.base = base;
|
|
lang.extend = extend;
|
|
|
|
}; //////////////////// END: CLOSURE /////////////////////////////////////
|