Updated build to packer3
This commit is contained in:
parent
5fae496933
commit
0539495e86
5 changed files with 1255 additions and 3 deletions
|
@ -1,5 +1,18 @@
|
||||||
load("build/js/ParseMaster.js", "build/js/pack.js", "build/js/writeFile.js");
|
load("build/js/writeFile.js");
|
||||||
|
load("build/js/base2.js");
|
||||||
|
load("build/js/Packer.js");
|
||||||
|
load("build/js/Words.js");
|
||||||
|
|
||||||
var out = readFile( arguments[0] );
|
// arguments
|
||||||
|
var inFile = arguments[0];
|
||||||
|
var outFile = arguments[1] || inFile.replace(/\.js$/, "-p.js");
|
||||||
|
|
||||||
writeFile( arguments[1], pack( out, 62, true, false ) );
|
// options
|
||||||
|
var base62 = true;
|
||||||
|
var shrink = true;
|
||||||
|
|
||||||
|
var script = readFile(inFile);
|
||||||
|
var packer = new Packer;
|
||||||
|
var packedScript = packer.pack(script, base62, shrink);
|
||||||
|
|
||||||
|
writeFile(outFile, packedScript);
|
||||||
|
|
BIN
build/js.jar
BIN
build/js.jar
Binary file not shown.
205
build/js/Packer.js
Normal file
205
build/js/Packer.js
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
/*
|
||||||
|
Packer version 3.0 (beta 5) - copyright 2004-2007, Dean Edwards
|
||||||
|
http://www.opensource.org/licenses/mit-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
eval(base2.namespace);
|
||||||
|
|
||||||
|
var IGNORE = RegGrp.IGNORE;
|
||||||
|
var REMOVE = "";
|
||||||
|
var SPACE = " ";
|
||||||
|
var WORDS = /\w+/g;
|
||||||
|
|
||||||
|
var Packer = Base.extend({
|
||||||
|
minify: function(script) {
|
||||||
|
script = script.replace(Packer.CONTINUE, "");
|
||||||
|
script = Packer.clean.exec(script);
|
||||||
|
script = Packer.whitespace.exec(script);
|
||||||
|
script = Packer.clean.exec(script); // seem to grab a few more bytes on the second pass
|
||||||
|
return script;
|
||||||
|
},
|
||||||
|
|
||||||
|
pack: function(script, base62, shrink) {
|
||||||
|
script = this.minify(script);
|
||||||
|
if (shrink) script = this._shrinkVariables(script);
|
||||||
|
if (base62) script = this._base62Encode(script);
|
||||||
|
return script;
|
||||||
|
},
|
||||||
|
|
||||||
|
_base62Encode: function(script) {
|
||||||
|
var words = new Words(script);
|
||||||
|
var encode = function(word) {
|
||||||
|
return words.fetch(word).encoded;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* build the packed script */
|
||||||
|
|
||||||
|
var p = this._escape(script.replace(WORDS, encode));
|
||||||
|
var a = Math.min(Math.max(words.count(), 2), 62);
|
||||||
|
var c = words.count();
|
||||||
|
var k = words;
|
||||||
|
var e = Packer["ENCODE" + (a > 10 ? a > 36 ? 62 : 36 : 10)];
|
||||||
|
var r = a > 10 ? "e(c)" : "c";
|
||||||
|
|
||||||
|
// the whole thing
|
||||||
|
return format(Packer.UNPACK, p,a,c,k,e,r);
|
||||||
|
},
|
||||||
|
|
||||||
|
_escape: function(script) {
|
||||||
|
// single quotes wrap the final string so escape them
|
||||||
|
// also escape new lines required by conditional comments
|
||||||
|
return script.replace(/([\\'])/g, "\\$1").replace(/[\r\n]+/g, "\\n");
|
||||||
|
},
|
||||||
|
|
||||||
|
_shrinkVariables: function(script) {
|
||||||
|
// Windows Scripting Host cannot do regexp.test() on global regexps.
|
||||||
|
var global = function(regexp) {
|
||||||
|
// This function creates a global version of the passed regexp.
|
||||||
|
return new RegExp(regexp.source, "g");
|
||||||
|
};
|
||||||
|
|
||||||
|
var data = []; // encoded strings and regular expressions
|
||||||
|
var store = function(string) {
|
||||||
|
var replacement = "#" + data.length;
|
||||||
|
data.push(string);
|
||||||
|
return replacement;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Base52 encoding (a-Z)
|
||||||
|
var encode52 = function(c) {
|
||||||
|
return (c < 52 ? '' : arguments.callee(parseInt(c / 52))) +
|
||||||
|
((c = c % 52) > 25 ? String.fromCharCode(c + 39) : String.fromCharCode(c + 97));
|
||||||
|
};
|
||||||
|
|
||||||
|
// identify blocks, particularly identify function blocks (which define scope)
|
||||||
|
var BLOCK = /(function\s*[\w$]*\s*\(\s*([^\)]*)\s*\)\s*)?(\{([^{}]*)\})/;
|
||||||
|
var VAR_ = /var\s+/g;
|
||||||
|
var VAR_NAME = /var\s+[\w$]{2,}/g; // > 1 char
|
||||||
|
var COMMA = /\s*,\s*/;
|
||||||
|
var blocks = []; // store program blocks (anything between braces {})
|
||||||
|
// encoder for program blocks
|
||||||
|
var encode = function(block, func, args) {
|
||||||
|
if (func) { // the block is a function block
|
||||||
|
|
||||||
|
// decode the function block (THIS IS THE IMPORTANT BIT)
|
||||||
|
// We are retrieving all sub-blocks and will re-parse them in light
|
||||||
|
// of newly shrunk variables
|
||||||
|
block = decode(block);
|
||||||
|
|
||||||
|
// create the list of variable and argument names
|
||||||
|
var vars = match(block, VAR_NAME).join(",").replace(VAR_, "");
|
||||||
|
var ids = Array2.combine(args.split(COMMA).concat(vars.split(COMMA)));
|
||||||
|
|
||||||
|
// process each identifier
|
||||||
|
var count = 0, shortId;
|
||||||
|
forEach (ids, function(id) {
|
||||||
|
id = rescape(trim(id));
|
||||||
|
if (id) {
|
||||||
|
// find the next free short name (check everything in the current scope)
|
||||||
|
do shortId = encode52(count++);
|
||||||
|
while (new RegExp("[^\\w$.]" + shortId + "[^\\w$:]").test(block));
|
||||||
|
// replace the long name with the short name
|
||||||
|
var reg = new RegExp("([^\\w$.])" + id + "([^\\w$:])");
|
||||||
|
while (reg.test(block)) block = block.replace(global(reg), "$1" + shortId + "$2");
|
||||||
|
var reg = new RegExp("([^{,])" + id + ":", "g");
|
||||||
|
block = block.replace(reg, "$1" + shortId + ":");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var replacement = "~" + blocks.length;
|
||||||
|
blocks.push(block);
|
||||||
|
return replacement;
|
||||||
|
};
|
||||||
|
|
||||||
|
// decoder for program blocks
|
||||||
|
var ENCODED = /~(\d+)/;
|
||||||
|
var decode = function(script) {
|
||||||
|
while (ENCODED.test(script)) {
|
||||||
|
script = script.replace(global(ENCODED), function(match, index) {
|
||||||
|
return blocks[index];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return script;
|
||||||
|
};
|
||||||
|
|
||||||
|
// encode strings and regular expressions
|
||||||
|
script = Packer.data.exec(script, store);
|
||||||
|
|
||||||
|
// remove closures (this is for base2 namespaces only)
|
||||||
|
script = script.replace(/new function\(_\)\s*\{/g, "{;#;");
|
||||||
|
|
||||||
|
// encode blocks, as we encode we replace variable and argument names
|
||||||
|
while (BLOCK.test(script)) {
|
||||||
|
script = script.replace(global(BLOCK), encode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// put the blocks back
|
||||||
|
script = decode(script);
|
||||||
|
|
||||||
|
// put back the closure (for base2 namespaces only)
|
||||||
|
script = script.replace(/\{;#;/g, "new function(_){");
|
||||||
|
|
||||||
|
// put strings and regular expressions back
|
||||||
|
script = script.replace(/#(\d+)/g, function(match, index) {
|
||||||
|
return data[index];
|
||||||
|
});
|
||||||
|
|
||||||
|
return script;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
CONTINUE: /\\\r?\n/g,
|
||||||
|
|
||||||
|
ENCODE10: "String",
|
||||||
|
ENCODE36: "function(c){return c.toString(a)}",
|
||||||
|
ENCODE62: "function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))}",
|
||||||
|
|
||||||
|
UNPACK: "eval(function(p,a,c,k,e,r){e=%5;if(!''.replace(/^/,String)){while(c--)r[%6]=k[c]" +
|
||||||
|
"||%6;k=[function(e){return r[e]}];e=function(){return'\\\\w+'};c=1};while(c--)if(k[c])p=p." +
|
||||||
|
"replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('%1',%2,%3,'%4'.split('|'),0,{}))",
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
this.data = reduce(this.data, new RegGrp, function(data, replacement, expression) {
|
||||||
|
data.store(this.javascript.exec(expression), replacement);
|
||||||
|
return data;
|
||||||
|
}, this);
|
||||||
|
this.clean = this.data.union(this.clean);
|
||||||
|
this.whitespace = this.data.union(this.whitespace);
|
||||||
|
},
|
||||||
|
|
||||||
|
clean: {
|
||||||
|
";;;[^\\n]*": REMOVE, // triple semi-colons treated like line comments
|
||||||
|
"\\(\\s*;\\s*;\\s*\\)": "(;;)", // for (;;) loops
|
||||||
|
"throw[^};]+[};]": IGNORE, // a safari 1.3 bug
|
||||||
|
";+\\s*([};])": "$1"
|
||||||
|
},
|
||||||
|
|
||||||
|
data: {
|
||||||
|
// strings
|
||||||
|
"STRING1": IGNORE,
|
||||||
|
'STRING2': IGNORE,
|
||||||
|
"CONDITIONAL": IGNORE, // conditional comments
|
||||||
|
"(COMMENT1)\\n\\s*(REGEXP)?": "\n$2",
|
||||||
|
"(COMMENT2)\\s*(REGEXP)?": " $3",
|
||||||
|
"COMMENT1$": REMOVE,
|
||||||
|
"([\\[(\\^=,{}:;&|!*?])\\s*(REGEXP)": "$1$2"
|
||||||
|
},
|
||||||
|
|
||||||
|
javascript: new RegGrp({
|
||||||
|
COMMENT1: /\/\/[^\n]*/.source,
|
||||||
|
COMMENT2: /\/\*[^*]*\*+([^\/][^*]*\*+)*\//.source,
|
||||||
|
CONDITIONAL: /\/\*@|@\*\/|\/\/@[^\n]*\n/.source,
|
||||||
|
REGEXP: /\/(\\\/|[^*\/])(\\.|[^\/\n\\])*\//.source,
|
||||||
|
STRING1: /'(\\.|[^'\\])*'/.source,
|
||||||
|
STRING2: /"(\\.|[^"\\])*"/.source
|
||||||
|
}),
|
||||||
|
|
||||||
|
whitespace: {
|
||||||
|
"(\\d)\\s+(\\.\\s*[a-z\\$_\\[(])": "$1 $2", // http://dean.edwards.name/weblog/2007/04/packer3/#comment84066
|
||||||
|
"([+-])\\s+([+-])": "$1 $2", // c = a++ +b;
|
||||||
|
"\\b\\s+\\$\\s+\\b": " $ ", // var $ in
|
||||||
|
"\\$\\s+\\b": "$ ", // object$ in
|
||||||
|
"\\b\\s+\\$": " $", // return $object
|
||||||
|
"\\b\\s+\\b": SPACE,
|
||||||
|
"\\s+": REMOVE
|
||||||
|
}
|
||||||
|
});
|
62
build/js/Words.js
Normal file
62
build/js/Words.js
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
|
||||||
|
var Words = Collection.extend({
|
||||||
|
constructor: function(script) {
|
||||||
|
this.base();
|
||||||
|
forEach (script.match(WORDS), this.add, this);
|
||||||
|
this.encode();
|
||||||
|
},
|
||||||
|
|
||||||
|
add: function(word) {
|
||||||
|
if (!this.exists(word)) this.base(word);
|
||||||
|
word = this.fetch(word);
|
||||||
|
word.count++;
|
||||||
|
return word;
|
||||||
|
},
|
||||||
|
|
||||||
|
encode: function() {
|
||||||
|
// sort by frequency
|
||||||
|
this.sort(function(word1, word2) {
|
||||||
|
return word2.count - word1.count;
|
||||||
|
});
|
||||||
|
|
||||||
|
eval("var a=62,e=" + Packer.ENCODE62);
|
||||||
|
var encode = e;
|
||||||
|
var encoded = new Collection; // a dictionary of base62 -> base10
|
||||||
|
var count = this.count();
|
||||||
|
for (var i = 0; i < count; i++) {
|
||||||
|
encoded.store(encode(i), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
var empty = function() {return ""};
|
||||||
|
var index = 0;
|
||||||
|
forEach (this, function(word) {
|
||||||
|
if (encoded.exists(word)) {
|
||||||
|
word.index = encoded.fetch(word);
|
||||||
|
word.toString = empty;
|
||||||
|
} else {
|
||||||
|
while (this.exists(encode(index))) index++;
|
||||||
|
word.index = index++;
|
||||||
|
}
|
||||||
|
word.encoded = encode(word.index);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
// sort by encoding
|
||||||
|
this.sort(function(word1, word2) {
|
||||||
|
return word1.index - word2.index;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
toString: function() {
|
||||||
|
return this.values().join("|");
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
Item: {
|
||||||
|
constructor: function(word) {
|
||||||
|
this.toString = function() {return word};
|
||||||
|
},
|
||||||
|
|
||||||
|
count: 0,
|
||||||
|
encoded: "",
|
||||||
|
index: -1
|
||||||
|
}
|
||||||
|
});
|
972
build/js/base2.js
Normal file
972
build/js/base2.js
Normal file
|
@ -0,0 +1,972 @@
|
||||||
|
// timestamp: Tue, 24 Apr 2007 09:57:15
|
||||||
|
/*
|
||||||
|
base2.js - copyright 2007, Dean Edwards
|
||||||
|
http://www.opensource.org/licenses/mit-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
var base2 = {};
|
||||||
|
|
||||||
|
// You know, writing a javascript library is awfully time consuming.
|
||||||
|
|
||||||
|
new function(_) { //////////////////// BEGIN: CLOSURE ////////////////////
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// base2/Base.js
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
// version 1.1
|
||||||
|
|
||||||
|
var Base = function() {
|
||||||
|
// call this method from any other method to invoke that method's ancestor
|
||||||
|
};
|
||||||
|
|
||||||
|
Base.prototype = {
|
||||||
|
extend: function(source) {
|
||||||
|
if (arguments.length > 1) { // extending with a name/value pair
|
||||||
|
var ancestor = this[source];
|
||||||
|
var value = arguments[1];
|
||||||
|
if (typeof value == "function" && ancestor && /\bbase\b/.test(value)) {
|
||||||
|
var method = value;
|
||||||
|
value = function() { // override
|
||||||
|
var previous = this.base;
|
||||||
|
this.base = ancestor;
|
||||||
|
var returnValue = method.apply(this, arguments);
|
||||||
|
this.base = previous;
|
||||||
|
return returnValue;
|
||||||
|
};
|
||||||
|
value.method = method;
|
||||||
|
value.ancestor = ancestor;
|
||||||
|
}
|
||||||
|
this[source] = value;
|
||||||
|
} else if (source) { // extending with an object literal
|
||||||
|
var extend = Base.prototype.extend;
|
||||||
|
if (Base._prototyping) {
|
||||||
|
var key, i = 0, members = ["constructor", "toString", "valueOf"];
|
||||||
|
while (key = members[i++]) if (source[key] != Object.prototype[key]) {
|
||||||
|
extend.call(this, key, source[key]);
|
||||||
|
}
|
||||||
|
} else if (typeof this != "function") {
|
||||||
|
// if the object has a customised extend() method then use it
|
||||||
|
extend = this.extend || extend;
|
||||||
|
}
|
||||||
|
// copy each of the source object's properties to this object
|
||||||
|
for (key in source) if (!Object.prototype[key]) {
|
||||||
|
extend.call(this, key, source[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
base: Base
|
||||||
|
};
|
||||||
|
|
||||||
|
Base.extend = function(_instance, _static) { // subclass
|
||||||
|
var extend = Base.prototype.extend;
|
||||||
|
|
||||||
|
// build the prototype
|
||||||
|
Base._prototyping = true;
|
||||||
|
var proto = new this;
|
||||||
|
extend.call(proto, _instance);
|
||||||
|
delete Base._prototyping;
|
||||||
|
|
||||||
|
// create the wrapper for the constructor function
|
||||||
|
var constructor = proto.constructor;
|
||||||
|
var klass = proto.constructor = function() {
|
||||||
|
if (!Base._prototyping) {
|
||||||
|
if (this._constructing || this.constructor == klass) { // instantiation
|
||||||
|
this._constructing = true;
|
||||||
|
constructor.apply(this, arguments);
|
||||||
|
delete this._constructing;
|
||||||
|
} else { // casting
|
||||||
|
var object = arguments[0];
|
||||||
|
if (object != null) {
|
||||||
|
(object.extend || extend).call(object, proto);
|
||||||
|
}
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// build the class interface
|
||||||
|
for (var i in Base) klass[i] = this[i];
|
||||||
|
klass.ancestor = this;
|
||||||
|
klass.base = Base.base;
|
||||||
|
klass.prototype = proto;
|
||||||
|
klass.toString = this.toString;
|
||||||
|
extend.call(klass, _static);
|
||||||
|
// class initialisation
|
||||||
|
if (typeof klass.init == "function") klass.init();
|
||||||
|
return klass;
|
||||||
|
};
|
||||||
|
|
||||||
|
// initialise
|
||||||
|
Base = Base.extend({
|
||||||
|
constructor: function() {
|
||||||
|
this.extend(arguments[0]);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
ancestor: Object,
|
||||||
|
base: Base,
|
||||||
|
|
||||||
|
implement: function(_interface) {
|
||||||
|
if (typeof _interface == "function") {
|
||||||
|
// if it's a function, call it
|
||||||
|
_interface(this.prototype);
|
||||||
|
} else {
|
||||||
|
// add the interface using the extend() method
|
||||||
|
this.prototype.extend(_interface);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// lang/main.js
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
var Legacy = typeof $Legacy == "undefined" ? {} : $Legacy;
|
||||||
|
|
||||||
|
var K = function(k) {return k};
|
||||||
|
|
||||||
|
var assert = function(condition, message, Err) {
|
||||||
|
if (!condition) {
|
||||||
|
throw new (Err || Error)(message || "Assertion failed.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var assertType = function(object, type, message) {
|
||||||
|
if (type) {
|
||||||
|
var condition = typeof type == "function" ? instanceOf(object, type) : typeof object == type;
|
||||||
|
assert(condition, message || "Invalid type.", TypeError);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var format = function(string) {
|
||||||
|
// replace %n with arguments[n]
|
||||||
|
// e.g. format("%1 %2%3 %2a %1%3", "she", "se", "lls");
|
||||||
|
// ==> "she sells sea shells"
|
||||||
|
// only supports nine replacements: %1 - %9
|
||||||
|
var args = arguments;
|
||||||
|
return String(string).replace(/%([1-9])/g, function(match, index) {
|
||||||
|
return index < args.length ? args[index] : match;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var $instanceOf = Legacy.instanceOf || new Function("o,k", "return o instanceof k");
|
||||||
|
var instanceOf = function(object, klass) {
|
||||||
|
assertType(klass, "function", "Invalid 'instanceOf' operand.");
|
||||||
|
if ($instanceOf(object, klass)) return true;
|
||||||
|
// handle exceptions where the target object originates from another frame
|
||||||
|
// this is handy for JSON parsing (amongst other things)
|
||||||
|
if (object != null) switch (klass) {
|
||||||
|
case Object:
|
||||||
|
return true;
|
||||||
|
case Number:
|
||||||
|
case Boolean:
|
||||||
|
case Function:
|
||||||
|
case String:
|
||||||
|
return typeof object == typeof klass.prototype.valueOf();
|
||||||
|
case Array:
|
||||||
|
// this is the only troublesome one
|
||||||
|
return !!(object.join && object.splice && !arguments.callee(object, Function));
|
||||||
|
case Date:
|
||||||
|
return !!object.getTimezoneOffset;
|
||||||
|
case RegExp:
|
||||||
|
return String(object.constructor.prototype) == String(new RegExp);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
var match = function(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) || [];
|
||||||
|
};
|
||||||
|
|
||||||
|
var RESCAPE = /([\/()[\]{}|*+-.,^$?\\])/g;
|
||||||
|
var rescape = function(string) {
|
||||||
|
// make a string safe for creating a RegExp
|
||||||
|
return String(string).replace(RESCAPE, "\\$1");
|
||||||
|
};
|
||||||
|
|
||||||
|
var $slice = Array.prototype.slice;
|
||||||
|
var slice = function(object) {
|
||||||
|
// slice an array-like object
|
||||||
|
return $slice.apply(object, $slice.call(arguments, 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
var TRIM = /^\s+|\s+$/g;
|
||||||
|
var trim = function(string) {
|
||||||
|
return String(string).replace(TRIM, "");
|
||||||
|
};
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// lang/extend.js
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
var base = function(object, args) {
|
||||||
|
// invoke the base method with all supplied arguments
|
||||||
|
return object.base.apply(object, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
var extend = function(object) {
|
||||||
|
assert(object != Object.prototype, "Object.prototype is verboten!");
|
||||||
|
return Base.prototype.extend.apply(object, slice(arguments, 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// lang/assignID.js
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
var $ID = 1;
|
||||||
|
var assignID = function(object) {
|
||||||
|
// assign a unique id
|
||||||
|
if (!object.base2ID) object.base2ID = "b2_" + $ID++;
|
||||||
|
return object.base2ID;
|
||||||
|
};
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// lang/forEach.js
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
if (typeof StopIteration == "undefined") {
|
||||||
|
StopIteration = new Error("StopIteration");
|
||||||
|
}
|
||||||
|
|
||||||
|
var forEach = function(object, block, context) {
|
||||||
|
if (object == null) return;
|
||||||
|
if (typeof object == "function") {
|
||||||
|
// functions are a special case
|
||||||
|
var 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
|
||||||
|
forEach.Array(object, block, context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
forEach.Function(fn || Object, object, block, context);
|
||||||
|
};
|
||||||
|
|
||||||
|
// these are the two core enumeration methods. all other forEach methods
|
||||||
|
// eventually call one of these two.
|
||||||
|
|
||||||
|
forEach.Array = function(array, block, context) {
|
||||||
|
var i, length = array.length; // preserve
|
||||||
|
if (typeof array == "string") {
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
block.call(context, array.charAt(i), i, array);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
block.call(context, array[i], i, array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
forEach.Function = Legacy.forEach || 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// base2/Base/forEach.js
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
Base.forEach = function(object, block, context) {
|
||||||
|
forEach.Function(this, object, block, context);
|
||||||
|
};
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// base2/../Function.js
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
// some browsers don't define this
|
||||||
|
|
||||||
|
Function.prototype.prototype = {};
|
||||||
|
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// base2/../String.js
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
// fix String.replace (Safari/IE5.0)
|
||||||
|
|
||||||
|
if ("".replace(/^/, String)) {
|
||||||
|
extend(String.prototype, "replace", function(expression, replacement) {
|
||||||
|
if (typeof replacement == "function") { // Safari doesn't like functions
|
||||||
|
if (instanceOf(expression, RegExp)) {
|
||||||
|
var regexp = expression;
|
||||||
|
var global = regexp.global;
|
||||||
|
if (global == null) global = /(g|gi)$/.test(regexp);
|
||||||
|
// we have to convert global RexpExps for exec() to work consistently
|
||||||
|
if (global) regexp = new RegExp(regexp.source); // non-global
|
||||||
|
} else {
|
||||||
|
regexp = new RegExp(rescape(expression));
|
||||||
|
}
|
||||||
|
var match, string = this, result = "";
|
||||||
|
while (string && (match = regexp.exec(string))) {
|
||||||
|
result += string.slice(0, match.index) + replacement.apply(this, match);
|
||||||
|
string = string.slice(match.index + match[0].length);
|
||||||
|
if (!global) break;
|
||||||
|
}
|
||||||
|
return result + string;
|
||||||
|
} else {
|
||||||
|
return base(this, arguments);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// base2/Abstract.js
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
var Abstract = Base.extend({
|
||||||
|
constructor: function() {
|
||||||
|
throw new TypeError("Class cannot be instantiated.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// base2/Module.js
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
// based on ruby's Module class and Mozilla's Array generics:
|
||||||
|
// http://www.ruby-doc.org/core/classes/Module.html
|
||||||
|
// http://developer.mozilla.org/en/docs/New_in_JavaScript_1.6#Array_and_String_generics
|
||||||
|
|
||||||
|
// A Module is used as the basis for creating interfaces that can be
|
||||||
|
// applied to other classes. *All* properties and methods are static.
|
||||||
|
// When a module is used as a mixin, methods defined on what would normally be
|
||||||
|
// the instance interface become instance methods of the target object.
|
||||||
|
|
||||||
|
// Modules cannot be instantiated. Static properties and methods are inherited.
|
||||||
|
|
||||||
|
var Module = Abstract.extend(null, {
|
||||||
|
extend: function(_interface, _static) {
|
||||||
|
// extend a module to create a new module
|
||||||
|
var module = this.base();
|
||||||
|
// inherit static methods
|
||||||
|
forEach (this, function(property, name) {
|
||||||
|
if (!Module[name] && name != "init") {
|
||||||
|
extend(module, name, property);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// implement module (instance AND static) methods
|
||||||
|
module.implement(_interface);
|
||||||
|
// implement static properties and methods
|
||||||
|
extend(module, _static);
|
||||||
|
// Make the submarine noises Larry!
|
||||||
|
if (typeof module.init == "function") module.init();
|
||||||
|
return module;
|
||||||
|
},
|
||||||
|
|
||||||
|
implement: function(_interface) {
|
||||||
|
// implement an interface on BOTH the instance and static interfaces
|
||||||
|
var module = this;
|
||||||
|
if (typeof _interface == "function") {
|
||||||
|
module.base(_interface);
|
||||||
|
forEach (_interface, function(property, name) {
|
||||||
|
if (!Module[name] && name != "init") {
|
||||||
|
extend(module, name, property);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// create the instance interface
|
||||||
|
Base.forEach (extend({}, _interface), function(property, name) {
|
||||||
|
// instance methods call the equivalent static method
|
||||||
|
if (typeof property == "function") {
|
||||||
|
property = function() {
|
||||||
|
base; // force inheritance
|
||||||
|
return module[name].apply(module, [this].concat(slice(arguments)));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!Module[name]) extend(this, name, property);
|
||||||
|
}, module.prototype);
|
||||||
|
// add the static interface
|
||||||
|
extend(module, _interface);
|
||||||
|
}
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// base2/Enumerable.js
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
var Enumerable = Module.extend({
|
||||||
|
every: function(object, test, context) {
|
||||||
|
var result = true;
|
||||||
|
try {
|
||||||
|
this.forEach (object, function(value, key) {
|
||||||
|
result = test.call(context, value, key, object);
|
||||||
|
if (!result) throw StopIteration;
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
if (error != StopIteration) throw error;
|
||||||
|
}
|
||||||
|
return !!result; // cast to boolean
|
||||||
|
},
|
||||||
|
|
||||||
|
filter: function(object, test, context) {
|
||||||
|
return this.reduce(object, new Array2, function(result, value, key) {
|
||||||
|
if (test.call(context, value, key, object)) {
|
||||||
|
result[result.length] = value;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
invoke: function(object, method) {
|
||||||
|
// apply a method to each item in the enumerated object
|
||||||
|
var args = slice(arguments, 2);
|
||||||
|
return this.map(object, (typeof method == "function") ? function(item) {
|
||||||
|
if (item != null) return method.apply(item, args);
|
||||||
|
} : function(item) {
|
||||||
|
if (item != null) return item[method].apply(item, args);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
map: function(object, block, context) {
|
||||||
|
var result = new Array2;
|
||||||
|
this.forEach (object, function(value, key) {
|
||||||
|
result[result.length] = block.call(context, value, key, object);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
pluck: function(object, key) {
|
||||||
|
return this.map(object, function(item) {
|
||||||
|
if (item != null) return item[key];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
reduce: function(object, result, block, context) {
|
||||||
|
this.forEach (object, function(value, key) {
|
||||||
|
result = block.call(context, result, value, key, object);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
some: function(object, test, context) {
|
||||||
|
return !this.every(object, function(value, key) {
|
||||||
|
return !test.call(context, value, key, object);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
forEach: forEach
|
||||||
|
});
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// base2/Array2.js
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
// The IArray module implements all Array methods.
|
||||||
|
// This module is not public but its methods are accessible through the Array2 object (below).
|
||||||
|
|
||||||
|
var IArray = Module.extend({
|
||||||
|
combine: function(keys, values) {
|
||||||
|
// combine two arrays to make a hash
|
||||||
|
if (!values) values = keys;
|
||||||
|
return this.reduce(keys, {}, function(object, key, index) {
|
||||||
|
object[key] = values[index];
|
||||||
|
return object;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
copy: function(array) {
|
||||||
|
return this.concat(array);
|
||||||
|
},
|
||||||
|
|
||||||
|
contains: function(array, item) {
|
||||||
|
return this.indexOf(array, item) != -1;
|
||||||
|
},
|
||||||
|
|
||||||
|
forEach: forEach.Array,
|
||||||
|
|
||||||
|
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, item, index) {
|
||||||
|
this.splice(array, index, 0, item);
|
||||||
|
return item;
|
||||||
|
},
|
||||||
|
|
||||||
|
insertBefore: function(array, item, before) {
|
||||||
|
var index = this.indexOf(array, before);
|
||||||
|
if (index == -1) this.push(array, item);
|
||||||
|
else this.splice(array, index, 0, item);
|
||||||
|
return item;
|
||||||
|
},
|
||||||
|
|
||||||
|
lastIndexOf: function(array, item, fromIndex) {
|
||||||
|
var length = array.length;
|
||||||
|
if (fromIndex == null) {
|
||||||
|
fromIndex = length - 1;
|
||||||
|
} else if (from < 0) {
|
||||||
|
fromIndex = Math.max(0, length + fromIndex);
|
||||||
|
}
|
||||||
|
for (var i = fromIndex; i >= 0; i--) {
|
||||||
|
if (array[i] === item) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
},
|
||||||
|
|
||||||
|
remove: function(array, item) {
|
||||||
|
var index = this.indexOf(array, item);
|
||||||
|
if (index != -1) this.removeAt(array, index);
|
||||||
|
return item;
|
||||||
|
},
|
||||||
|
|
||||||
|
removeAt: function(array, index) {
|
||||||
|
var item = array[index];
|
||||||
|
this.splice(array, index, 1);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
IArray.prototype.forEach = function(block, context) {
|
||||||
|
forEach.Array(this, block, context);
|
||||||
|
};
|
||||||
|
|
||||||
|
IArray.implement(Enumerable);
|
||||||
|
|
||||||
|
forEach ("concat,join,pop,push,reverse,shift,slice,sort,splice,unshift".split(","), function(name) {
|
||||||
|
IArray[name] = function(array) {
|
||||||
|
return Array.prototype[name].apply(array, slice(arguments, 1));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// create a faux constructor that augments the built-in Array object
|
||||||
|
var Array2 = function() {
|
||||||
|
return IArray(this.constructor == IArray ? Array.apply(null, arguments) : arguments[0]);
|
||||||
|
};
|
||||||
|
// expose IArray.prototype so that it can be extended
|
||||||
|
Array2.prototype = IArray.prototype;
|
||||||
|
|
||||||
|
forEach (IArray, function(method, name, proto) {
|
||||||
|
if (Array[name]) {
|
||||||
|
IArray[name] = Array[name];
|
||||||
|
delete IArray.prototype[name];
|
||||||
|
}
|
||||||
|
Array2[name] = IArray[name];
|
||||||
|
});
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// base2/Hash.js
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
var HASH = "#" + Number(new Date);
|
||||||
|
var KEYS = HASH + "keys";
|
||||||
|
var VALUES = HASH + "values";
|
||||||
|
|
||||||
|
var Hash = Base.extend({
|
||||||
|
constructor: function(values) {
|
||||||
|
this[KEYS] = new Array2;
|
||||||
|
this[VALUES] = {};
|
||||||
|
this.merge(values);
|
||||||
|
},
|
||||||
|
|
||||||
|
copy: function() {
|
||||||
|
var copy = new this.constructor(this);
|
||||||
|
Base.forEach (this, function(property, name) {
|
||||||
|
if (typeof property != "function" && name.charAt(0) != "#") {
|
||||||
|
copy[name] = property;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return copy;
|
||||||
|
},
|
||||||
|
|
||||||
|
// ancient browsers throw an error when we use "in" as an operator
|
||||||
|
// so we must create the function dynamically
|
||||||
|
exists: Legacy.exists || new Function("k", format("return('%1'+k)in this['%2']", HASH, VALUES)),
|
||||||
|
|
||||||
|
fetch: function(key) {
|
||||||
|
return this[VALUES][HASH + key];
|
||||||
|
},
|
||||||
|
|
||||||
|
forEach: function(block, context) {
|
||||||
|
forEach (this[KEYS], function(key) {
|
||||||
|
block.call(context, this.fetch(key), key, this);
|
||||||
|
}, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
keys: function(index, length) {
|
||||||
|
var keys = this[KEYS] || new Array2;
|
||||||
|
switch (arguments.length) {
|
||||||
|
case 0: return keys.copy();
|
||||||
|
case 1: return keys[index];
|
||||||
|
default: return keys.slice(index, length);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
merge: function(values) {
|
||||||
|
forEach (arguments, function(values) {
|
||||||
|
forEach (values, function(value, key) {
|
||||||
|
this.store(key, value);
|
||||||
|
}, this);
|
||||||
|
}, this);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
remove: function(key) {
|
||||||
|
var value = this.fetch(key);
|
||||||
|
this[KEYS].remove(String(key));
|
||||||
|
delete this[VALUES][HASH + key];
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
|
||||||
|
store: function(key, value) {
|
||||||
|
if (arguments.length == 1) value = key;
|
||||||
|
// only store the key for a new entry
|
||||||
|
if (!this.exists(key)) {
|
||||||
|
this[KEYS].push(String(key));
|
||||||
|
}
|
||||||
|
// create the new entry (or overwrite the old entry)
|
||||||
|
this[VALUES][HASH + key] = value;
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
|
||||||
|
toString: function() {
|
||||||
|
return String(this[KEYS]);
|
||||||
|
},
|
||||||
|
|
||||||
|
union: function(values) {
|
||||||
|
return this.merge.apply(this.copy(), arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
values: function(index, length) {
|
||||||
|
var values = this.map(K);
|
||||||
|
switch (arguments.length) {
|
||||||
|
case 0: return values;
|
||||||
|
case 1: return values[index];
|
||||||
|
default: return values.slice(index, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Hash.implement(Enumerable);
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// base2/Collection.js
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
// A Hash that is more array-like (accessible by index).
|
||||||
|
|
||||||
|
// Collection classes have a special (optional) property: Item
|
||||||
|
// The Item property points to a constructor function.
|
||||||
|
// Members of the collection must be an instance of Item.
|
||||||
|
// e.g.
|
||||||
|
// var Dates = Collection.extend(); // create a collection class
|
||||||
|
// Dates.Item = Date; // only JavaScript Date objects allowed as members
|
||||||
|
// var appointments = new Dates(); // instantiate the class
|
||||||
|
// appointments.add(appointmentId, new Date); // add a date
|
||||||
|
// appointments.add(appointmentId, "tomorrow"); // ERROR!
|
||||||
|
|
||||||
|
// The static create() method is responsible for all construction of collection items.
|
||||||
|
// Instance methods that add new items (add, store, insertAt, replaceAt) pass *all* of their arguments
|
||||||
|
// to the static create() method. If you want to modify the way collection items are
|
||||||
|
// created then you only need to override this method for custom collections.
|
||||||
|
|
||||||
|
var Collection = Hash.extend({
|
||||||
|
add: function(key, item) {
|
||||||
|
// Duplicates not allowed using add().
|
||||||
|
// - but you can still overwrite entries using store()
|
||||||
|
assert(!this.exists(key), "Duplicate key.");
|
||||||
|
return this.store.apply(this, arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
count: function() {
|
||||||
|
return this[KEYS].length;
|
||||||
|
},
|
||||||
|
|
||||||
|
indexOf: function(key) {
|
||||||
|
return this[KEYS].indexOf(String(key));
|
||||||
|
},
|
||||||
|
|
||||||
|
insertAt: function(index, key, item) {
|
||||||
|
assert(!this.exists(key), "Duplicate key.");
|
||||||
|
this[KEYS].insertAt(index, String(key));
|
||||||
|
return this.store.apply(this, slice(arguments, 1));
|
||||||
|
},
|
||||||
|
|
||||||
|
item: function(index) {
|
||||||
|
return this.fetch(this[KEYS][index]);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeAt: function(index) {
|
||||||
|
return this.remove(this[KEYS][index]);
|
||||||
|
},
|
||||||
|
|
||||||
|
reverse: function() {
|
||||||
|
this[KEYS].reverse();
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
sort: function(compare) {
|
||||||
|
if (compare) {
|
||||||
|
var self = this;
|
||||||
|
this[KEYS].sort(function(key1, key2) {
|
||||||
|
return compare(self.fetch(key1), self.fetch(key2), key1, key2);
|
||||||
|
});
|
||||||
|
} else this[KEYS].sort();
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
store: function(key, item) {
|
||||||
|
if (arguments.length == 1) item = key;
|
||||||
|
item = this.constructor.create.apply(this.constructor, arguments);
|
||||||
|
return this.base(key, item);
|
||||||
|
},
|
||||||
|
|
||||||
|
storeAt: function(index, item) {
|
||||||
|
//-dean: get rid of this?
|
||||||
|
assert(index < this.count(), "Index out of bounds.");
|
||||||
|
arguments[0] = this[KEYS][index];
|
||||||
|
return this.store.apply(this, arguments);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
Item: null, // if specified, all members of the Collection must be instances of Item
|
||||||
|
|
||||||
|
create: function(key, item) {
|
||||||
|
if (this.Item && !instanceOf(item, this.Item)) {
|
||||||
|
item = new this.Item(key, item);
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
},
|
||||||
|
|
||||||
|
extend: function(_instance, _static) {
|
||||||
|
var klass = this.base(_instance);
|
||||||
|
klass.create = this.create;
|
||||||
|
extend(klass, _static);
|
||||||
|
if (!klass.Item) {
|
||||||
|
klass.Item = this.Item;
|
||||||
|
} else if (typeof klass.Item != "function") {
|
||||||
|
klass.Item = (this.Item || Base).extend(klass.Item);
|
||||||
|
}
|
||||||
|
if (typeof klass.init == "function") klass.init();
|
||||||
|
return klass;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// base2/RegGrp.js
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
var RegGrp = Collection.extend({
|
||||||
|
constructor: function(values, flags) {
|
||||||
|
this.base(values);
|
||||||
|
if (typeof flags == "string") {
|
||||||
|
this.global = /g/.test(flags);
|
||||||
|
this.ignoreCase = /i/.test(flags);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
global: true, // global is the default setting
|
||||||
|
ignoreCase: false,
|
||||||
|
|
||||||
|
exec: function(string, replacement) {
|
||||||
|
if (arguments.length == 1) {
|
||||||
|
var keys = this[KEYS];
|
||||||
|
var values = this[VALUES];
|
||||||
|
replacement = function(match) {
|
||||||
|
if (!match) return "";
|
||||||
|
var offset = 1, i = 0;
|
||||||
|
// loop through the values
|
||||||
|
while (match = values[HASH + keys[i++]]) {
|
||||||
|
// do we have a result?
|
||||||
|
if (arguments[offset]) {
|
||||||
|
var replacement = match.replacement;
|
||||||
|
switch (typeof replacement) {
|
||||||
|
case "function":
|
||||||
|
return replacement.apply(null, slice(arguments, offset));
|
||||||
|
case "number":
|
||||||
|
return arguments[offset + replacement];
|
||||||
|
default:
|
||||||
|
return replacement;
|
||||||
|
}
|
||||||
|
// no? then skip over references to sub-expressions
|
||||||
|
} else offset += match.length + 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var flags = (this.global ? "g" : "") + (this.ignoreCase ? "i" : "");
|
||||||
|
return String(string).replace(new RegExp(this, flags), replacement);
|
||||||
|
},
|
||||||
|
|
||||||
|
test: function(string) {
|
||||||
|
return this.exec(string) != string;
|
||||||
|
},
|
||||||
|
|
||||||
|
toString: function() {
|
||||||
|
var length = 0;
|
||||||
|
return "(" + this.map(function(item) {
|
||||||
|
// fix back references
|
||||||
|
var expression = String(item).replace(/\\(\d+)/g, function($, index) {
|
||||||
|
return "\\" + (1 + Number(index) + length);
|
||||||
|
});
|
||||||
|
length += item.length + 1;
|
||||||
|
return expression;
|
||||||
|
}).join(")|(") + ")";
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
IGNORE: "$0",
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
forEach ("add,exists,fetch,remove,store".split(","), function(name) {
|
||||||
|
extend(this, name, function(expression) {
|
||||||
|
if (instanceOf(expression, RegExp)) {
|
||||||
|
expression = expression.source;
|
||||||
|
}
|
||||||
|
return base(this, arguments);
|
||||||
|
});
|
||||||
|
}, this.prototype);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// base2/RegGrp/Item.js
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
RegGrp.Item = Base.extend({
|
||||||
|
constructor: function(expression, replacement) {
|
||||||
|
var ESCAPE = /\\./g;
|
||||||
|
var STRING = /(['"])\1\+(.*)\+\1\1$/;
|
||||||
|
|
||||||
|
expression = instanceOf(expression, RegExp) ? expression.source : String(expression);
|
||||||
|
|
||||||
|
if (typeof replacement == "number") replacement = String(replacement);
|
||||||
|
else if (replacement == null) replacement = "";
|
||||||
|
|
||||||
|
// count the number of sub-expressions
|
||||||
|
// - add one because each pattern is itself a sub-expression
|
||||||
|
this.length = match(expression.replace(ESCAPE, "").replace(/\[[^\]]+\]/g, ""), /\(/g).length;
|
||||||
|
|
||||||
|
// does the pattern use sub-expressions?
|
||||||
|
if (typeof replacement == "string" && /\$(\d+)/.test(replacement)) {
|
||||||
|
// a simple lookup? (e.g. "$2")
|
||||||
|
if (/^\$\d+$/.test(replacement)) {
|
||||||
|
// store the index (used for fast retrieval of matched strings)
|
||||||
|
replacement = parseInt(replacement.slice(1));
|
||||||
|
} else { // a complicated lookup (e.g. "Hello $2 $1")
|
||||||
|
// build a function to do the lookup
|
||||||
|
var i = this.length + 1;
|
||||||
|
var Q = /'/.test(replacement.replace(ESCAPE, "")) ? '"' : "'";
|
||||||
|
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(STRING, "$1") + Q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.replacement = replacement;
|
||||||
|
this.toString = function() {
|
||||||
|
return expression || "";
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
length: 0,
|
||||||
|
replacement: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// base2/Namespace.js
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
var Namespace = Base.extend({
|
||||||
|
constructor: function(_private, _public) {
|
||||||
|
this.extend(_public);
|
||||||
|
this.toString = function() {
|
||||||
|
return format("[base2.%1]", this.name);
|
||||||
|
};
|
||||||
|
|
||||||
|
// initialise
|
||||||
|
if (typeof this.init == "function") this.init();
|
||||||
|
|
||||||
|
if (this.name != "base2") {
|
||||||
|
this.namespace = format("var %1=base2.%1;", this.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
var namespace = "var base=" + base + ";";
|
||||||
|
var imports = ("base2,lang," + this.imports).split(",");
|
||||||
|
_private.imports = Enumerable.reduce(imports, namespace, function(namespace, name) {
|
||||||
|
if (base2[name]) namespace += base2[name].namespace;
|
||||||
|
return namespace;
|
||||||
|
});
|
||||||
|
|
||||||
|
var namespace = format("base2.%1=%1;", this.name);
|
||||||
|
var exports = this.exports.split(",");
|
||||||
|
_private.exports = Enumerable.reduce(exports, namespace, function(namespace, name) {
|
||||||
|
if (name) {
|
||||||
|
this.namespace += format("var %2=%1.%2;", this.name, name);
|
||||||
|
namespace += format("if(!%1.%2)%1.%2=%2;base2.%2=%1.%2;", this.name, name);
|
||||||
|
}
|
||||||
|
return namespace;
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
if (this.name != "base2") {
|
||||||
|
base2.namespace += format("var %1=base2.%1;", this.name);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
exports: "",
|
||||||
|
imports: "",
|
||||||
|
namespace: "",
|
||||||
|
name: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
base2 = new Namespace(this, {
|
||||||
|
name: "base2",
|
||||||
|
version: "0.8 (alpha)",
|
||||||
|
exports: "Base,Abstract,Module,Enumerable,Array2,Hash,Collection,RegGrp,Namespace"
|
||||||
|
});
|
||||||
|
|
||||||
|
base2.toString = function() {
|
||||||
|
return "[base2]";
|
||||||
|
};
|
||||||
|
|
||||||
|
eval(this.exports);
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// base2/lang/namespace.js
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
var lang = new Namespace(this, {
|
||||||
|
name: "lang",
|
||||||
|
version: base2.version,
|
||||||
|
exports: "K,assert,assertType,assignID,instanceOf,extend,format,forEach,match,rescape,slice,trim",
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
this.extend = extend;
|
||||||
|
// add the Enumerable methods to the lang object
|
||||||
|
forEach (Enumerable.prototype, function(method, name) {
|
||||||
|
if (!Module[name]) {
|
||||||
|
this[name] = function() {
|
||||||
|
return Enumerable[name].apply(Enumerable, arguments);
|
||||||
|
};
|
||||||
|
this.exports += "," + name;
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
eval(this.exports);
|
||||||
|
|
||||||
|
base2.namespace += lang.namespace;
|
||||||
|
|
||||||
|
}; //////////////////// END: CLOSURE /////////////////////////////////////
|
Loading…
Add table
Reference in a new issue