1 // timestamp: Tue, 01 May 2007 19:13:00
\r
3 base2.js - copyright 2007, Dean Edwards
\r
4 http://www.opensource.org/licenses/mit-license
\r
9 // You know, writing a javascript library is awfully time consuming.
\r
11 new function(_) { //////////////////// BEGIN: CLOSURE ////////////////////
\r
13 // =========================================================================
\r
15 // =========================================================================
\r
19 var Base = function() {
\r
20 // call this method from any other method to invoke that method's ancestor
\r
24 extend: function(source) {
\r
25 if (arguments.length > 1) { // extending with a name/value pair
\r
26 var ancestor = this[source];
\r
27 var value = arguments[1];
\r
28 if (typeof value == "function" && ancestor && /\bbase\b/.test(value)) {
\r
29 var method = value;
\r
30 value = function() { // override
\r
31 var previous = this.base;
\r
32 this.base = ancestor;
\r
33 var returnValue = method.apply(this, arguments);
\r
34 this.base = previous;
\r
37 value.method = method;
\r
38 value.ancestor = ancestor;
\r
40 this[source] = value;
\r
41 } else if (source) { // extending with an object literal
\r
42 var extend = Base.prototype.extend;
\r
43 if (Base._prototyping) {
\r
44 var key, i = 0, members = ["constructor", "toString", "valueOf"];
\r
45 while (key = members[i++]) if (source[key] != Object.prototype[key]) {
\r
46 extend.call(this, key, source[key]);
\r
48 } else if (typeof this != "function") {
\r
49 // if the object has a customised extend() method then use it
\r
50 extend = this.extend || extend;
\r
52 // copy each of the source object's properties to this object
\r
53 for (key in source) if (!Object.prototype[key]) {
\r
54 extend.call(this, key, source[key]);
\r
63 Base.extend = function(_instance, _static) { // subclass
\r
64 var extend = Base.prototype.extend;
\r
66 // build the prototype
\r
67 Base._prototyping = true;
\r
68 var proto = new this;
\r
69 extend.call(proto, _instance);
\r
70 delete Base._prototyping;
\r
72 // create the wrapper for the constructor function
\r
73 var constructor = proto.constructor;
\r
74 var klass = proto.constructor = function() {
\r
75 if (!Base._prototyping) {
\r
76 if (this._constructing || this.constructor == klass) { // instantiation
\r
77 this._constructing = true;
\r
78 constructor.apply(this, arguments);
\r
79 delete this._constructing;
\r
81 var object = arguments[0];
\r
82 if (object != null) {
\r
83 (object.extend || extend).call(object, proto);
\r
90 // build the class interface
\r
91 for (var i in Base) klass[i] = this[i];
\r
92 klass.ancestor = this;
\r
93 klass.base = Base.base;
\r
94 klass.prototype = proto;
\r
95 klass.toString = this.toString;
\r
96 extend.call(klass, _static);
\r
97 // class initialisation
\r
98 if (typeof klass.init == "function") klass.init();
\r
103 Base = Base.extend({
\r
104 constructor: function() {
\r
105 this.extend(arguments[0]);
\r
111 implement: function(_interface) {
\r
112 if (typeof _interface == "function") {
\r
113 // if it's a function, call it
\r
114 _interface(this.prototype);
\r
116 // add the interface using the extend() method
\r
117 this.prototype.extend(_interface);
\r
123 // =========================================================================
\r
125 // =========================================================================
\r
127 var Legacy = typeof $Legacy == "undefined" ? {} : $Legacy;
\r
129 var K = function(k) {return k};
\r
131 var assert = function(condition, message, Err) {
\r
133 throw new (Err || Error)(message || "Assertion failed.");
\r
137 var assertType = function(object, type, message) {
\r
139 var condition = typeof type == "function" ? instanceOf(object, type) : typeof object == type;
\r
140 assert(condition, message || "Invalid type.", TypeError);
\r
144 var copy = function(object) {
\r
145 var fn = new Function;
\r
146 fn.prototype = object;
\r
150 var format = function(string) {
\r
151 // replace %n with arguments[n]
\r
152 // e.g. format("%1 %2%3 %2a %1%3", "she", "se", "lls");
\r
153 // ==> "she sells sea shells"
\r
154 // only supports nine replacements: %1 - %9
\r
155 var args = arguments;
\r
156 return String(string).replace(/%([1-9])/g, function(match, index) {
\r
157 return index < args.length ? args[index] : match;
\r
161 var $instanceOf = Legacy.instanceOf || new Function("o,k", "return o instanceof k");
\r
162 var instanceOf = function(object, klass) {
\r
163 assertType(klass, "function", "Invalid 'instanceOf' operand.");
\r
164 if ($instanceOf(object, klass)) return true;
\r
165 // handle exceptions where the target object originates from another frame
\r
166 // this is handy for JSON parsing (amongst other things)
\r
167 if (object != null) switch (klass) {
\r
174 return typeof object == typeof klass.prototype.valueOf();
\r
176 // this is the only troublesome one
\r
177 return !!(object.join && object.splice && !arguments.callee(object, Function));
\r
179 return !!object.getTimezoneOffset;
\r
181 return String(object.constructor.prototype) == String(new RegExp);
\r
186 var match = function(string, expression) {
\r
187 // same as String.match() except that this function will return an empty
\r
188 // array if there is no match
\r
189 return String(string).match(expression) || [];
\r
192 var RESCAPE = /([\/()[\]{}|*+-.,^$?\\])/g;
\r
193 var rescape = function(string) {
\r
194 // make a string safe for creating a RegExp
\r
195 return String(string).replace(RESCAPE, "\\$1");
\r
198 var $slice = Array.prototype.slice;
\r
199 var slice = function(object) {
\r
200 // slice an array-like object
\r
201 return $slice.apply(object, $slice.call(arguments, 1));
\r
204 var TRIM = /^\s+|\s+$/g;
\r
205 var trim = function(string) {
\r
206 return String(string).replace(TRIM, "");
\r
209 // =========================================================================
\r
211 // =========================================================================
\r
213 var base = function(object, args) {
\r
214 // invoke the base method with all supplied arguments
\r
215 return object.base.apply(object, args);
\r
218 var extend = function(object) {
\r
219 assert(object != Object.prototype, "Object.prototype is verboten!");
\r
220 return Base.prototype.extend.apply(object, slice(arguments, 1));
\r
223 // =========================================================================
\r
224 // lang/assignID.js
\r
225 // =========================================================================
\r
228 var assignID = function(object) {
\r
229 // assign a unique id
\r
230 if (!object.base2ID) object.base2ID = "b2_" + $ID++;
\r
231 return object.base2ID;
\r
234 // =========================================================================
\r
236 // =========================================================================
\r
238 if (typeof StopIteration == "undefined") {
\r
239 StopIteration = new Error("StopIteration");
\r
242 var forEach = function(object, block, context) {
\r
243 if (object == null) return;
\r
244 if (typeof object == "function") {
\r
245 // functions are a special case
\r
247 } else if (typeof object.forEach == "function" && object.forEach != arguments.callee) {
\r
248 // the object implements a custom forEach method
\r
249 object.forEach(block, context);
\r
251 } else if (typeof object.length == "number") {
\r
252 // the object is array-like
\r
253 forEach.Array(object, block, context);
\r
256 forEach.Function(fn || Object, object, block, context);
\r
259 // these are the two core enumeration methods. all other forEach methods
\r
260 // eventually call one of these two.
\r
262 forEach.Array = function(array, block, context) {
\r
263 var i, length = array.length; // preserve
\r
264 if (typeof array == "string") {
\r
265 for (i = 0; i < length; i++) {
\r
266 block.call(context, array.charAt(i), i, array);
\r
269 for (i = 0; i < length; i++) {
\r
270 block.call(context, array[i], i, array);
\r
275 forEach.Function = Legacy.forEach || function(fn, object, block, context) {
\r
276 // enumerate an object and compare its keys with fn's prototype
\r
277 for (var key in object) {
\r
278 if (fn.prototype[key] === undefined) {
\r
279 block.call(context, object[key], key, object);
\r
284 // =========================================================================
\r
285 // base2/Base/forEach.js
\r
286 // =========================================================================
\r
288 Base.forEach = function(object, block, context) {
\r
289 forEach.Function(this, object, block, context);
\r
292 // =========================================================================
\r
293 // base2/../Function.js
\r
294 // =========================================================================
\r
296 // some browsers don't define this
\r
298 Function.prototype.prototype = {};
\r
301 // =========================================================================
\r
302 // base2/../String.js
\r
303 // =========================================================================
\r
305 // fix String.replace (Safari/IE5.0)
\r
307 if ("".replace(/^/, String)) {
\r
308 extend(String.prototype, "replace", function(expression, replacement) {
\r
309 if (typeof replacement == "function") { // Safari doesn't like functions
\r
310 if (instanceOf(expression, RegExp)) {
\r
311 var regexp = expression;
\r
312 var global = regexp.global;
\r
313 if (global == null) global = /(g|gi)$/.test(regexp);
\r
314 // we have to convert global RexpExps for exec() to work consistently
\r
315 if (global) regexp = new RegExp(regexp.source); // non-global
\r
317 regexp = new RegExp(rescape(expression));
\r
319 var match, string = this, result = "";
\r
320 while (string && (match = regexp.exec(string))) {
\r
321 result += string.slice(0, match.index) + replacement.apply(this, match);
\r
322 string = string.slice(match.index + match[0].length);
\r
323 if (!global) break;
\r
325 return result + string;
\r
327 return base(this, arguments);
\r
332 // =========================================================================
\r
333 // base2/Abstract.js
\r
334 // =========================================================================
\r
336 var Abstract = Base.extend({
\r
337 constructor: function() {
\r
338 throw new TypeError("Class cannot be instantiated.");
\r
342 // =========================================================================
\r
344 // =========================================================================
\r
346 // based on ruby's Module class and Mozilla's Array generics:
\r
347 // http://www.ruby-doc.org/core/classes/Module.html
\r
348 // http://developer.mozilla.org/en/docs/New_in_JavaScript_1.6#Array_and_String_generics
\r
350 // A Module is used as the basis for creating interfaces that can be
\r
351 // applied to other classes. *All* properties and methods are static.
\r
352 // When a module is used as a mixin, methods defined on what would normally be
\r
353 // the instance interface become instance methods of the target object.
\r
355 // Modules cannot be instantiated. Static properties and methods are inherited.
\r
357 var Module = Abstract.extend(null, {
\r
358 extend: function(_interface, _static) {
\r
359 // extend a module to create a new module
\r
360 var module = this.base();
\r
361 // inherit static methods
\r
362 forEach (this, function(property, name) {
\r
363 if (!Module[name] && name != "init") {
\r
364 extend(module, name, property);
\r
367 // implement module (instance AND static) methods
\r
368 module.implement(_interface);
\r
369 // implement static properties and methods
\r
370 extend(module, _static);
\r
371 // Make the submarine noises Larry!
\r
372 if (typeof module.init == "function") module.init();
\r
376 implement: function(_interface) {
\r
377 // implement an interface on BOTH the instance and static interfaces
\r
379 if (typeof _interface == "function") {
\r
380 module.base(_interface);
\r
381 forEach (_interface, function(property, name) {
\r
382 if (!Module[name] && name != "init") {
\r
383 extend(module, name, property);
\r
387 // create the instance interface
\r
388 Base.forEach (extend({}, _interface), function(property, name) {
\r
389 // instance methods call the equivalent static method
\r
390 if (typeof property == "function") {
\r
391 property = function() {
\r
392 base; // force inheritance
\r
393 return module[name].apply(module, [this].concat(slice(arguments)));
\r
396 if (!Module[name]) extend(this, name, property);
\r
397 }, module.prototype);
\r
398 // add the static interface
\r
399 extend(module, _interface);
\r
406 // =========================================================================
\r
407 // base2/Enumerable.js
\r
408 // =========================================================================
\r
410 var Enumerable = Module.extend({
\r
411 every: function(object, test, context) {
\r
414 this.forEach (object, function(value, key) {
\r
415 result = test.call(context, value, key, object);
\r
416 if (!result) throw StopIteration;
\r
419 if (error != StopIteration) throw error;
\r
421 return !!result; // cast to boolean
\r
424 filter: function(object, test, context) {
\r
425 return this.reduce(object, function(result, value, key) {
\r
426 if (test.call(context, value, key, object)) {
\r
427 result[result.length] = value;
\r
433 invoke: function(object, method) {
\r
434 // apply a method to each item in the enumerated object
\r
435 var args = slice(arguments, 2);
\r
436 return this.map(object, (typeof method == "function") ? function(item) {
\r
437 if (item != null) return method.apply(item, args);
\r
438 } : function(item) {
\r
439 if (item != null) return item[method].apply(item, args);
\r
443 map: function(object, block, context) {
\r
444 var result = new Array2;
\r
445 this.forEach (object, function(value, key) {
\r
446 result[result.length] = block.call(context, value, key, object);
\r
451 pluck: function(object, key) {
\r
452 return this.map(object, function(item) {
\r
453 if (item != null) return item[key];
\r
457 reduce: function(object, block, result, context) {
\r
458 this.forEach (object, function(value, key) {
\r
459 result = block.call(context, result, value, key, object);
\r
464 some: function(object, test, context) {
\r
465 return !this.every(object, function(value, key) {
\r
466 return !test.call(context, value, key, object);
\r
473 // =========================================================================
\r
475 // =========================================================================
\r
477 // The IArray module implements all Array methods.
\r
478 // This module is not public but its methods are accessible through the Array2 object (below).
\r
480 var IArray = Module.extend({
\r
481 combine: function(keys, values) {
\r
482 // combine two arrays to make a hash
\r
483 if (!values) values = keys;
\r
484 return this.reduce(keys, function(object, key, index) {
\r
485 object[key] = values[index];
\r
490 copy: function(array) {
\r
491 return this.concat(array);
\r
494 contains: function(array, item) {
\r
495 return this.indexOf(array, item) != -1;
\r
498 forEach: forEach.Array,
\r
500 indexOf: function(array, item, fromIndex) {
\r
501 var length = array.length;
\r
502 if (fromIndex == null) {
\r
504 } else if (fromIndex < 0) {
\r
505 fromIndex = Math.max(0, length + fromIndex);
\r
507 for (var i = fromIndex; i < length; i++) {
\r
508 if (array[i] === item) return i;
\r
513 insertAt: function(array, item, index) {
\r
514 this.splice(array, index, 0, item);
\r
518 insertBefore: function(array, item, before) {
\r
519 var index = this.indexOf(array, before);
\r
520 if (index == -1) this.push(array, item);
\r
521 else this.splice(array, index, 0, item);
\r
525 lastIndexOf: function(array, item, fromIndex) {
\r
526 var length = array.length;
\r
527 if (fromIndex == null) {
\r
528 fromIndex = length - 1;
\r
529 } else if (from < 0) {
\r
530 fromIndex = Math.max(0, length + fromIndex);
\r
532 for (var i = fromIndex; i >= 0; i--) {
\r
533 if (array[i] === item) return i;
\r
538 remove: function(array, item) {
\r
539 var index = this.indexOf(array, item);
\r
540 if (index != -1) this.removeAt(array, index);
\r
544 removeAt: function(array, index) {
\r
545 var item = array[index];
\r
546 this.splice(array, index, 1);
\r
551 IArray.prototype.forEach = function(block, context) {
\r
552 forEach.Array(this, block, context);
\r
555 IArray.implement(Enumerable);
\r
557 forEach ("concat,join,pop,push,reverse,shift,slice,sort,splice,unshift".split(","), function(name) {
\r
558 IArray[name] = function(array) {
\r
559 return Array.prototype[name].apply(array, slice(arguments, 1));
\r
563 // create a faux constructor that augments the built-in Array object
\r
564 var Array2 = function() {
\r
565 return IArray(this.constructor == IArray ? Array.apply(null, arguments) : arguments[0]);
\r
567 // expose IArray.prototype so that it can be extended
\r
568 Array2.prototype = IArray.prototype;
\r
570 forEach (IArray, function(method, name, proto) {
\r
572 IArray[name] = Array[name];
\r
573 delete IArray.prototype[name];
\r
575 Array2[name] = IArray[name];
\r
578 // =========================================================================
\r
580 // =========================================================================
\r
582 var HASH = "#" + Number(new Date);
\r
583 var KEYS = HASH + "keys";
\r
584 var VALUES = HASH + "values";
\r
586 var Hash = Base.extend({
\r
587 constructor: function(values) {
\r
588 this[KEYS] = new Array2;
\r
590 this.merge(values);
\r
594 var copy = new this.constructor(this);
\r
595 Base.forEach (this, function(property, name) {
\r
596 if (typeof property != "function" && name.charAt(0) != "#") {
\r
597 copy[name] = property;
\r
603 // ancient browsers throw an error when we use "in" as an operator
\r
604 // so we must create the function dynamically
\r
605 exists: Legacy.exists || new Function("k", format("return('%1'+k)in this['%2']", HASH, VALUES)),
\r
607 fetch: function(key) {
\r
608 return this[VALUES][HASH + key];
\r
611 forEach: function(block, context) {
\r
612 forEach (this[KEYS], function(key) {
\r
613 block.call(context, this.fetch(key), key, this);
\r
617 keys: function(index, length) {
\r
618 var keys = this[KEYS] || new Array2;
\r
619 switch (arguments.length) {
\r
620 case 0: return keys.copy();
\r
621 case 1: return keys[index];
\r
622 default: return keys.slice(index, length);
\r
626 merge: function(values) {
\r
627 forEach (arguments, function(values) {
\r
628 forEach (values, function(value, key) {
\r
629 this.store(key, value);
\r
635 remove: function(key) {
\r
636 var value = this.fetch(key);
\r
637 this[KEYS].remove(String(key));
\r
638 delete this[VALUES][HASH + key];
\r
642 store: function(key, value) {
\r
643 if (arguments.length == 1) value = key;
\r
644 // only store the key for a new entry
\r
645 if (!this.exists(key)) {
\r
646 this[KEYS].push(String(key));
\r
648 // create the new entry (or overwrite the old entry)
\r
649 this[VALUES][HASH + key] = value;
\r
653 toString: function() {
\r
654 return String(this[KEYS]);
\r
657 union: function(values) {
\r
658 return this.merge.apply(this.copy(), arguments);
\r
661 values: function(index, length) {
\r
662 var values = this.map(K);
\r
663 switch (arguments.length) {
\r
664 case 0: return values;
\r
665 case 1: return values[index];
\r
666 default: return values.slice(index, length);
\r
671 Hash.implement(Enumerable);
\r
673 // =========================================================================
\r
674 // base2/Collection.js
\r
675 // =========================================================================
\r
677 // A Hash that is more array-like (accessible by index).
\r
679 // Collection classes have a special (optional) property: Item
\r
680 // The Item property points to a constructor function.
\r
681 // Members of the collection must be an instance of Item.
\r
683 // var Dates = Collection.extend(); // create a collection class
\r
684 // Dates.Item = Date; // only JavaScript Date objects allowed as members
\r
685 // var appointments = new Dates(); // instantiate the class
\r
686 // appointments.add(appointmentId, new Date); // add a date
\r
687 // appointments.add(appointmentId, "tomorrow"); // ERROR!
\r
689 // The static create() method is responsible for all construction of collection items.
\r
690 // Instance methods that add new items (add, store, insertAt, replaceAt) pass *all* of their arguments
\r
691 // to the static create() method. If you want to modify the way collection items are
\r
692 // created then you only need to override this method for custom collections.
\r
694 var Collection = Hash.extend({
\r
695 add: function(key, item) {
\r
696 // Duplicates not allowed using add().
\r
697 // - but you can still overwrite entries using store()
\r
698 assert(!this.exists(key), "Duplicate key.");
\r
699 return this.store.apply(this, arguments);
\r
702 count: function() {
\r
703 return this[KEYS].length;
\r
706 indexOf: function(key) {
\r
707 return this[KEYS].indexOf(String(key));
\r
710 insertAt: function(index, key, item) {
\r
711 assert(!this.exists(key), "Duplicate key.");
\r
712 this[KEYS].insertAt(index, String(key));
\r
713 return this.store.apply(this, slice(arguments, 1));
\r
716 item: function(index) {
\r
717 return this.fetch(this[KEYS][index]);
\r
720 removeAt: function(index) {
\r
721 return this.remove(this[KEYS][index]);
\r
724 reverse: function() {
\r
725 this[KEYS].reverse();
\r
729 sort: function(compare) {
\r
732 this[KEYS].sort(function(key1, key2) {
\r
733 return compare(self.fetch(key1), self.fetch(key2), key1, key2);
\r
735 } else this[KEYS].sort();
\r
739 store: function(key, item) {
\r
740 if (arguments.length == 1) item = key;
\r
741 item = this.constructor.create.apply(this.constructor, arguments);
\r
742 return this.base(key, item);
\r
745 storeAt: function(index, item) {
\r
746 //-dean: get rid of this?
\r
747 assert(index < this.count(), "Index out of bounds.");
\r
748 arguments[0] = this[KEYS][index];
\r
749 return this.store.apply(this, arguments);
\r
752 Item: null, // if specified, all members of the Collection must be instances of Item
\r
754 create: function(key, item) {
\r
755 if (this.Item && !instanceOf(item, this.Item)) {
\r
756 item = new this.Item(key, item);
\r
761 extend: function(_instance, _static) {
\r
762 var klass = this.base(_instance);
\r
763 klass.create = this.create;
\r
764 extend(klass, _static);
\r
766 klass.Item = this.Item;
\r
767 } else if (typeof klass.Item != "function") {
\r
768 klass.Item = (this.Item || Base).extend(klass.Item);
\r
770 if (typeof klass.init == "function") klass.init();
\r
775 // =========================================================================
\r
777 // =========================================================================
\r
779 var RegGrp = Collection.extend({
\r
780 constructor: function(values, flags) {
\r
782 if (typeof flags == "string") {
\r
783 this.global = /g/.test(flags);
\r
784 this.ignoreCase = /i/.test(flags);
\r
788 global: true, // global is the default setting
\r
791 exec: function(string, replacement) {
\r
792 if (arguments.length == 1) {
\r
793 var keys = this[KEYS];
\r
794 var values = this[VALUES];
\r
795 replacement = function(match) {
\r
796 if (!match) return "";
\r
797 var offset = 1, i = 0;
\r
798 // loop through the values
\r
799 while (match = values[HASH + keys[i++]]) {
\r
800 // do we have a result?
\r
801 if (arguments[offset]) {
\r
802 var replacement = match.replacement;
\r
803 switch (typeof replacement) {
\r
805 return replacement.apply(null, slice(arguments, offset));
\r
807 return arguments[offset + replacement];
\r
809 return replacement;
\r
811 // no? then skip over references to sub-expressions
\r
812 } else offset += match.length + 1;
\r
816 var flags = (this.global ? "g" : "") + (this.ignoreCase ? "i" : "");
\r
817 return String(string).replace(new RegExp(this, flags), replacement);
\r
820 test: function(string) {
\r
821 return this.exec(string) != string;
\r
824 toString: function() {
\r
826 return "(" + this.map(function(item) {
\r
827 // fix back references
\r
828 var expression = String(item).replace(/\\(\d+)/g, function($, index) {
\r
829 return "\\" + (1 + Number(index) + length);
\r
831 length += item.length + 1;
\r
833 }).join(")|(") + ")";
\r
839 forEach ("add,exists,fetch,remove,store".split(","), function(name) {
\r
840 extend(this, name, function(expression) {
\r
841 if (instanceOf(expression, RegExp)) {
\r
842 expression = expression.source;
\r
844 return base(this, arguments);
\r
846 }, this.prototype);
\r
850 // =========================================================================
\r
851 // base2/RegGrp/Item.js
\r
852 // =========================================================================
\r
854 RegGrp.Item = Base.extend({
\r
855 constructor: function(expression, replacement) {
\r
856 var ESCAPE = /\\./g;
\r
857 var STRING = /(['"])\1\+(.*)\+\1\1$/;
\r
859 expression = instanceOf(expression, RegExp) ? expression.source : String(expression);
\r
861 if (typeof replacement == "number") replacement = String(replacement);
\r
862 else if (replacement == null) replacement = "";
\r
864 // count the number of sub-expressions
\r
865 // - add one because each pattern is itself a sub-expression
\r
866 this.length = match(expression.replace(ESCAPE, "").replace(/\[[^\]]+\]/g, ""), /\(/g).length;
\r
868 // does the pattern use sub-expressions?
\r
869 if (typeof replacement == "string" && /\$(\d+)/.test(replacement)) {
\r
870 // a simple lookup? (e.g. "$2")
\r
871 if (/^\$\d+$/.test(replacement)) {
\r
872 // store the index (used for fast retrieval of matched strings)
\r
873 replacement = parseInt(replacement.slice(1));
\r
874 } else { // a complicated lookup (e.g. "Hello $2 $1")
\r
875 // build a function to do the lookup
\r
876 var i = this.length + 1;
\r
877 var Q = /'/.test(replacement.replace(ESCAPE, "")) ? '"' : "'";
\r
878 replacement = replacement.replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\$(\d+)/g, Q +
\r
879 "+(arguments[$1]||" + Q+Q + ")+" + Q);
\r
880 replacement = new Function("return " + Q + replacement.replace(STRING, "$1") + Q);
\r
883 this.replacement = replacement;
\r
884 this.toString = function() {
\r
885 return expression || "";
\r
893 // =========================================================================
\r
894 // base2/Namespace.js
\r
895 // =========================================================================
\r
897 var Namespace = Base.extend({
\r
898 constructor: function(_private, _public) {
\r
899 this.extend(_public);
\r
900 this.toString = function() {
\r
901 return format("[base2.%1]", this.name);
\r
905 if (typeof this.init == "function") this.init();
\r
907 if (this.name != "base2") {
\r
908 this.namespace = format("var %1=base2.%1;", this.name);
\r
911 var namespace = "var base=" + base + ";";
\r
912 var imports = ("base2,lang," + this.imports).split(",");
\r
913 _private.imports = Enumerable.reduce(imports, function(namespace, name) {
\r
914 if (base2[name]) namespace += base2[name].namespace;
\r
918 var namespace = format("base2.%1=%1;", this.name);
\r
919 var exports = this.exports.split(",");
\r
920 _private.exports = Enumerable.reduce(exports, function(namespace, name) {
\r
922 this.namespace += format("var %2=%1.%2;", this.name, name);
\r
923 namespace += format("if(!%1.%2)%1.%2=%2;base2.%2=%1.%2;", this.name, name);
\r
926 }, namespace, this);
\r
928 if (this.name != "base2") {
\r
929 base2.namespace += format("var %1=base2.%1;", this.name);
\r
939 base2 = new Namespace(this, {
\r
941 version: "0.8 (alpha)",
\r
942 exports: "Base,Abstract,Module,Enumerable,Array2,Hash,Collection,RegGrp,Namespace"
\r
945 base2.toString = function() {
\r
949 eval(this.exports);
\r
951 // =========================================================================
\r
952 // base2/lang/namespace.js
\r
953 // =========================================================================
\r
955 var lang = new Namespace(this, {
\r
957 version: base2.version,
\r
958 exports: "K,assert,assertType,assignID,copy,instanceOf,extend,format,forEach,match,rescape,slice,trim",
\r
961 this.extend = extend;
\r
962 // add the Enumerable methods to the lang object
\r
963 forEach (Enumerable.prototype, function(method, name) {
\r
964 if (!Module[name]) {
\r
965 this[name] = function() {
\r
966 return Enumerable[name].apply(Enumerable, arguments);
\r
968 this.exports += "," + name;
\r
974 eval(this.exports);
\r
976 base2.namespace += lang.namespace;
\r
978 }; //////////////////// END: CLOSURE /////////////////////////////////////
\r