Modified:
trunk/lib/base2.js
Log:
Updating to Base2 1.0 final.
Modified: trunk/lib/base2.js
==============================================================================
--- trunk/lib/base2.js (original)
+++ trunk/lib/base2.js Thu Dec 4 09:06:24 2008
@@ -1,89 +1,40 @@
-// timestamp: Sun, 06 Jan 2008 18:17:45
/*
base2 - copyright 2007-2008, Dean Edwards
http://code.google.com/p/base2/
http://www.opensource.org/licenses/mit-license.php
-
+
Contributors:
Doeke Zanstra
*/
+// timestamp: Sat, 06 Sep 2008 16:52:32
+
var base2 = {
name: "base2",
- version: "1.0 (beta 2)",
+ version: "1.0",
exports:
- "Base,Package,Abstract,Module,Enumerable,Map,Collection,RegGrp,"+
- "assert,assertArity,assertType,assignID,copy,detect,extend,"+
- "forEach,format,global,instanceOf,match,rescape,slice,trim,typeOf,"+
- "I,K,Undefined,Null,True,False,bind,delegate,flip,not,unbind",
-
- global: this, // the window object in a browser environment
-
- // this is defined here because it must be defined in the global scope
- detect: new function(_) {
- // 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 global = _;
- var jscript = NaN/*@cc_on||@_jscript_version@*/; //
http://dean.edwards.name/weblog/2007/03/sniff/#comment85164
- var java = _.java ? true : false;
- if (_.navigator) {
- 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, "");
- userAgent = navigator.platform + " " + userAgent;
- java &= navigator.javaEnabled();
- }
-
- return function(expression) {
- var r = false;
- var not = expression.charAt(0) == "!";
- if (not) expression = expression.slice(1);
- if (expression.charAt(0) == "(") {
- // Object detection.
- try {
- eval("r=!!" + expression);
- } catch (e) {
- // the test failed
- }
- } else {
- // Browser sniffing.
- r = new RegExp("(" + expression + ")", "i").test(userAgent);
- }
- return !!(not ^ r);
- };
- }(this)
+ "Base,Package,Abstract,Module,Enumerable,Map,Collection,RegGrp," +
+ "Undefined,Null,This,True,False,assignID,detect,global",
+ namespace: ""
};
-new function(_) { //////////////////// BEGIN: CLOSURE
////////////////////
+new function(_no_shrink_) { /////////////// BEGIN: CLOSURE
///////////////
//
=========================================================================
-// base2/lang/header.js
+// base2/header.js
//
=========================================================================
-var _namespace = "function base(o,a){return o.base.apply(o,a)};";
-eval(_namespace);
-
-var detect = base2.detect;
+var Undefined = K(), Null = K(null), True = K(true), False = K(false),
This = function(){return this};
-var Undefined = K(), Null = K(null), True = K(true), False = K(false);
+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 = /eval/.test(detect) ? /\bbase\s*\(/ : /.*/; // some platforms
don't allow decompilation
+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};
@@ -91,12 +42,14 @@
var _counter = 1;
var _slice = Array.prototype.slice;
-var slice = Array.slice || function(array) {
- return _slice.apply(array, _slice.call(arguments, 1));
-};
-
_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
//
=========================================================================
@@ -107,7 +60,7 @@
// Build the prototype.
base2.__prototyping = this.prototype;
var _prototype = new this;
- extend(_prototype, _instance);
+ if (_instance) extend(_prototype, _instance);
delete base2.__prototyping;
// Create the wrapper for the constructor function.
@@ -133,13 +86,12 @@
for (var i in Base) _class[i] = this[i];
_class.ancestor = this;
_class.base = Undefined;
- _class.init = Undefined;
- extend(_class, _static);
+ //_class.init = Undefined;
+ if (_static) extend(_class, _static);
_class.prototype = _prototype;
- _class.init();
+ if (_class.init) _class.init();
// introspection (removed when packed)
- ;;; _class.toString = K(String(_constructor));
;;; _class["#implements"] = [];
;;; _class["#implemented_by"] = [];
@@ -157,28 +109,29 @@
// Call this method from any other method to invoke the current
method's ancestor (super).
},
- extend: delegate(extend)
+ extend: delegate(extend)
}, Base = {
- ancestorOf: delegate(_ancestorOf),
+ ancestorOf: function(klass) {
+ return _ancestorOf(this, klass);
+ },
extend: _subclass,
- forEach: delegate(_Function_forEach),
+ forEach: function(object, block, context) {
+ _Function_forEach(this, object, block, context);
+ },
implement: function(source) {
if (typeof source == "function") {
- // If we are implementing another classs/module then we can use
- // casting to apply the interface.
- if (_ancestorOf(Base, source)) {
- source(this.prototype); // cast
+ ;;; if (_ancestorOf(Base, source)) {
// introspection (removed when packed)
;;; this["#implements"].push(source);
;;; source["#implemented_by"].push(this);
- }
- } else {
- // Add the interface using the extend() function.
- extend(this.prototype, source);
+ ;;; }
+ source = source.prototype;
}
+ // Add the interface using the extend() function.
+ extend(this.prototype, source);
return this;
}
});
@@ -192,30 +145,52 @@
this.extend(_public);
if (this.init) this.init();
- if (this.name != "base2") {
+ 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,
String(this).slice(1, -1));
+ this.namespace = format("var %1=%2;", this.name, String2.slice(this,
1, -1));
}
- var LIST = /[^\s,]+/g; // pattern for comma separated list
-
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(this.imports.match(LIST),
function(namespace, name) {
- eval("var ns=base2." + name);
- assert(ns, format("Package not found: '%1'.", name),
ReferenceError);
+ _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;
- }, _namespace + base2.namespace + JavaScript.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(this.exports.match(LIST),
function(namespace, name) {
+ _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) + "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: "",
@@ -237,7 +212,7 @@
},
toString: function() {
- return format("[%1]", this.parent ? String(this.parent).slice(1, -1)
+ "." + this.name : this.name);
+ return format("[%1]", this.parent ? String2.slice(this.parent, 1, -1)
+ "." + this.name : this.name);
}
});
@@ -247,7 +222,7 @@
var Abstract = Base.extend({
constructor: function() {
- throw new TypeError("Class cannot be instantiated.");
+ throw new TypeError("Abstract class cannot be instantiated.");
}
});
@@ -255,62 +230,116 @@
// 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.
- module.implement(_interface);
+ if (_interface) module.implement(_interface);
// Implement static properties and methods.
- extend(module, _static);
- module.init();
+ 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.
- forEach (_interface, function(property, name) {
- if (!module[name]) {
+ for (var name in _interface) {
+ if (module[name] === undefined) {
+ var property = _interface[name];
if (typeof property == "function" && property.call &&
_interface.prototype[name]) {
- property = function() { // Late binding.
- return _interface[name].apply(_interface, arguments);
- };
+ 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.
- _Function_forEach (Object, _interface, function(source, name) {
- if (name.charAt(0) == "@") { // object detection
- if (detect(name.slice(1))) {
- forEach (source, arguments.callee);
- }
- } else if (typeof source == "function" && source.call) {
- module.prototype[name] = function() { // Late binding.
- var args = _slice.call(arguments);
- args.unshift(this);
- return module[name].apply(module, args);
- };
- ;;; module.prototype[name]._module = module; // introspection
- }
- });
+ _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
//
=========================================================================
@@ -319,7 +348,7 @@
every: function(object, test, context) {
var result = true;
try {
- this.forEach (object, function(value, key) {
+ forEach (object, function(value, key) {
result = test.call(context, value, key, object);
if (!result) throw StopIteration;
});
@@ -343,15 +372,15 @@
// 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);
+ return item == null ? undefined : method.apply(item, args);
} : function(item) {
- return (item == null) ? undefined : item[method].apply(item, args);
+ return item == null ? undefined : item[method].apply(item, args);
});
},
map: function(object, block, context) {
var result = [], i = 0;
- this.forEach (object, function(value, key) {
+ forEach (object, function(value, key) {
result[i++] = block.call(context, value, key, object);
});
return result;
@@ -359,13 +388,13 @@
pluck: function(object, key) {
return this.map(object, function(item) {
- return (item == null) ? undefined : item[key];
+ return item == null ? undefined : item[key];
});
},
reduce: function(object, block, result, context) {
var initialised = arguments.length > 2;
- this.forEach (object, function(value, key) {
+ forEach (object, function(value, key) {
if (initialised) {
result = block.call(context, result, value, key, object);
} else {
@@ -379,11 +408,8 @@
some: function(object, test, context) {
return !this.every(object, not(test), context);
}
-}, {
- forEach: forEach
});
-
//
=========================================================================
// base2/Map.js
//
=========================================================================
@@ -394,13 +420,27 @@
var Map = Base.extend({
constructor: function(values) {
- this.merge(values);
+ if (values) this.merge(values);
+ },
+
+ clear: function() {
+ for (var key in this) if (key.indexOf(_HASH) == 0) {
+ delete this[key];
+ }
},
- copy: delegate(copy),
+ 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.charAt(0) == _HASH) {
+ for (var key in this) if (key.indexOf(_HASH) == 0) {
block.call(context, this[key], key.slice(1), this);
}
},
@@ -410,14 +450,14 @@
},
getKeys: function() {
- return this.map(flip(I));
+ return this.map(II);
},
getValues: function() {
return this.map(I);
},
- // Ancient browsers throw an error when we use "in" as an operator.
+ // Ancient browsers throw an error if we use "in" as an operator.
has: function(key) {
/*@cc_on @*/
/*@if (@_jscript_version < 5.5)
@@ -435,20 +475,19 @@
return this;
},
- remove: function(key) {
- delete this[_HASH + key];
- },
-
put: function(key, value) {
- if (arguments.length == 1) value = key;
// 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.charAt(0) == _HASH) size++;
+ for (var key in this) if (key.indexOf(_HASH) == 0) size++;
return size;
},
@@ -459,6 +498,15 @@
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
//
=========================================================================
@@ -489,13 +537,18 @@
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) { // optimised (refers to _HASH)
+ forEach: function(block, context) {
var keys = this[_KEYS];
var length = keys.length;
for (var i = 0; i < length; i++) {
@@ -504,13 +557,12 @@
},
getAt: function(index) {
- if (index < 0) index += this[_KEYS].length; // starting from the end
- var key = this[_KEYS][index];
+ var key = this[_KEYS].item(index);
return (key === undefined) ? undefined : this[_HASH + key];
},
getKeys: function() {
- return this[_KEYS].concat();
+ return this[_KEYS].copy();
},
indexOf: function(key) {
@@ -518,19 +570,18 @@
},
insertAt: function(index, key, item) {
- assert(Math.abs(index) < this[_KEYS].length, "Index out of bounds.");
+ 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[_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 (arguments.length == 1) item = key;
if (!this.has(key)) {
this[_KEYS].push(String(key));
}
@@ -542,8 +593,8 @@
},
putAt: function(index, item) {
- assert(Math.abs(index) < this[_KEYS].length, "Index out of bounds.");
arguments[0] = this[_KEYS].item(index);
+ assert(arguments[0] !== undefined, "Index out of bounds.");
this.put.apply(this, arguments);
},
@@ -556,8 +607,11 @@
},
removeAt: function(index) {
- var key = this[_KEYS].removeAt(index);
- delete this[_HASH + key];
+ var key = this[_KEYS].item(index);
+ if (key !== undefined) {
+ this[_KEYS].removeAt(index);
+ delete this[_HASH + key];
+ }
},
reverse: function() {
@@ -569,18 +623,35 @@
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) {
- var self = this;
- this[_KEYS].sort(function(key1, key2) {
- return compare(self[_HASH + key1], self[_HASH + key2], key1, key2);
- });
+ 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 String(this[_KEYS]);
+ return "(" + (this[_KEYS] || "") + ")";
}
}, {
Item: null, // If specified, all members of the collection must be
instances of Item.
@@ -592,13 +663,13 @@
extend: function(_instance, _static) {
var klass = this.base(_instance);
klass.create = this.create;
- extend(klass, _static);
+ 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);
}
- klass.init();
+ if (klass.init) klass.init();
return klass;
}
});
@@ -618,47 +689,38 @@
_RG_LOOKUP_SIMPLE = /^\$\d+$/;
var RegGrp = Collection.extend({
- constructor: function(values, flags) {
+ constructor: function(values, ignoreCase) {
this.base(values);
- if (typeof flags == "string") {
- this.global = /g/.test(flags);
- this.ignoreCase = /i/.test(flags);
- }
+ this.ignoreCase = !!ignoreCase;
},
- global: true, // global is the default setting
ignoreCase: false,
- exec: function(string, replacement) { // optimised (refers to
_HASH/_KEYS)
- var flags = (this.global ? "g" : "") + (this.ignoreCase ? "i" : "");
- string = String(string) + ""; // type-safe
- if (arguments.length == 1) {
- var self = this;
- var keys = this[_KEYS];
- replacement = function(match) {
- if (match) {
- var item, offset = 1, i = 0;
- // Loop through the RegGrp items.
- while ((item = self[_HASH + keys[i++]])) {
- var next = offset + item.length + 1;
- if (arguments[offset]) { // do we have a result?
- var replacement = item.replacement;
- switch (typeof replacement) {
- case "function":
- return replacement.apply(self, _slice.call(arguments,
offset, next));
- case "number":
- return arguments[offset + replacement];
- default:
- return replacement;
- }
- }
- offset = next;
+ 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;
}
}
- return "";
- };
- }
- return string.replace(new RegExp(this, flags), replacement);
+ offset = next;
+ }
+ return match;
+ });
},
insertAt: function(index, expression, replacement) {
@@ -669,18 +731,19 @@
},
test: function(string) {
+ // The slow way to do it. Hopefully, this isn't called too often. :-)
return this.exec(string) != string;
},
toString: function() {
- var length = 0;
+ var offset = 1;
return "(" + this.map(function(item) {
// Fix back references.
- var ref = String(item).replace(_RG_BACK_REF, function(match, index) {
- return "\\" + (1 + Number(index) + length);
+ var expression = (item + "").replace(_RG_BACK_REF, function(match,
index) {
+ return "\\" + (offset + Number(index));
});
- length += item.length + 1;
- return ref;
+ offset += item.length + 1;
+ return expression;
}).join(")|(") + ")";
}
}, {
@@ -699,8 +762,9 @@
Item: {
constructor: function(expression, replacement) {
- if (typeof replacement == "number") replacement =
String(replacement);
- else if (replacement == null) 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)) {
@@ -710,16 +774,22 @@
replacement = parseInt(replacement.slice(1));
} else { // a complicated lookup (e.g. "Hello $2 $1")
// build a function to do the lookup
- var Q = /'/.test(replacement.replace(/\\./g, "")) ? '"' : "'";
- replacement =
replacement.replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\$(\d+)/g,
Q +
- "+(arguments[$1]||" + Q+Q + ")+" + Q);
- replacement = new Function("return " + Q +
replacement.replace(/(['"])\1\+(.*)\+\1\1$/, "$1") + Q);
+ // 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(String(expression));
+ this.toString = K(expression + "");
},
length: 0,
@@ -728,2199 +798,881 @@
count: function(expression) {
// Count the number of sub-expressions in a RegExp/RegGrp.Item.
- expression =
String(expression).replace(_RG_ESCAPE_CHARS, "").replace(_RG_ESCAPE_BRACKETS, "");
+ expression = (expression
+ "").replace(_RG_ESCAPE_CHARS, "").replace(_RG_ESCAPE_BRACKETS, "");
return match(expression, _RG_BRACKETS).length;
}
});
//
=========================================================================
-// JavaScript/package.js
+// lang/package.js
//
=========================================================================
-var JavaScript = {
- name: "JavaScript",
+var lang = {
+ name: "lang",
version: base2.version,
- exports: "Array2,Date2,String2",
- namespace: "", // fixed later
-
- bind: function(host) {
- forEach (this.exports.match(/\w+/g), function(name2) {
- var name = name2.slice(0, -1);
- extend(host[name], this[name2]);
- this[name2](host[name].prototype); // cast
- }, this);
- return this;
- }
+
exports: "assert,assertArity,assertType,base,bind,copy,extend,forEach,format,instanceOf,match,pcopy,rescape,trim,typeOf",
+ namespace: "" // fixed later
};
//
=========================================================================
-// JavaScript/~/Date.js
+// lang/assert.js
//
=========================================================================
-// Fix Date.get/setYear() (IE5-7)
+function assert(condition, message, ErrorClass) {
+ if (!condition) {
+ throw new (ErrorClass || Error)(message || "Assertion failed.");
+ }
+};
-if ((new Date).getYear() > 1900) {
- Date.prototype.getYear = function() {
- return this.getFullYear() - 1900;
- };
- Date.prototype.setYear = function(year) {
- return this.setFullYear(year + 1900);
- };
-}
+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.");
+ }
+};
//
=========================================================================
-// JavaScript/~/Function.js
+// lang/copy.js
//
=========================================================================
-// Some browsers don't define this.
+function copy(object) {
+ // a quick copy
+ var copy = {};
+ for (var i in object) {
+ copy[i] = object[i];
+ }
+ return copy;
+};
-Function.prototype.prototype = {};
+function pcopy(object) {
+ // Doug Crockford / Richard Cornford
+ _dummy.prototype = object;
+ return new _dummy;
+};
+
+function _dummy(){};
//
=========================================================================
-// JavaScript/~/String.js
+// lang/extend.js
//
=========================================================================
-// A KHTML bug.
+function base(object, args) {
+ return object.base.apply(object, args);
+};
-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("$$");
- };
+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];
}
- return this.base(expression, replacement);
- });
-}
+ 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 + "");
+};
//
=========================================================================
-// JavaScript/Array2.js
+// lang/forEach.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 this.reduce(keys, function(hash, key, index) {
- hash[key] = values[index];
- return hash;
- }, {});
- },
-
- contains: function(array, item) {
- return this.indexOf(array, item) != -1;
- },
+// http://dean.edwards.name/weblog/2006/07/enum/
- copy: function(array) {
- var copy = _slice.call(array);
- if (!copy.swap) this(copy); // cast to Array2
- return copy;
- },
-
- flatten: function(array) {
- var length = 0;
- return this.reduce(array, function(result, item) {
- if (this.like(item)) {
- this.reduce(item, arguments.callee, result, this);
- } else {
- result[length++] = item;
- }
- return result;
- }, [], this);
- },
-
- 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) {
- this.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 = [];
- this.forEach (array, function(item, index) {
- result[index] = block.call(context, item, index, array);
- });
- return result;
- },
-
- remove: function(array, item) {
- var index = this.indexOf(array, item);
- if (index != -1) this.removeAt(array, index);
- return item;
- },
-
- removeAt: function(array, index) {
- return this.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 !!(object && 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 new Date(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");
- }
- }]
-);
-
-Date2.now = function() {
- return (new Date).valueOf(); // milliseconds since the epoch
-};
-
-Date2.parse = function(string, defaultDate) {
- if (arguments.length > 1) {
- assertType(defaultDate, "number", "defaultDate should be of
type 'number'.")
- }
- // parse ISO date
- var match = String(string).match(_DATE_PATTERN);
- if (match) {
- if (match[_DATE_PARTS.Month]) match[_DATE_PARTS.Month]--; // js months
start at zero
- // round milliseconds on 3 digits
- if (match[_TIMEZONE_PARTS.Hectomicroseconds] >= 5)
match[_DATE_PARTS.Milliseconds]++;
- var date = new Date(defaultDate || 0);
- var prefix = match[_TIMEZONE_PARTS.UTC] ||
match[_TIMEZONE_PARTS.Hours] ? "UTC" : "";
- for (var part in _DATE_PARTS) {
- var value = match[_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]() != match[_DATE_PARTS[part]]) {
- return NaN;
- }
- }
- // timezone can be set, without time being available
- // without a timezone, local timezone is respected
- if (match[_TIMEZONE_PARTS.Hours]) {
- var Hours = Number(match[_TIMEZONE_PARTS.Sign] +
match[_TIMEZONE_PARTS.Hours]);
- var Minutes = Number(match[_TIMEZONE_PARTS.Sign] +
(match[_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",
- [{trim: trim}]
-);
-
-//
=========================================================================
-// JavaScript/functions.js
-//
=========================================================================
-
-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();
- //
http://developer.mozilla.org/en/docs/New_in_JavaScript_1.6#Array_and_String_generics
- forEach (generics.match(/\w+/g), function(name) {
- INative[name] = unbind(Native.prototype[name]);
- });
- forEach (extensions, 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.
- forEach (INative, function(method, name) {
- if (Native[name]) {
- INative[name] = Native[name];
- delete INative.prototype[name];
- }
- Native2[name] = INative[name];
- });
- Native2.ancestor = Object;
- delete Native2.extend;
- if (Native != Array) delete Native2.forEach;
-
- return Native2;
-};
-
-//
=========================================================================
-// lang/extend.js
-//
=========================================================================
-
-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 = (typeof source == "function" ? Function :
Object).prototype;
- // Add constructor, toString etc
- var i = _HIDDEN.length, key;
- if (base2.__prototyping) {
- 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))) arguments.callee(object, value);
- continue;
- }
- // Check for method overriding.
- var ancestor = object[key];
- if (ancestor && typeof value == "function") {
- if (value != ancestor && (!ancestor.method |
| !_ancestorOf(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 classes
- 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.ancestor = ancestor;
- object[name] = _base;
- // introspection (removed when packed)
- ;;; _base.toString = K(String(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);
-};
-
-// 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) return;
- var length = array.length, 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/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.call == "function" |
| _MSIE_NATIVE_FUNCTION.test(object) ? "function" : type;
- case "function":
- return typeof object.call == "function" ? type : "object";
- default:
- return type;
- }
-};
-
-//
=========================================================================
-// 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 (@_jscript_version < 5.1)
- if ($Legacy.instanceOf(object, klass)) return true;
- @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: // These are bullet-proof.
- case Boolean:
- return typeof object == typeof klass.prototype.valueOf();
- case Object:
- return true;
- }
-
- return false;
-};
-
-//
=========================================================================
-// 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/core.js
-//
=========================================================================
-
-function assignID(object) {
- // Assign a unique ID to an object.
- if (!object.base2ID) object.base2ID = "b2_" + _counter++;
- return object.base2ID;
-};
-
-function copy(object) {
- var fn = function(){};
- fn.prototype = object;
- return new fn;
-};
-
-// String/RegExp.
-
-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 + "])", "g");
- return String(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(string).match(expression) || [];
-};
-
-function rescape(string) {
- // Make a string safe for creating a RegExp.
- return String(string).replace(_RESCAPE, "\\$1");
-};
-
-// http://blog.stevenlevithan.com/archives/faster-trim-javascript
-function trim(string) {
- return String(string).replace(_LTRIM, "").replace(_RTRIM, "");
-};
-
-//
=========================================================================
-// lang/functional.js
-//
=========================================================================
-
-function I(i) {
- return i;
-};
-
-function K(k) {
- return function() {
- return k;
- };
-};
-
-function bind(fn, context) {
- var args = _slice.call(arguments, 2);
- return args.length == 0 ? function() {
- return fn.apply(context, arguments);
- } : function() {
- return fn.apply(context, args.concat.apply(args, arguments));
- };
-};
-
-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 unbind(fn) {
- return function(context) {
- return fn.apply(context, _slice.call(arguments, 1));
- };
-};
-
-//
=========================================================================
-// base2/init.js
-//
=========================================================================
-
-base2 = new Package(this, base2);
-eval(this.exports);
-
-base2.extend = extend;
-
-// the enumerable methods are extremely useful so we'll add them to the
base2
-// namespace for convenience
-forEach (Enumerable, function(method, name) {
- if (!Module[name]) base2.addName(name, bind(method, Enumerable));
-});
-
-JavaScript = new Package(this, JavaScript);
-eval(this.exports);
-
-}; //////////////////// END: CLOSURE
/////////////////////////////////////
-// timestamp: Sun, 06 Jan 2008 18:17:46
-
-new function(_) { //////////////////// BEGIN: CLOSURE
////////////////////
-
-//
=========================================================================
-// DOM/package.js
-//
=========================================================================
-
-var DOM = new base2.Package(this, {
- name: "DOM",
- version: "1.0 (beta 2)",
- exports:
- "Interface,Binding,Node,Document,Element,AbstractView,HTMLDocument,HTMLElement,"+
- "Selector,Traversal,XPathParser,NodeSelector,DocumentSelector,ElementSelector,"+
- "StaticNodeList,Event,EventTarget,DocumentEvent,ViewCSS,CSSStyleDeclaration",
-
- bind: function(node) {
- // Apply a base2 DOM Binding to a native DOM node.
- if (node && node.nodeType) {
- var uid = assignID(node);
- if (!DOM.bind[uid]) {
- switch (node.nodeType) {
- case 1: // Element
- if (typeof node.className == "string") {
- // It's an HTML element, so use bindings based on tag name.
- (HTMLElement.bindings[node.tagName] ||
HTMLElement).bind(node);
- } else {
- Element.bind(node);
- }
- break;
- case 9: // Document
- if (node.writeln) {
- HTMLDocument.bind(node);
- } else {
- Document.bind(node);
- }
- break;
- default:
- Node.bind(node);
- }
- DOM.bind[uid] = true;
- }
- }
- return node;
- },
-
- "@MSIE5.+win": {
- bind: function(node) {
- if (node && node.writeln) {
- node.nodeType = 9;
- }
- return this.base(node);
- }
- }
-});
-
-eval(this.imports);
-
-var _MSIE = detect("MSIE");
-var _MSIE5 = detect("MSIE5");
-
-//
=========================================================================
-// DOM/Interface.js
-//
=========================================================================
-
-// The Interface module is the base module for defining DOM interfaces.
-// Interfaces are defined with reference to the original W3C IDL.
-// e.g. http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1950641247
+if (typeof StopIteration == "undefined") {
+ StopIteration = new Error("StopIteration");
+}
-var Interface = Module.extend(null, {
- implement: function(_interface) {
- var module = this;
- if (Interface.ancestorOf(_interface)) {
- forEach (_interface, function(property, name) {
- if (_interface[name]._delegate) {
- module[name] = function() { // Late binding.
- return _interface[name].apply(_interface, arguments);
- };
- }
- });
- } else if (typeof _interface == "object") {
- this.forEach (_interface, function(source, name) {
- if (name.charAt(0) == "@") {
- forEach (source, arguments.callee);
- } else if (typeof source == "function" && source.call) {
- // delegate a static method to the bound object
- // e.g. for most browsers:
- // EventTarget.addEventListener(element, type, listener,
capture)
- // forwards to:
- // element.addEventListener(type, listener, capture)
- if (!module[name]) {
- var FN = "var fn=function _%1(%2){%3.base=%3.%1.ancestor;var
m=%3.base?'base':'%1';return %3[m](%4)}";
- var args = "abcdefghij".split("").slice(-source.length);
- eval(format(FN, name, args, args[0], args.slice(1)));
- fn._delegate = name;
- module[name] = fn;
- }
- }
- });
+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;
}
- return this.base(_interface);
}
-});
-
-//
=========================================================================
-// DOM/Binding.js
-//
=========================================================================
-
-var Binding = Interface.extend(null, {
- bind: function(object) {
- return extend(object, this.prototype);
- }
-});
-
-//
=========================================================================
-// DOM/Node.js
-//
=========================================================================
-
-// http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1950641247
+ _Function_forEach(fn || Object, object, block, context);
+};
-var Node = Binding.extend({
- "@!(element.compareDocumentPosition)" : {
- compareDocumentPosition: function(node, other) {
- //
http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-compareDocumentPosition
-
- if (Traversal.contains(node, other)) {
- return 4|16; // following|contained_by
- } else if (Traversal.contains(other, node)) {
- return 2|8; // preceding|contains
- }
-
- var nodeIndex = _getSourceIndex(node);
- var otherIndex = _getSourceIndex(other);
-
- if (nodeIndex < otherIndex) {
- return 4; // following
- } else if (nodeIndex > otherIndex) {
- return 2; // preceding
- }
- return 0;
- }
- }
-});
+forEach.csv = function(string, block, context) {
+ forEach (csv(string), block, context);
+};
-var _getSourceIndex = document.documentElement.sourceIndex ?
function(node) {
- return node.sourceIndex;
-} : function(node) {
- // return a key suitable for comparing nodes
- var key = 0;
- while (node) {
- key = Traversal.getNodeIndex(node) + "." + key;
- node = node.parentNode;
- }
- return key;
+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);
+ });
};
-//
=========================================================================
-// DOM/Document.js
-//
=========================================================================
+// These are the two core enumeration methods. All other forEach methods
+// eventually call one of these two.
-var Document = Node.extend(null, {
- bind: function(document) {
- extend(document, "createElement", function(tagName) {
- return DOM.bind(this.base(tagName));
- });
- AbstractView.bind(document.defaultView);
- if (document != window.document)
- new DOMContentLoadedEvent(document);
- return this.base(document);
- },
-
- "@!(document.defaultView)": {
- bind: function(document) {
- document.defaultView = Traversal.getDefaultView(document);
- return this.base(document);
+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);
}
}
-});
-
-//
=========================================================================
-// DOM/Element.js
-//
=========================================================================
-
-// http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-745549614
-
-// Fix has/get/setAttribute() for IE here instead of HTMLElement.
-
-// getAttribute() will return null if the attribute is not specified. This
is
-// contrary to the specification but has become the de facto standard.
-
-var _EVALUATED = /^(href|src)$/;
-var _ATTRIBUTES = {
- "class": "className",
- "for": "htmlFor"
};
-var Element = Node.extend({
- "@MSIE.+win": {
- getAttribute: function(element, name, iFlags) {
- if (element.className === undefined) { // XML
- return this.base(element, name);
- }
- var attribute = _MSIE_getAttributeNode(element, name);
- if (attribute && (attribute.specified || name == "value")) {
- if (_EVALUATED.test(name)) {
- return this.base(element, name, 2);
- } else if (name == "style") {
- return element.style.cssText;
- } else {
- return attribute.nodeValue;
- }
- }
- return null;
- },
-
- setAttribute: function(element, name, value) {
- if (element.className === undefined) { // XML
- this.base(element, name, value);
- } else if (name == "style") {
- element.style.cssText = value;
- } else {
- value = String(value);
- var attribute = _MSIE_getAttributeNode(element, name);
- if (attribute) {
- attribute.nodeValue = value;
- } else {
- this.base(element, _ATTRIBUTES[name] || name, value);
- }
+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);
}
}
- },
-
- "@!(element.hasAttribute)": {
- hasAttribute: function(element, name) {
- return this.getAttribute(element, name) != null;
+ } : 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);
+ }
}
- }
-});
-
-// remove the base2ID for clones
-extend(Element.prototype, "cloneNode", function(deep) {
- var clone = this.base(deep || false);
- clone.base2ID = undefined;
- return clone;
-});
-
-if (_MSIE) {
- var _PROPERCASE_ATTRIBUTES
= "colSpan,rowSpan,vAlign,dateTime,accessKey,tabIndex,encType,maxLength,readOnly,longDesc";
- // Convert the list of strings to a hash, mapping the lowercase name to
the camelCase name.
- extend(_ATTRIBUTES,
Array2.combine(_PROPERCASE_ATTRIBUTES.toLowerCase().split(","),
_PROPERCASE_ATTRIBUTES.split(",")));
-
- var _MSIE_getAttributeNode = _MSIE5 ? function(element, name) {
- return element.attributes[name] ||
element.attributes[_ATTRIBUTES[name.toLowerCase()]];
- } : function(element, name) {
- return element.getAttributeNode(name);
};
-}
+
+ _Function_forEach(fn, object, block, context);
+};
//
=========================================================================
-// DOM/Traversal.js
+// lang/instanceOf.js
//
=========================================================================
-// DOM Traversal. Just the basics.
-
-// Loosely based on this:
-// http://www.w3.org/TR/2007/WD-ElementTraversal-20070727/
-
-var TEXT = _MSIE ? "innerText" : "textContent";
-
-var Traversal = Module.extend({
- getDefaultView: function(node) {
- return this.getDocument(node).defaultView;
- },
+function instanceOf(object, klass) {
+ // Handle exceptions where the target object originates from another
frame.
+ // This is handy for JSON parsing (amongst other things).
- getNextElementSibling: function(node) {
- // return the next element to the supplied element
- // nextSibling is not good enough as it might return a text or
comment node
- while (node && (node = node.nextSibling) && !this.isElement(node))
continue;
- return node;
- },
+ if (typeof klass != "function") {
+ throw new TypeError("Invalid 'instanceOf' operand.");
+ }
- getNodeIndex: function(node) {
- var index = 0;
- while (node && (node = node.previousSibling)) index++;
- return index;
- },
-
- getOwnerDocument: function(node) {
- // return the node's containing document
- return node.ownerDocument;
- },
+ if (object == null) return false;
- getPreviousElementSibling: function(node) {
- // return the previous element to the supplied element
- while (node && (node = node.previousSibling) && !this.isElement(node))
continue;
- return node;
- },
-
- getTextContent: function(node) {
- return node[TEXT];
- },
-
- isEmpty: function(node) {
- node = node.firstChild;
- while (node) {
- if (node.nodeType == 3 || this.isElement(node)) return false;
- node = node.nextSibling;
- }
- return true;
- },
+ /*@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 @*/
- setTextContent: function(node, text) {
- return node[TEXT] = text;
- },
+ // If the class is a base2 class then it would have passed the test
above.
+ if (Base.ancestorOf == klass.ancestorOf) return false;
- "@MSIE": {
- getDefaultView: function(node) {
- return (node.document || node).parentWindow;
- },
+ // base2 objects can only be instances of Object.
+ if (Base.ancestorOf == object.constructor.ancestorOf) return klass ==
Object;
- "@MSIE5": {
- // return the node's containing document
- getOwnerDocument: function(node) {
- return node.ownerDocument || node.document;
- }
- }
+ 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;
}
-}, {
- contains: function(node, target) {
- while (target && (target = target.parentNode) && node != target)
continue;
- return !!target;
- },
-
- getDocument: function(node) {
- // return the document object
- return this.isDocument(node) ? node : this.getOwnerDocument(node);
- },
- isDocument: function(node) {
- return !!(node && node.documentElement);
- },
-
- isElement: function(node) {
- return !!(node && node.nodeType == 1);
- },
-
- "@(element.contains)": {
- contains: function(node, target) {
- return node != target && (this.isDocument(node) ? node ==
this.getOwnerDocument(target) : node.contains(target));
- }
- },
-
- "@MSIE5": {
- isElement: function(node) {
- return !!(node && node.nodeType == 1 && node.nodeName != "!");
- }
- }
-});
-
-//
=========================================================================
-// DOM/views/AbstractView.js
-//
=========================================================================
-
-var AbstractView = Binding.extend();
-
-//
=========================================================================
-// DOM/events/Event.js
-//
=========================================================================
-
-// http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-Event
-
-var Event = Binding.extend({
- "@!(document.createEvent)": {
- initEvent: function(event, type, bubbles, cancelable) {
- event.type = type;
- event.bubbles = bubbles;
- event.cancelable = cancelable;
- event.timeStamp = new Date().valueOf();
- },
-
- "@MSIE": {
- initEvent: function(event, type, bubbles, cancelable) {
- this.base(event, type, bubbles, cancelable);
- event.cancelBubble = !event.bubbles;
- },
-
- preventDefault: function(event) {
- if (event.cancelable !== false) {
- event.returnValue = false;
- }
- },
-
- stopPropagation: function(event) {
- event.cancelBubble = true;
- }
- }
- }
-}, {
-/* "@WebKit": {
- bind: function(event) {
- if (event.target && event.target.nodeType == 3) { // TEXT_NODE
- event = copy(event);
- event.target = event.target.parentNode;
- }
- return this.base(event);
- }
- }, */
-
- "@!(document.createEvent)": {
- "@MSIE": {
- bind: function(event) {
- if (!event.timeStamp) {
- event.bubbles = !!_BUBBLES[event.type];
- event.cancelable = !!_CANCELABLE[event.type];
- event.timeStamp = new Date().valueOf();
- }
- if (!event.target) {
- event.target = event.srcElement;
- }
- event.relatedTarget = event[(event.type
== "mouseout" ? "to" : "from") + "Element"];
- return this.base(event);
- }
- }
- }
-});
-
-if (_MSIE) {
- var _BUBBLES = "abort,error,select,change,resize,scroll"; // +
_CANCELABLE
- var _CANCELABLE
= "click,mousedown,mouseup,mouseover,mousemove,mouseout,keydown,keyup,submit,reset";
- _BUBBLES = Array2.combine((_BUBBLES + "," + _CANCELABLE).split(","));
- _CANCELABLE = Array2.combine(_CANCELABLE.split(","));
-}
+ return false;
+};
//
=========================================================================
-// DOM/events/EventTarget.js
+// lang/typeOf.js
//
=========================================================================
-//
http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-Registration-interfaces
-
-// TO DO: event capture
-
-var EventTarget = Interface.extend({
- "@!(element.addEventListener)": {
- addEventListener: function(target, type, listener, capture) {
- // assign a unique id to both objects
- var targetID = assignID(target);
- var listenerID = assignID(listener);
- // create a hash table of event types for the target object
- var events = _eventMap[targetID];
- if (!events) events = _eventMap[targetID] = {};
- // create a hash table of event listeners for each object/event pair
- var listeners = events[type];
- var current = target["on" + type];
- if (!listeners) {
- listeners = events[type] = {};
- // store the existing event listener (if there is one)
- if (current) listeners[0] = current;
- }
- // store the event listener in the hash table
- listeners[listenerID] = listener;
- if (current !== undefined) {
- target["on" + type] = _eventMap._handleEvent;
- }
- },
-
- dispatchEvent: function(target, event) {
- return _handleEvent.call(target, event);
- },
-
- removeEventListener: function(target, type, listener, capture) {
- // delete the event listener from the hash table
- var events = _eventMap[target.base2ID];
- if (events && events[type]) {
- delete events[type][listener.base2ID];
- }
- },
-
- "@(element.fireEvent)": {
- dispatchEvent: function(target, event) {
- var type = "on" + event.type;
- event.target = target;
- if (target[type] === undefined) {
- return this.base(target, event);
- } else {
- return target.fireEvent(type, event);
- }
- }
- }
- }
-});
-
-var _eventMap = new Base({
- _handleEvent: _handleEvent,
-
- "@MSIE": {
- _handleEvent: function() {
- var target = this;
- var window = (target.document || target).parentWindow;
- if (target.Infinity) target = window;
- return _handleEvent.call(target, window.event);
- }
- }
-});
+// http://wiki.ecmascript.org/doku.php?id=proposals:typeof
-function _handleEvent(event) {
- var returnValue = true;
- // get a reference to the hash table of event listeners
- var events = _eventMap[this.base2ID];
- if (events) {
- Event.bind(event); // fix the event object
- var listeners = events[event.type];
- // execute each event listener
- for (var i in listeners) {
- var listener = listeners[i];
- // support the EventListener interface
- if (listener.handleEvent) {
- var result = listener.handleEvent(event);
- } else {
- result = listener.call(this, event);
- }
- if (result === false || event.returnValue === false) returnValue =
false;
- }
+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;
}
- return returnValue;
};
//
=========================================================================
-// DOM/events/DocumentEvent.js
+// JavaScript/package.js
//
=========================================================================
-// http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-DocumentEvent
-
-var DocumentEvent = Interface.extend({
- "@!(document.createEvent)": {
- createEvent: function(document, type) {
- return Event.bind({});
- },
-
- "@(document.createEventObject)": {
- createEvent: function(document, type) {
- return Event.bind(document.createEventObject());
- }
- }
- },
+var JavaScript = {
+ name: "JavaScript",
+ version: base2.version,
+ exports: "Array2,Date2,Function2,String2",
+ namespace: "", // fixed later
- "@(document.createEvent)": {
- "@!(document.createEvent('Events'))": { // before Safari 3
- createEvent: function(document, type) {
- return this.base(document, type == "Events" ? "UIEvents" : type);
- }
- }
+ 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;
}
-});
+};
-//
=========================================================================
-// DOM/events/DOMContentLoadedEvent.js
-//
=========================================================================
+function _createObject2(Native, constructor, generics, extensions) {
+ // Clone native objects and extend them.
-// http://dean.edwards.name/weblog/2006/06/again
+ // 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);
-var DOMContentLoadedEvent = Base.extend({
- constructor: function(document) {
- var fired = false;
- this.fire = function() {
- if (!fired) {
- fired = true;
- // this function will be called from another event handler so
we'll user a timer
- // to drop out of any current event
- setTimeout(function() {
- var event = DocumentEvent.createEvent(document, "Events");
- Event.initEvent(event, "DOMContentLoaded", false, false);
- EventTarget.dispatchEvent(document, event);
- }, 1);
- }
- };
- // use the real event for browsers that support it (opera & firefox)
- EventTarget.addEventListener(document, "DOMContentLoaded", function() {
- fired = true;
- }, false);
- this.listen(document);
- },
-
- listen: function(document) {
- // if all else fails fall back on window.onload
-
EventTarget.addEventListener(Traversal.getDefaultView(document), "load",
this.fire, false);
- },
-
- "@MSIE.+win": {
- listen: function(document) {
- if (document.readyState != "complete") {
- // Matthias Miller/Mark Wubben/Paul Sowden/Me
- var event = this;
- document.write("<script id=__ready defer src=//:><\/script>");
- document.all.__ready.onreadystatechange = function() {
- if (this.readyState == "complete") {
- this.removeNode(); // tidy
- event.fire();
- }
- };
- }
- }
- },
-
- "@KHTML": {
- listen: function(document) {
- // John Resig
- if (document.readyState != "complete") {
- var event = this;
- var timer = setInterval(function() {
- if (/loaded|complete/.test(document.readyState)) {
- clearInterval(timer);
- event.fire();
- }
- }, 100);
- }
+ // 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]) {
+ INative[name] = Native[name];
+ delete INative.prototype[name];
}
+ Native2[name] = INative[name];
}
-});
-
-new DOMContentLoadedEvent(document);
+ Native2.ancestor = Object;
+ delete Native2.extend;
+
+ // remove "lang.bind.."
+ Native2.namespace = Native2.namespace.replace(/(var
(\w+)=)[^,;]+,([^\)]+)\)/g, "$1$3.$2");
+
+ return Native2;
+};
//
=========================================================================
-// DOM/events/implementations.js
+// JavaScript/~/Date.js
//
=========================================================================
-Document.implement(DocumentEvent);
-Document.implement(EventTarget);
-
-Element.implement(EventTarget);
-
-//
=========================================================================
-// DOM/style/ViewCSS.js
-//
=========================================================================
+// Fix Date.get/setYear() (IE5-7)
-// http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-ViewCSS
+if ((new Date).getYear() > 1900) {
+ Date.prototype.getYear = function() {
+ return this.getFullYear() - 1900;
+ };
+ Date.prototype.setYear = function(year) {
+ return this.setFullYear(year + 1900);
+ };
+}
-var _PIXEL = /^\d+(px)?$/i;
-var _METRICS = /(width|height|top|bottom|left|right|fontSize)$/;
-var _COLOR = /^(color|backgroundColor)$/;
+// https://bugs.webkit.org/show_bug.cgi?id=9532
-var ViewCSS = Interface.extend({
- "@!(document.defaultView.getComputedStyle)": {
- "@MSIE": {
- getComputedStyle: function(view, element, pseudoElement) {
- // pseudoElement parameter is not supported
- var currentStyle = element.currentStyle;
- var computedStyle = {};
- for (var i in currentStyle) {
- if (_METRICS.test(i)) {
- computedStyle[i] = _MSIE_getPixelValue(element,
computedStyle[i]) + "px";
- } else if (_COLOR.test(i)) {
- computedStyle[i] = _MSIE_getColorValue(element, i
== "color" ? "ForeColor" : "BackColor");
- } else {
- computedStyle[i] = currentStyle[i];
- }
- }
- return computedStyle;
+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);
}
- }
- },
-
- getComputedStyle: function(view, element, pseudoElement) {
- return _CSSStyleDeclaration_ReadOnly.bind(this.base(view, element,
pseudoElement));
- }
-}, {
- toCamelCase: function(string) {
- return string.replace(/\-([a-z])/g, function(match, chr) {
- return chr.toUpperCase();
+ return value;
});
- }
-});
-
-function _MSIE_getPixelValue(element, value) {
- if (_PIXEL.test(value)) return parseInt(value);
- var styleLeft = element.style.left;
- var runtimeStyleLeft = element.runtimeStyle.left;
- element.runtimeStyle.left = element.currentStyle.left;
- element.style.left = value || 0;
- value = element.style.pixelLeft;
- element.style.left = styleLeft;
- element.runtimeStyle.left = runtimeStyleLeft;
- return value;
-};
-
-function _MSIE_getColorValue(element, value) {
- var range = element.document.body.createTextRange();
- range.moveToElementText(element);
- var color = range.queryCommandValue(value);
- return format("rgb(%1,%2,%3)", color & 0xff, (color & 0xff00) >> 8,
(color & 0xff0000) >> 16);
-};
+ });
+}
//
=========================================================================
-// DOM/style/CSSStyleDeclaration.js
+// JavaScript/~/Function.js
//
=========================================================================
-// http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration
+// Some browsers don't define this.
-var _CSSStyleDeclaration_ReadOnly = Binding.extend({
- getPropertyValue: function(style, propertyName) {
- return this.base(style, _CSSPropertyNameMap[propertyName] ||
propertyName);
- },
-
- "@MSIE.+win": {
- getPropertyValue: function(style, propertyName) {
- return propertyName == "float" ? style.styleFloat :
style[ViewCSS.toCamelCase(propertyName)];
- }
- }
-});
+Function.prototype.prototype = {};
-var CSSStyleDeclaration = _CSSStyleDeclaration_ReadOnly.extend({
- setProperty: function(style, propertyName, value, important) {
- return this.base(style, _CSSPropertyNameMap[propertyName] ||
propertyName, value, important);
- },
-
- "@MSIE.+win": {
- setProperty: function(style, propertyName, value, priority) {
- if (propertyName == "opacity") {
- value *= 100;
- style.opacity = value;
- style.zoom = 1;
- style.filter = "Alpha(opacity=" + value + ")";
- } else {
- style.setAttribute(propertyName, value);
- }
- }
- }
-}, {
- "@MSIE": {
- bind: function(style) {
- style.getPropertyValue = this.prototype.getPropertyValue;
- style.setProperty = this.prototype.setProperty;
- return style;
- }
- }
-});
+//
=========================================================================
+// JavaScript/~/String.js
+//
=========================================================================
-var _CSSPropertyNameMap = new Base({
- "@Gecko": {
- opacity: "-moz-opacity"
- },
-
- "@KHTML": {
- opacity: "-khtml-opacity"
- }
-});
+// A KHTML bug.
-with (CSSStyleDeclaration.prototype) getPropertyValue.toString =
setProperty.toString = function() {
- return "[base2]";
-};
+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);
+ });
+}
//
=========================================================================
-// DOM/style/implementations.js
+// JavaScript/Array2.js
//
=========================================================================
-AbstractView.implement(ViewCSS);
+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;
+ }, {});
+ },
-//
=========================================================================
-// DOM/selectors-api/NodeSelector.js
-//
=========================================================================
+ contains: function(array, item) {
+ return Array2.indexOf(array, item) != -1;
+ },
-// http://www.w3.org/TR/selectors-api/
+ copy: function(array) {
+ var copy = _slice.call(array);
+ if (!copy.swap) Array2(copy); // cast to Array2
+ return copy;
+ },
-var NodeSelector = Interface.extend({
- "@!(element.querySelector)": { // future-proof
- querySelector: function(node, selector) {
- return new Selector(selector).exec(node, 1);
+ 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];
},
- querySelectorAll: function(node, selector) {
- return new Selector(selector).exec(node);
+ 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;
}
}
-});
+);
-// automatically bind objects retrieved using the Selectors API
+Array2.reduce = Enumerable.reduce; // Mozilla does not implement the
thisObj argument
-extend(NodeSelector.prototype, {
- querySelector: function(selector) {
- return DOM.bind(this.base(selector));
- },
+Array2.like = function(object) {
+ // is the object like an array?
+ return typeOf(object) == "object" && typeof object.length == "number";
+};
- querySelectorAll: function(selector) {
- return extend(this.base(selector), "item", function(index) {
- return DOM.bind(this.base(index));
- });
- }
-});
+// introspection (removed when packed)
+;;; Enumerable["#implemented_by"].pop();
+;;; Enumerable["#implemented_by"].push(Array2);
//
=========================================================================
-// DOM/selectors-api/DocumentSelector.js
+// JavaScript/Date2.js
//
=========================================================================
-// http://www.w3.org/TR/selectors-api/#documentselector
+// http://developer.mozilla.org/es4/proposals/date_and_time.html
-var DocumentSelector = NodeSelector.extend();
+// 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
+};
-//
=========================================================================
-// DOM/selectors-api/ElementSelector.js
-//
=========================================================================
+var _TRIM_ZEROES = /(((00)?:0+)?:0+)?\.0+$/;
+var _TRIM_TIMEZONE = /(T[0-9:.]+)$/;
-var ElementSelector = NodeSelector.extend({
- "@!(element.matchesSelector)": { // future-proof
- matchesSelector: function(element, selector) {
- return new Selector(selector).test(element);
+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");
}
}
-});
-
-//
=========================================================================
-// DOM/selectors-api/StaticNodeList.js
-//
=========================================================================
+);
-// http://www.w3.org/TR/selectors-api/#staticnodelist
+delete Date2.forEach;
-// A wrapper for an array of elements or an XPathResult.
-// The item() method provides access to elements.
-// Implements Enumerable so you can forEach() to your heart's
content... :-)
+Date2.now = function() {
+ return (new Date).valueOf(); // milliseconds since the epoch
+};
-var StaticNodeList = Base.extend({
- constructor: function(nodes) {
- nodes = nodes || [];
- this.length = nodes.length;
- this.item = function(index) {
- return nodes[index];
- };
- },
-
- length: 0,
-
- forEach: function(block, context) {
- for (var i = 0; i < this.length; i++) {
- block.call(context, this.item(i), i, this);
- }
- },
-
- item: Undefined, // defined in the constructor function
-
- "@(XPathResult)": {
- constructor: function(nodes) {
- //- if (nodes instanceof XPathResult) { // doesn't work in Safari
- if (nodes && nodes.snapshotItem) {
- this.length = nodes.snapshotLength;
- this.item = function(index) {
- return nodes.snapshotItem(index);
- };
- } else this.base(nodes);
+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);
}
-});
-
-StaticNodeList.implement(Enumerable);
+};
//
=========================================================================
-// DOM/selectors-api/CSSParser.js
+// JavaScript/String2.js
//
=========================================================================
-var _CSS_ESCAPE = /'(\\.|[^'\\])*'|"(\\.|[^"\\])*"/g,
- _CSS_IMPLIED_ASTERISK = /([\s>+~,]|[^(]\+|^)([#.:\[])/g,
- _CSS_IMPLIED_SPACE = /(^|,)([^\s>+~])/g,
- _CSS_WHITESPACE = /\s*([\s>+~(),]|^|$)\s*/g,
- _CSS_WILD_CARD = /\s\*\s/g,
- _CSS_UNESCAPE = /\x01(\d+)/g,
- _QUOTE = /'/g;
-
-var CSSParser = RegGrp.extend({
- constructor: function(items) {
- this.base(items);
- this.cache = {};
- this.sorter = new RegGrp;
- this.sorter.add(/:not\([^)]*\)/, RegGrp.IGNORE);
- this.sorter.add(/([ >](\*|[\w-]+))([^:
>+~]*)(:\w+-child(\([^)]+\))?)([^: >+~]*)/, "$1$3$6$4");
- },
-
- cache: null,
- ignoreCase: true,
-
- escape: function(selector) {
- // remove strings
- var strings = this._strings = [];
- return this.optimise(this.format(String(selector).replace(_CSS_ESCAPE,
function(string) {
- return "\x01" + strings.push(string.slice(1,
-1).replace(_QUOTE, "\\'"));
- })));
- },
-
- format: function(selector) {
- return selector
- .replace(_CSS_WHITESPACE, "$1")
- .replace(_CSS_IMPLIED_SPACE, "$1 $2")
- .replace(_CSS_IMPLIED_ASTERISK, "$1*$2");
- },
-
- optimise: function(selector) {
- // optimise wild card descendant selectors
- return this.sorter.exec(selector.replace(_CSS_WILD_CARD, ">* "));
- },
-
- parse: function(selector) {
- return this.cache[selector] ||
- (this.cache[selector] =
this.unescape(this.exec(this.escape(selector))));
+var String2 = _createObject2(
+ String,
+ function(string) {
+ return new String(arguments.length == 0 ? "" : string);
},
-
- unescape: function(selector) {
- // put string values back
- var strings = this._strings;
- return selector.replace(_CSS_UNESCAPE, function(match, index) {
- return strings[index - 1];
- });
- }
-});
-
-function _nthChild(match, args, position, last, not, and, mod, equals) {
- // ugly but it works for both CSS and XPath
- last = /last/i.test(match) ? last + "+1-" : "";
- if (!isNaN(args)) args = "0n+" + args;
- else if (args == "even") args = "2n";
- else if (args == "odd") args = "2n+1";
- args = args.split("n");
- var a = args[0] ? (args[0] == "-") ? -1 : parseInt(args[0]) : 1;
- var b = parseInt(args[1]) || 0;
- var negate = a < 0;
- if (negate) {
- a = -a;
- if (a == 1) b++;
+ "charAt,charCodeAt,concat,indexOf,lastIndexOf,match,replace,search,slice,split,substr,substring,toLowerCase,toUpperCase",
+ {
+ csv: csv,
+ format: format,
+ rescape: rescape,
+ trim: trim
}
- var query = format(a == 0 ? "%3%7" + (last +
b) : "(%4%3-%2)%6%1%70%5%4%3>=%2", a, b, position, last, and, mod, equals);
- if (negate) query = not + "(" + query + ")";
- return query;
-};
+);
-//
=========================================================================
-// DOM/selectors-api/XPathParser.js
-//
=========================================================================
+delete String2.forEach;
-// XPath parser
-// converts CSS expressions to *optimised* XPath queries
+// http://blog.stevenlevithan.com/archives/faster-trim-javascript
+function trim(string) {
+ return String(string).replace(_LTRIM, "").replace(_RTRIM, "");
+};
-// This code used to be quite readable until I added code to optimise
*-child selectors.
+function csv(string) {
+ return string ? (string + "").split(/\s*,\s*/) : [];
+};
-var XPathParser = CSSParser.extend({
- constructor: function() {
- this.base(XPathParser.rules);
- // The sorter sorts child selectors to the end because they are slow.
- // For XPath we need the child selectors to be sorted to the beginning,
- // so we reverse the sort order. That's what this line does:
- this.sorter.putAt(1, "$1$4$3$6");
- },
-
- escape: function(selector) {
- return this.base(selector).replace(/,/g, "\x02");
- },
-
- unescape: function(selector) {
- return this.base(selector
- .replace(/\[self::\*\]/g, "") // remove redundant wild cards
- .replace(/(^|\x02)\//g, "$1./") // context
- .replace(/\x02/g, " | ") // put commas back
- ).replace(/'[^'\\]*\\'(\\.|[^'\\])*'/g, function(match) { // escape
single quotes
- return "concat(" + match.split("\\'").join("',\"'\",'") + ")";
- });
- },
-
- "@opera": {
- unescape: function(selector) {
- // opera does not seem to support last() but I can't find any
- // documentation to confirm this
- return
this.base(selector.replace(/last\(\)/g, "count(preceding-sibling::*)+count(following-sibling::*)+1"));
- }
- }
-}, {
- init: function() {
- // build the prototype
- this.values.attributes[""] = "[@$1]";
- forEach (this.types, function(add, type) {
- forEach (this.values[type], add, this.rules);
- }, this);
- },
-
- optimised: {
- pseudoClasses: {
- "first-child": "[1]",
- "last-child": "[last()]",
- "only-child": "[last()=1]"
- }
- },
-
- rules: extend({}, {
- "@!KHTML": { // these optimisations do not work on Safari
- // fast id() search
- "(^|\\x02) (\\*|[\\w-]+)#([\\w-]+)": "$1id('$3')[self::$2]",
- // optimise positional searches
- "([ >])(\\*|[\\w-]+):([\\w-]+-child(\\(([^)]+)\\))?)":
function(match, token, tagName, pseudoClass, $4, args) {
- var replacement = (token == " ") ? "//*" : "/*";
- if (/^nth/i.test(pseudoClass)) {
- replacement += _xpath_nthChild(pseudoClass, args, "position()");
- } else {
- replacement += XPathParser.optimised.pseudoClasses[pseudoClass];
- }
- return replacement + "[self::" + tagName + "]";
- }
- }
- }),
-
- types: {
- identifiers: function(replacement, token) {
- this[rescape(token) + "([\\w-]+)"] = replacement;
- },
-
- combinators: function(replacement, combinator) {
- this[rescape(combinator) + "(\\*|[\\w-]+)"] = replacement;
- },
-
- attributes: function(replacement, operator) {
- this["\\[([\\w-]+)\\s*" + rescape(operator) + "\\s*([^\\]]*)\\]"] =
replacement;
- },
-
- pseudoClasses: function(replacement, pseudoClass) {
- this[":" + pseudoClass.replace(/\(\)$/, "\\(([^)]+)\\)")] =
replacement;
- }
- },
-
- values: {
- identifiers: {
- "#": "[@id='$1'][1]", // ID selector
- ".": "[contains(concat(' ',@class,' '),' $1 ')]" // class selector
- },
-
- combinators: {
- " ": "/descendant::$1", // descendant selector
- ">": "/child::$1", // child selector
- "+": "/following-sibling::*[1][self::$1]", // direct adjacent
selector
- "~": "/following-sibling::$1" // indirect adjacent selector
- },
-
- attributes: { // attribute selectors
- "*=": "[contains(@$1,'$2')]",
- "^=": "[starts-with(@$1,'$2')]",
- "$=": "[substring(@$1,string-length(@$1)-string-length('$2')+1)='$2']",
- "~=": "[contains(concat(' ',@$1,' '),' $2 ')]",
- "|=": "[contains(concat('-',@$1,'-'),'-$2-')]",
- "!=": "[not(@$1='$2')]",
- "=": "[@$1='$2']"
- },
-
- pseudoClasses: { // pseudo class selectors
- "empty": "[not(child::*) and not(text())]",
-//- "lang()": "[boolean(lang('$1') or
boolean(ancestor-or-self::*[@lang][1][starts-with(@lang,'$1')]))]",
- "first-child": "[not(preceding-sibling::*)]",
- "last-child": "[not(following-sibling::*)]",
- "not()": _xpath_not,
- "nth-child()": _xpath_nthChild,
- "nth-last-child()": _xpath_nthChild,
- "only-child": "[not(preceding-sibling::*) and
not(following-sibling::*)]",
- "root": "[not(parent::*)]"
- }
- },
-
- "@opera": {
- init: function() {
- this.optimised.pseudoClasses["last-child"] =
this.values.pseudoClasses["last-child"];
- this.optimised.pseudoClasses["only-child"] =
this.values.pseudoClasses["only-child"];
- this.base();
- }
- }
-});
+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];
+ });
+};
-// these functions defined here to make the code more readable
-var _notParser = new XPathParser;
-function _xpath_not(match, args) {
- return "[not(" + _notParser.exec(trim(args))
- .replace(/\[1\]/g, "") // remove the "[1]" introduced by ID selectors
- .replace(/^(\*|[\w-]+)/, "[self::$1]") // tagName test
- .replace(/\]\[/g, " and ") // merge predicates
- .slice(1, -1)
- + ")]";
+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 _xpath_nthChild(match, args, position) {
- return "[" + _nthChild(match, args, position |
| "count(preceding-sibling::*)+1", "last()", "not", " and ", " mod ", "=")
+ "]";
+function rescape(string) {
+ // Make a string safe for creating a RegExp.
+ return (string + "").replace(_RESCAPE, "\\$1");
};
//
=========================================================================
-// DOM/selectors-api/Selector.js
+// JavaScript/Function2.js
//
=========================================================================
-// This object can be instantiated, however it is probably better to use
-// the querySelector/querySelectorAll methods on DOM nodes.
-
-// There is no public standard for this object.
-
-var Selector = Base.extend({
- constructor: function(selector) {
- this.toString = K(trim(selector));
- },
-
- exec: function(context, single) {
- return Selector.parse(this)(context, single);
- },
-
- test: function(element) {
- //-dean: improve this for simple selectors
- var selector = new Selector(this + "[b2-test]");
- element.setAttribute("b2-test", true);
- var result = selector.exec(Traversal.getOwnerDocument(element), true);
- element.removeAttribute("b2-test");
- return result == element;
- },
-
- toXPath: function() {
- return Selector.toXPath(this);
- },
-
- "@(XPathResult)": {
- exec: function(context, single) {
- // use DOM methods if the XPath engine can't be used
- if (_NOT_XPATH.test(this)) {
- return this.base(context, single);
- }
- var document = Traversal.getDocument(context);
- var type = single
- ? 9 /* FIRST_ORDERED_NODE_TYPE */
- : 7 /* ORDERED_NODE_SNAPSHOT_TYPE */;
- var result = document.evaluate(this.toXPath(), context, null, type,
null);
- return single ? result.singleNodeValue : result;
- }
- },
-
- "@MSIE": {
- exec: function(context, single) {
- if (typeof context.selectNodes != "undefined"
&& !_NOT_XPATH.test(this)) { // xml
- var method = single ? "selectSingleNode" : "selectNodes";
- return context[method](this.toXPath());
- }
- return this.base(context, single);
- }
- },
-
- "@(true)": {
- exec: function(context, single) {
- try {
- var result = this.base(context || document, single);
- } catch (error) { // probably an invalid selector =)
- throw new SyntaxError(format("'%1' is not a valid CSS selector.",
this));
- }
- return single ? result : new StaticNodeList(result);
- }
+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
}
-}, {
- toXPath: function(selector) {
- if (!_xpathParser) _xpathParser = new XPathParser;
- return _xpathParser.parse(selector);
- }
-});
+);
-var _NOT_XPATH = ":(checked|disabled|enabled|contains)|
^(#[\\w-]+\\s*)?\\w+$";
-if (detect("KHTML")) {
- if (detect("WebKit5")) {
- _NOT_XPATH += "|nth\\-|,";
- } else {
- _NOT_XPATH = ".";
- }
-}
-_NOT_XPATH = new RegExp(_NOT_XPATH);
+function I(i) { // return first argument
+ return i;
+};
-// Selector.parse() - converts CSS selectors to DOM queries.
+function II(i, ii) { // return second argument
+ return ii;
+};
-// Hideous code but it produces fast DOM queries.
-// Respect due to Alex Russell and Jack Slocum for inspiration.
+function K(k) {
+ return function() {
+ return k;
+ };
+};
-var _OPERATORS = {
- "=": "%1=='%2'",
- "!=": "%1!='%2'", // not standard but other libraries support it
- "~=": /(^| )%1( |$)/,
- "|=": /^%1(-|$)/,
- "^=": /^%1/,
- "$=": /%1$/,
- "*=": /%1/
-};
-_OPERATORS[""] = "%1!=null";
-
-var _PSEUDO_CLASSES = { //-dean: lang()
- "checked": "e%1.checked",
- "contains": "e%1[TEXT].indexOf('%2')!=-1",
- "disabled": "e%1.disabled",
- "empty": "Traversal.isEmpty(e%1)",
- "enabled": "e%1.disabled===false",
- "first-child": "!Traversal.getPreviousElementSibling(e%1)",
- "last-child": "!Traversal.getNextElementSibling(e%1)",
- "only-child": "!Traversal.getPreviousElementSibling(e%1)&&!Traversal.getNextElementSibling(e%1)",
- "root": "e%1==Traversal.getDocument(e%1).documentElement"
-};
-
-var _INDEXED = detect("(element.sourceIndex)") ;
-var _VAR = "var p%2=0,i%2,e%2,n%2=e%1.";
-var _ID = _INDEXED ? "e%1.sourceIndex" : "assignID(e%1)";
-var _TEST = "var g=" + _ID + ";if(!p[g]){p[g]=1;";
-var _STORE = "r[r.length]=e%1;if(s)return e%1;";
-//var _SORT = "r.sort(sorter);";
-var _FN = "var _selectorFunction=function(e0,s){_indexed++;var
r=[],p={},reg=[%1]," +
- "d=Traversal.getDocument(e0),c=d.body?'toUpperCase':'toString';";
-
-var _xpathParser;
-
-//var sorter = _INDEXED ? function(a, b) {
-// return a.sourceIndex - b.sourceIndex;
-//} : Node.compareDocumentPosition;
-
-// variables used by the parser
-
-var _reg; // a store for RexExp objects
-var _index;
-var _wild; // need to flag certain _wild card selectors as _MSIE includes
comment nodes
-var _list; // are we processing a node _list?
-var _duplicate; // possible duplicates?
-var _cache = {}; // store parsed selectors
-
-// a hideous parser
-var _parser = new CSSParser({
- "^ \\*:root": function(match) { // :root pseudo class
- _wild = false;
- var replacement
= "e%2=d.documentElement;if(Traversal.contains(e%1,e%2)){";
- return format(replacement, _index++, _index);
- },
-
- " (\\*|[\\w-]+)#([\\w-]+)": function(match, tagName, id) { // descendant
selector followed by ID
- _wild = false;
- var replacement = "var e%2=_byId(d,'%4');if(e%2&&";
- if (tagName != "*") replacement += "e%2.nodeName=='%3'[c]()&&";
- replacement += "Traversal.contains(e%1,e%2)){";
- if (_list) replacement += format("i%1=n%1.length;", _list);
- return format(replacement, _index++, _index, tagName, id);
- },
-
- " (\\*|[\\w-]+)": function(match, tagName) { // descendant selector
- _duplicate++; // this selector may produce duplicates
- _wild = tagName == "*";
- var replacement = _VAR;
- // IE5.x does not support getElementsByTagName("*");
- replacement += (_wild &&
_MSIE5) ? "all" : "getElementsByTagName('%3')";
- replacement += ";for(i%2=0;(e%2=n%2[i%2]);i%2++){";
- return format(replacement, _index++, _list = _index, tagName);
- },
-
- ">(\\*|[\\w-]+)": function(match, tagName) { // child selector
- var children = _MSIE && _list;
- _wild = tagName == "*";
- var replacement = _VAR;
- // use the children property for _MSIE as it does not contain text
nodes
- // (but the children collection still includes comments).
- // the document object does not have a children collection
- replacement += children ? "children": "childNodes";
- if (!_wild && children) replacement += ".tags('%3')";
- replacement += ";for(i%2=0;(e%2=n%2[i%2]);i%2++){";
- if (_wild) {
- replacement += "if(e%2.nodeType==1){";
- _wild = _MSIE5;
- } else {
- if (!children) replacement += "if(e%2.nodeName=='%3'[c]()){";
- }
- return format(replacement, _index++, _list = _index, tagName);
- },
-
- "\\+(\\*|[\\w-]+)": function(match, tagName) { // direct adjacent
selector
- var replacement = "";
- if (_wild && _MSIE) replacement += "if(e%1.nodeName!='!'){";
- _wild = false;
- replacement += "e%1=Traversal.getNextElementSibling(e%1);if(e%1";
- if (tagName != "*") replacement += "&&e%1.nodeName=='%2'[c]()";
- replacement += "){";
- return format(replacement, _index, tagName);
- },
-
- "~(\\*|[\\w-]+)": function(match, tagName) { // indirect adjacent
selector
- var replacement = "";
- if (_wild && _MSIE) replacement += "if(e%1.nodeName!='!'){";
- _wild = false;
- _duplicate = 2; // this selector may produce duplicates
- replacement
+= "while(e%1=e%1.nextSibling){if(e%1.b2_adjacent==_indexed)break;if(";
- if (tagName == "*") {
- replacement += "e%1.nodeType==1";
- if (_MSIE5) replacement += "&&e%1.nodeName!='!'";
- } else replacement += "e%1.nodeName=='%2'[c]()";
- replacement += "){e%1.b2_adjacent=_indexed;";
- return format(replacement, _index, tagName);
- },
-
- "#([\\w-]+)": function(match, id) { // ID selector
- _wild = false;
- var replacement = "if(e%1.id=='%2'){";
- if (_list) replacement += format("i%1=n%1.length;", _list);
- return format(replacement, _index, id);
- },
-
- "\\.([\\w-]+)": function(match, className) { // class selector
- _wild = false;
- // store RegExp objects - slightly faster on IE
- _reg.push(new RegExp("(^|\\s)" + rescape(className) + "(\\s|$)"));
- return format("if(e%1.className&®[%2].test(e%1.className)){",
_index, _reg.length - 1);
- },
-
- ":not\\((\\*|[\\w-]+)?([^)]*)\\)": function(match, tagName, filters) {
// :not pseudo class
- var replacement = (tagName && tagName != "*") ?
format("if(e%1.nodeName=='%2'[c]()){", _index, tagName) : "";
- replacement += _parser.exec(filters);
- return "if(!" + replacement.slice(2, -1).replace(/\)\{if\(/g, "&&")
+ "){";
- },
-
- ":nth(-last)?-child\\(([^)]+)\\)": function(match, last, args) {
// :nth-child pseudo classes
- _wild = false;
- last = format("e%1.parentNode.b2_length", _index);
- var replacement
= "if(p%1!==e%1.parentNode)p%1=_register(e%1.parentNode);";
- replacement += "var
i=e%1[p%1.b2_lookup];if(p%1.b2_lookup!='b2_index')i++;if(";
- return format(replacement, _index) + _nthChild(match, args, "i",
last, "!", "&&", "%", "==") + "){";
- },
-
- ":([\\w-]+)(\\(([^)]+)\\))?": function(match, pseudoClass, $2, args) {
// other pseudo class selectors
- return "if(" + format(_PSEUDO_CLASSES[pseudoClass] || "throw", _index,
args || "") + "){";
- },
-
- "\\[([\\w-]+)\\s*([^=]?=)?\\s*([^\\]]*)\\]": function(match, attr,
operator, value) { // attribute selectors
- var alias = _ATTRIBUTES[attr] || attr;
- if (operator) {
- var getAttribute = "e%1.getAttribute('%2',2)";
- if (!_EVALUATED.test(attr)) {
- getAttribute = "e%1.%3||" + getAttribute;
- }
- attr = format("(" + getAttribute + ")", _index, attr, alias);
- } else {
- attr = format("Element.getAttribute(e%1,'%2')", _index, attr);
- }
- var replacement = _OPERATORS[operator || ""];
- if (instanceOf(replacement, RegExp)) {
- _reg.push(new RegExp(format(replacement.source,
rescape(_parser.unescape(value)))));
- replacement = "reg[%2].test(%1)";
- value = _reg.length - 1;
- }
- return "if(" + format(replacement, attr, value) + "){";
+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);
+ };
}
-});
+};
-new function(_) {
- // IE confuses the name attribute with id for form elements,
- // use document.all to retrieve all elements with name/id instead
- var _byId = _MSIE ? function(document, id) {
- var result = document.all[id] || null;
- // returns a single element or a collection
- if (!result || result.id == id) return result;
- // document.all has returned a collection of elements with name/id
- for (var i = 0; i < result.length; i++) {
- if (result[i].id == id) return result[i];
- }
- return null;
- } : function(document, id) {
- return document.getElementById(id);
+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;
};
+};
- // register a node and index its children
- var _indexed = 1;
- function _register(element) {
- if (element.rows) {
- element.b2_length = element.rows.length;
- element.b2_lookup = "rowIndex";
- } else if (element.cells) {
- element.b2_length = element.cells.length;
- element.b2_lookup = "cellIndex";
- } else if (element.b2_indexed != _indexed) {
- var index = 0;
- var child = element.firstChild;
- while (child) {
- if (child.nodeType == 1 && child.nodeName != "!") {
- child.b2_index = ++index;
- }
- child = child.nextSibling;
- }
- element.b2_length = index;
- element.b2_lookup = "b2_index";
- }
- element.b2_indexed = _indexed;
- return element;
+function delegate(fn, context) {
+ return function() {
+ var args = _slice.call(arguments);
+ args.unshift(this);
+ return fn.apply(context, args);
};
-
- Selector.parse = function(selector) {
- if (!_cache[selector]) {
- _reg = []; // store for RegExp objects
- var fn = "";
- var selectors = _parser.escape(selector).split(",");
- for (var i = 0; i < selectors.length; i++) {
- _wild = _index = _list = 0; // reset
- _duplicate = selectors.length > 1 ? 2 : 0; // reset
- var block = _parser.exec(selectors[i]) || "throw;";
- if (_wild && _MSIE) { // IE's pesky comment nodes
- block += format("if(e%1.nodeName!='!'){", _index);
- }
- // check for duplicates before storing results
- var store = (_duplicate > 1) ? _TEST : "";
- block += format(store + _STORE, _index);
- // add closing braces
- block += Array(match(block, /\{/g).length + 1).join("}");
- fn += block;
- }
-// if (selectors.length > 1) fn += _SORT;
- eval(format(_FN, _reg) + _parser.unescape(fn) + "return s?null:r}");
- _cache[selector] = _selectorFunction;
- }
- return _cache[selector];
+};
+
+function flip(fn) {
+ return function() {
+ return fn.apply(this, Array2.swap(arguments, 0, 1));
};
};
-//
=========================================================================
-// DOM/selectors-api/implementations.js
-//
=========================================================================
+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);
+ };
+};
-Document.implement(DocumentSelector);
-Element.implement(ElementSelector);
+function unbind(fn) {
+ return function(context) {
+ return fn.apply(context, _slice.call(arguments, 1));
+ };
+};
//
=========================================================================
-// DOM/html/HTMLDocument.js
+// base2/detect.js
//
=========================================================================
-// http://www.whatwg.org/specs/web-apps/current-work/#htmldocument
-
-var HTMLDocument = Document.extend(null, {
- // http://www.whatwg.org/specs/web-apps/current-work/#activeelement
- "@(document.activeElement===undefined)": {
- bind: function(document) {
- document.activeElement = null;
- EventTarget.addEventListener(document, "focus", function(event) {
//-dean: is onfocus good enough?
- document.activeElement = event.target;
- }, false);
- return this.base(document);
+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]);
+};
//
=========================================================================
-// DOM/html/HTMLElement.js
+// base2/init.js
//
=========================================================================
-// The className methods are not standard but are extremely handy. :-)
-
-var HTMLElement = Element.extend({
- addClass: function(element, className) {
- if (!this.hasClass(element, className)) {
- element.className += (element.className ? " " : "") + className;
- }
- },
-
- hasClass: function(element, className) {
- var regexp = new RegExp("(^|\\s)" + className + "(\\s|$)");
- return regexp.test(element.className);
- },
-
- removeClass: function(element, className) {
- var regexp = new RegExp("(^|\\s)" + className + "(\\s|$)", "g");
- element.className = trim(element.className.replace(regexp, "$2"));
- },
+base2 = global.base2 = new Package(this, base2);
+var exports = this.exports;
- toggleClass: function(element, className) {
- if (this.hasClass(element, className)) {
- this.removeClass(element, className);
- } else {
- this.addClass(element, className);
- }
- }
-}, {
- bindings: {},
- tags: "*",
-
- bind: function(element) {
- CSSStyleDeclaration.bind(element.style);
- return this.base(element);
- },
-
- extend: function() {
- // Maintain HTML element bindings.
- // This allows us to map specific interfaces to elements by reference
- // to tag name.
- var binding = base(this, arguments);
- var tags = (binding.tags || "").toUpperCase().split(",");
- forEach (tags, function(tagName) {
- HTMLElement.bindings[tagName] = binding;
- });
- return binding;
- },
-
- "@!(element.ownerDocument)": {
- bind: function(element) {
- element.ownerDocument = Traversal.getOwnerDocument(element);
- return this.base(element);
- }
- }
-});
+lang = new Package(this, lang);
+exports += this.exports;
-HTMLElement.extend(null, {
- tags: "APPLET,EMBED",
- bind: I // Binding not allowed for these elements.
-});
+JavaScript = new Package(this, JavaScript);
+eval(exports + this.exports);
-eval(this.exports);
+lang.base = base;
+lang.extend = extend;
}; //////////////////// END: CLOSURE
/////////////////////////////////////