6 description: The heart of MooTools.
8 license: MIT-style license.
10 copyright: Copyright (c) 2006-2010 [Valerio Proietti](http://mad4milk.net/).
12 authors: The MooTools production team (http://mootools.net/developers/)
15 - Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)
16 - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
18 provides: [Core, MooTools, Type, typeOf, instanceOf, Native]
32 var typeOf = this.typeOf = function(item){
33 if (item == null) return 'null';
34 if (item.$family) return item.$family();
37 if (item.nodeType == 1) return 'element';
38 if (item.nodeType == 3) return (/\S/).test(item.nodeValue) ? 'textnode' : 'whitespace';
39 } else if (typeof item.length == 'number'){
40 if (item.callee) return 'arguments';
41 if ('item' in item) return 'collection';
47 var instanceOf = this.instanceOf = function(item, object){
48 if (item == null) return false;
49 var constructor = item.$constructor || item.constructor;
51 if (constructor === object) return true;
52 constructor = constructor.parent;
54 return item instanceof object;
57 // Function overloading
59 var Function = this.Function;
61 var enumerables = true;
62 for (var i in {toString: 1}) enumerables = null;
63 if (enumerables) enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor'];
65 Function.prototype.overloadSetter = function(usePlural){
67 return function(a, b){
68 if (a == null) return this;
69 if (usePlural || typeof a != 'string'){
70 for (var k in a) self.call(this, k, a[k]);
71 if (enumerables) for (var i = enumerables.length; i--;){
73 if (a.hasOwnProperty(k)) self.call(this, k, a[k]);
76 self.call(this, a, b);
82 Function.prototype.overloadGetter = function(usePlural){
86 if (usePlural || typeof a != 'string') args = a;
87 else if (arguments.length > 1) args = arguments;
90 for (var i = 0; i < args.length; i++) result[args[i]] = self.call(this, args[i]);
92 result = self.call(this, a);
98 Function.prototype.extend = function(key, value){
102 Function.prototype.implement = function(key, value){
103 this.prototype[key] = value;
108 var slice = Array.prototype.slice;
110 Function.from = function(item){
111 return (typeOf(item) == 'function') ? item : function(){
116 Array.from = function(item){
117 if (item == null) return [];
118 return (Type.isEnumerable(item) && typeof item != 'string') ? (typeOf(item) == 'array') ? item : slice.call(item) : [item];
121 Number.from = function(item){
122 var number = parseFloat(item);
123 return isFinite(number) ? number : null;
126 String.from = function(item){
140 this.$protected = true;
148 var Type = this.Type = function(name, object){
150 var lower = name.toLowerCase();
151 var typeCheck = function(item){
152 return (typeOf(item) == lower);
155 Type['is' + name] = typeCheck;
157 object.prototype.$family = (function(){
161 object.type = typeCheck;
166 if (object == null) return null;
169 object.$constructor = Type;
170 object.prototype.$constructor = object;
175 var toString = Object.prototype.toString;
177 Type.isEnumerable = function(item){
178 return (item != null && typeof item.length == 'number' && toString.call(item) != '[object Function]' );
183 var hooksOf = function(object){
184 var type = typeOf(object.prototype);
185 return hooks[type] || (hooks[type] = []);
188 var implement = function(name, method){
189 if (method && method.$hidden) return;
191 var hooks = hooksOf(this);
193 for (var i = 0; i < hooks.length; i++){
195 if (typeOf(hook) == 'type') implement.call(hook, name, method);
196 else hook.call(this, name, method);
199 var previous = this.prototype[name];
200 if (previous == null || !previous.$protected) this.prototype[name] = method;
202 if (this[name] == null && typeOf(method) == 'function') extend.call(this, name, function(item){
203 return method.apply(item, slice.call(arguments, 1));
207 var extend = function(name, method){
208 if (method && method.$hidden) return;
209 var previous = this[name];
210 if (previous == null || !previous.$protected) this[name] = method;
215 implement: implement.overloadSetter(),
217 extend: extend.overloadSetter(),
219 alias: function(name, existing){
220 implement.call(this, name, this.prototype[existing]);
223 mirror: function(hook){
224 hooksOf(this).push(hook);
230 new Type('Type', Type);
234 var force = function(name, object, methods){
235 var isType = (object != Object),
236 prototype = object.prototype;
238 if (isType) object = new Type(name, object);
240 for (var i = 0, l = methods.length; i < l; i++){
241 var key = methods[i],
242 generic = object[key],
243 proto = prototype[key];
245 if (generic) generic.protect();
247 if (isType && proto){
248 delete prototype[key];
249 prototype[key] = proto.protect();
253 if (isType) object.implement(prototype);
258 force('String', String, [
259 'charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search',
260 'slice', 'split', 'substr', 'substring', 'trim', 'toLowerCase', 'toUpperCase'
262 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice',
263 'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight'
264 ])('Number', Number, [
265 'toExponential', 'toFixed', 'toLocaleString', 'toPrecision'
266 ])('Function', Function, [
267 'apply', 'call', 'bind'
268 ])('RegExp', RegExp, [
270 ])('Object', Object, [
271 'create', 'defineProperty', 'defineProperties', 'keys',
272 'getPrototypeOf', 'getOwnPropertyDescriptor', 'getOwnPropertyNames',
273 'preventExtensions', 'isExtensible', 'seal', 'isSealed', 'freeze', 'isFrozen'
274 ])('Date', Date, ['now']);
276 Object.extend = extend.overloadSetter();
278 Date.extend('now', function(){
282 new Type('Boolean', Boolean);
284 // fixes NaN returning as Number
286 Number.prototype.$family = function(){
287 return isFinite(this) ? 'number' : 'null';
292 Number.extend('random', function(min, max){
293 return Math.floor(Math.random() * (max - min + 1) + min);
298 var hasOwnProperty = Object.prototype.hasOwnProperty;
299 Object.extend('forEach', function(object, fn, bind){
300 for (var key in object){
301 if (hasOwnProperty.call(object, key)) fn.call(bind, object[key], key, object);
305 Object.each = Object.forEach;
309 forEach: function(fn, bind){
310 for (var i = 0, l = this.length; i < l; i++){
311 if (i in this) fn.call(bind, this[i], i, this);
315 each: function(fn, bind){
316 Array.forEach(this, fn, bind);
322 // Array & Object cloning, Object merging and appending
324 var cloneOf = function(item){
325 switch (typeOf(item)){
326 case 'array': return item.clone();
327 case 'object': return Object.clone(item);
328 default: return item;
332 Array.implement('clone', function(){
333 var i = this.length, clone = new Array(i);
334 while (i--) clone[i] = cloneOf(this[i]);
338 var mergeOne = function(source, key, current){
339 switch (typeOf(current)){
341 if (typeOf(source[key]) == 'object') Object.merge(source[key], current);
342 else source[key] = Object.clone(current);
344 case 'array': source[key] = current.clone(); break;
345 default: source[key] = current;
352 merge: function(source, k, v){
353 if (typeOf(k) == 'string') return mergeOne(source, k, v);
354 for (var i = 1, l = arguments.length; i < l; i++){
355 var object = arguments[i];
356 for (var key in object) mergeOne(source, key, object[key]);
361 clone: function(object){
363 for (var key in object) clone[key] = cloneOf(object[key]);
367 append: function(original){
368 for (var i = 1, l = arguments.length; i < l; i++){
369 var extended = arguments[i] || {};
370 for (var key in extended) original[key] = extended[key];
379 ['Object', 'WhiteSpace', 'TextNode', 'Collection', 'Arguments'].each(function(name){
385 var UID = Date.now();
387 String.extend('uniqueID', function(){
388 return (UID++).toString(36);
393 var Hash = this.Hash = new Type('Hash', function(object){
394 if (typeOf(object) == 'hash') object = Object.clone(object.getClean());
395 for (var key in object) this[key] = object[key];
401 forEach: function(fn, bind){
402 Object.forEach(this, fn, bind);
405 getClean: function(){
407 for (var key in this){
408 if (this.hasOwnProperty(key)) clean[key] = this[key];
413 getLength: function(){
415 for (var key in this){
416 if (this.hasOwnProperty(key)) length++;
423 Hash.alias('each', 'forEach');
425 Object.type = Type.isObject;
427 var Native = this.Native = function(properties){
428 return new Type(properties.name, properties.initialize);
431 Native.type = Type.type;
433 Native.implement = function(objects, methods){
434 for (var i = 0; i < objects.length; i++) objects[i].implement(methods);
438 var arrayType = Array.type;
439 Array.type = function(item){
440 return instanceOf(item, Array) || arrayType(item);
443 this.$A = function(item){
444 return Array.from(item).slice();
447 this.$arguments = function(i){
453 this.$chk = function(obj){
454 return !!(obj || obj === 0);
457 this.$clear = function(timer){
459 clearInterval(timer);
463 this.$defined = function(obj){
464 return (obj != null);
467 this.$each = function(iterable, fn, bind){
468 var type = typeOf(iterable);
469 ((type == 'arguments' || type == 'collection' || type == 'array' || type == 'elements') ? Array : Object).each(iterable, fn, bind);
472 this.$empty = function(){};
474 this.$extend = function(original, extended){
475 return Object.append(original, extended);
478 this.$H = function(object){
479 return new Hash(object);
482 this.$merge = function(){
483 var args = Array.slice(arguments);
485 return Object.merge.apply(null, args);
488 this.$lambda = Function.from;
489 this.$mixin = Object.merge;
490 this.$random = Number.random;
491 this.$splat = Array.from;
492 this.$time = Date.now;
494 this.$type = function(object){
495 var type = typeOf(object);
496 if (type == 'elements') return 'array';
497 return (type == 'null') ? false : type;
500 this.$unlink = function(object){
501 switch (typeOf(object)){
502 case 'object': return Object.clone(object);
503 case 'array': return Array.clone(object);
504 case 'hash': return new Hash(object);
505 default: return object;