1 /*
  2  * prototype.js light
  3  */
  4 Array.prototype.clone = function() {
  5   return [].concat(this);
  6 };
  7 Array.prototype.toArray = Array.prototype.clone;
  8 // The primary use of Array.from() is to obtain an actual Array object based on anything that could pass as an array.
  9 // the predefined arguments reference within your functions
 10 Array.from = function(iterable) {
 11   if (!iterable) return [];
 12   if (iterable.toArray) return iterable.toArray();
 13   var length = iterable.length || 0, results = new Array(length);
 14   while (length--) results[length] = iterable[length];
 15   return results;
 16 }
 17 // extend Object
 18 Object.extend = function(destination, source) {
 19   for (var property in source)
 20     destination[property] = source[property];
 21   return destination;
 22 };
 23 Object.extend(Object, {
 24   toJSON: function(object) {
 25     var type = typeof object;
 26     switch (type) {
 27       case 'undefined':
 28       case 'function':
 29       case 'unknown': return;
 30       case 'boolean': return object.toString();
 31     }
 32     if (object === null) return 'null';
 33     if (object.toJSON) return object.toJSON();
 34     var results = [];
 35     for (var property in object) {
 36       var value = Object.toJSON(object[property]);
 37       if (!Object.isUndefined(value))
 38         results.push(property.toJSON() + ': ' + value);
 39     }
 40     return '{' + results.join(', ') + '}';
 41   },
 42   keys: function(object) {
 43     var keys = [];
 44     for (var property in object)
 45       keys.push(property);
 46     return keys;
 47   },
 48   values: function(object) {
 49     var values = [];
 50     for (var property in object)
 51       values.push(object[property]);
 52     return values;
 53   },
 54   isArray: function(object) {
 55     return object != null && typeof object == "object" &&
 56       'splice' in object && 'join' in object;
 57   },
 58   isHash: function(object) {
 59     return object instanceof Hash;
 60   },
 61   isFunction: function(object) {
 62     return typeof object == "function";
 63   },
 64   isString: function(object) {
 65     return typeof object == "string";
 66   },
 67   isNumber: function(object) {
 68     return typeof object == "number";
 69   },
 70   isUndefined: function(object) {
 71     return typeof object == "undefined";
 72   },
 73   inheritConstants: function(destination, source) {
 74     for (var property in source) {
 75       if ((typeof source[property] == "string") || (typeof source[property] == "number")) {
 76           destination[property] = source[property];
 77       }
 78     }
 79     return destination;
 80   }
 81 });
 82 // extend Function
 83 Object.extend(Function.prototype, {
 84   argumentNames: function() {
 85     var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1]
 86       .replace(/\s+/g, '').split(',');
 87     return names.length == 1 && !names[0] ? [] : names;
 88   },
 89   bind: function() {
 90     if (arguments.length < 2 && (typeof arguments[0] == "undefined")) return this;
 91     var __method = this, args = Array.from(arguments), object = args.shift();
 92     return function() {
 93       return __method.apply(object, args.concat(Array.from(arguments)));
 94     }
 95   },
 96   curry: function() {
 97     if (!arguments.length) return this;
 98     var __method = this, args = Array.from(arguments);
 99     return function() {
100       return __method.apply(this, args.concat(Array.from(arguments)));
101     }
102   },
103   wrap: function(wrapper) {
104     var __method = this;
105     return function() {
106       return wrapper.apply(this, [__method.bind(this)].concat(Array.from(arguments)));
107     }
108   },
109   methodize: function() {
110     if (this._methodized) return this._methodized;
111     var __method = this;
112     return this._methodized = function() {
113       return __method.apply(null, [this].concat(Array.from(arguments)));
114     };
115   }
116 });
117 Object.extend(String.prototype, {
118   camelize: function(prefix, suffix) {
119     var parts = this.split('-');
120     if (prefix) parts.unshift(prefix);
121     if (suffix) parts.push(suffix);
122     var len = parts.length;
123     if (len == 1) return parts[0];
124 
125     var camelized = this.charAt(0) == '-'
126       ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
127       : parts[0];
128 
129     for (var i = 1; i < len; i++)
130       camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
131 
132     return camelized;
133   },
134   capitalize: function() {
135     return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
136   },
137   startsWith: function(pattern) {
138     return this.indexOf(pattern) === 0;
139   },
140   endsWith: function(pattern) {
141     var d = this.length - pattern.length;
142     return d >= 0 && this.lastIndexOf(pattern) === d;
143   },
144   empty: function() {
145     return this == '';
146   },
147   strip: function() {
148     return this.replace(/^\s+/, '').replace(/\s+$/, '');
149   },
150   // TODO Remove this
151   times: function(count) {
152     return count < 1 ? '' : new Array(count + 1).join(this);
153   },
154   toJSON: function() {
155     // TODO Fix quotes...
156     return '\'' + this.toString().replace(/([\\'])/g, '\\$1') + '\'';
157   }
158 });
159 Object.extend(Number.prototype, {
160   toPaddedString: function(length, radix) {
161     var string = this.toString(radix || 10);
162     return '0'.times(length - string.length) + string;
163   },
164   toJSON: function() {
165     return isFinite(this) ? this.toString() : 'null';
166   }
167 });
168 Object.extend(Array.prototype, {
169   indexOf: function(object, from) {
170     var len = this.length;
171     from = from || 0;
172     for (var i = from; i < len; i++) {
173       if (this[i] === object) {
174         return i;
175       }
176     }
177     return -1;
178   },
179   remove: function(object) {
180     var index = 0;
181     if (typeof object == 'number') {
182       index = object;
183     } else {
184       index = this.indexOf(object);
185       if (index < 0) {
186         return null;
187       }
188     }
189     return this.splice(index, 1)[0];
190   },
191   toJSON: function() {
192     var results = [];
193     this.each(function(object) {
194       var value = Object.toJSON(object);
195       if (!Object.isUndefined(value)) results.push(value);
196     });
197     return '[' + results.join(', ') + ']';
198   }
199 });
200 Object.extend(Date.prototype, {
201   // TODO Fix UTC
202   toJSON: function() {
203     return '"' + this.getUTCFullYear() + '-' +
204       (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
205       this.getUTCDate().toPaddedString(2) + 'T' +
206       this.getUTCHours().toPaddedString(2) + ':' +
207       this.getUTCMinutes().toPaddedString(2) + ':' +
208       this.getUTCSeconds().toPaddedString(2) + 'Z"';
209   }
210 });
211 /**
212  * @class Class like creation with inheritance. Based on Alex Arnell's inheritance implementation.
213  */
214 jls.lang.Class = {/** @lends jls.lang.Class */
215     /**
216      * Creates a new class.
217      * 
218      * @param {Object} declaration An object containing the class declaration.
219      * @returns {Object} The new class.
220      */
221   create: function() {
222     var parent = null, properties = Array.from(arguments);
223     if (typeof properties[0] == "function")
224       parent = properties.shift();
225 
226     function klass() {
227       this.initialize.apply(this, arguments);
228     }
229 
230     Object.extend(klass, jls.lang.Class.Methods);
231     klass.superclass = parent;
232     klass.subclasses = [];
233 
234     if (parent) {
235       var subclass = function() { };
236       subclass.prototype = parent.prototype;
237       klass.prototype = new subclass;
238       parent.subclasses.push(klass);
239     }
240 
241     for (var i = 0; i < properties.length; i++)
242       klass.addMethods(properties[i]);
243 
244     if (!klass.prototype.initialize)
245       klass.prototype.initialize = jls.lang.Class.emptyFunction;
246 
247     klass.prototype.constructor = klass;
248 
249     return klass;
250   },
251   emptyFunction: function() { },
252   notAvailableFunction: function() {
253       throw new jls.lang.Exception('Function not available');
254   },
255   abstractMethod: function() {
256       throw new jls.lang.Exception('Abstract method');
257   },
258   // instantiate
259   newInstance: function(object) {
260     if (!(object && object.classname)) {
261       throw new jls.lang.Exception('Invalid object, the classname property is required');
262     }
263     var classname = object.classname;
264     jls.loader.require(classname);
265     /*var properties = Array.from(arguments);
266     var args = '';
267     for (var i = 0; i < properties.length; i++) {
268       if (i > 0) args += ', ';
269       args += 'properties[' + i + ']';
270     }*/
271     var args = 'object';
272     for (var i = 1; i < arguments.length; i++) {
273       args += ', arguments[' + i + ']';
274     }
275     //jls.logger.info('newInstance() : eval(\'new ' + classname + '(' + args + ')\')');
276     return eval('new ' + classname + '(' + args + ')');
277   }
278 };
279 /**
280  * @class Class helper.
281  */
282 jls.lang.Class.Methods = /** @lends jls.lang.Class.Methods */
283 {
284   addMethods: function(source) {
285     var ancestor   = this.superclass && this.superclass.prototype;
286     var properties = Object.keys(source);
287 
288     if (!Object.keys({ toString: true }).length)
289       properties.push("toString", "valueOf");
290 
291     for (var i = 0, length = properties.length; i < length; i++) {
292       var property = properties[i], value = source[property];
293       if (ancestor && (typeof value == 'function') &&
294           value.argumentNames()[0] == "$super") {
295         var method = value;
296         value = (function(m) {
297           return function() { return ancestor[m].apply(this, arguments) };
298         })(property).wrap(method);
299 
300         value.valueOf = method.valueOf.bind(method);
301         value.toString = method.toString.bind(method);
302       }
303       this.prototype[property] = value;
304     }
305 
306     return this;
307   }
308 };
309