6 description: The heart of MooTools.
8 license: MIT-style license.
10 copyright: Copyright (c) 2006-2012 [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]
27 build: 'adb02e676407521b516ffa10d2dc6b54237a80f9'
32 var typeOf = this.typeOf = function(item){
33 if (item == null) return 'null';
34 if (item.$family != null) 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;
55 if (!item.hasOwnProperty) return false;
57 return item instanceof object;
60 // Function overloading
62 var Function = this.Function;
64 var enumerables = true;
65 for (var i in {toString: 1}) enumerables = null;
66 if (enumerables) enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor'];
68 Function.prototype.overloadSetter = function(usePlural){
70 return function(a, b){
71 if (a == null) return this;
72 if (usePlural || typeof a != 'string'){
73 for (var k in a) self.call(this, k, a[k]);
74 if (enumerables) for (var i = enumerables.length; i--;){
76 if (a.hasOwnProperty(k)) self.call(this, k, a[k]);
79 self.call(this, a, b);
85 Function.prototype.overloadGetter = function(usePlural){
89 if (usePlural || typeof a != 'string') args = a;
90 else if (arguments.length > 1) args = arguments;
93 for (var i = 0; i < args.length; i++) result[args[i]] = self.call(this, args[i]);
95 result = self.call(this, a);
101 Function.prototype.extend = function(key, value){
105 Function.prototype.implement = function(key, value){
106 this.prototype[key] = value;
111 var slice = Array.prototype.slice;
113 Function.from = function(item){
114 return (typeOf(item) == 'function') ? item : function(){
119 Array.from = function(item){
120 if (item == null) return [];
121 return (Type.isEnumerable(item) && typeof item != 'string') ? (typeOf(item) == 'array') ? item : slice.call(item) : [item];
124 Number.from = function(item){
125 var number = parseFloat(item);
126 return isFinite(number) ? number : null;
129 String.from = function(item){
143 this.$protected = true;
151 var Type = this.Type = function(name, object){
153 var lower = name.toLowerCase();
154 var typeCheck = function(item){
155 return (typeOf(item) == lower);
158 Type['is' + name] = typeCheck;
160 object.prototype.$family = (function(){
164 object.type = typeCheck;
169 if (object == null) return null;
172 object.$constructor = Type;
173 object.prototype.$constructor = object;
178 var toString = Object.prototype.toString;
180 Type.isEnumerable = function(item){
181 return (item != null && typeof item.length == 'number' && toString.call(item) != '[object Function]' );
186 var hooksOf = function(object){
187 var type = typeOf(object.prototype);
188 return hooks[type] || (hooks[type] = []);
191 var implement = function(name, method){
192 if (method && method.$hidden) return;
194 var hooks = hooksOf(this);
196 for (var i = 0; i < hooks.length; i++){
198 if (typeOf(hook) == 'type') implement.call(hook, name, method);
199 else hook.call(this, name, method);
202 var previous = this.prototype[name];
203 if (previous == null || !previous.$protected) this.prototype[name] = method;
205 if (this[name] == null && typeOf(method) == 'function') extend.call(this, name, function(item){
206 return method.apply(item, slice.call(arguments, 1));
210 var extend = function(name, method){
211 if (method && method.$hidden) return;
212 var previous = this[name];
213 if (previous == null || !previous.$protected) this[name] = method;
218 implement: implement.overloadSetter(),
220 extend: extend.overloadSetter(),
222 alias: function(name, existing){
223 implement.call(this, name, this.prototype[existing]);
226 mirror: function(hook){
227 hooksOf(this).push(hook);
233 new Type('Type', Type);
237 var force = function(name, object, methods){
238 var isType = (object != Object),
239 prototype = object.prototype;
241 if (isType) object = new Type(name, object);
243 for (var i = 0, l = methods.length; i < l; i++){
244 var key = methods[i],
245 generic = object[key],
246 proto = prototype[key];
248 if (generic) generic.protect();
249 if (isType && proto) object.implement(key, proto.protect());
253 var methodsEnumerable = prototype.propertyIsEnumerable(methods[0]);
254 object.forEachMethod = function(fn){
255 if (!methodsEnumerable) for (var i = 0, l = methods.length; i < l; i++){
256 fn.call(prototype, prototype[methods[i]], methods[i]);
258 for (var key in prototype) fn.call(prototype, prototype[key], key)
265 force('String', String, [
266 'charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search',
267 'slice', 'split', 'substr', 'substring', 'trim', 'toLowerCase', 'toUpperCase'
269 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice',
270 'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight'
271 ])('Number', Number, [
272 'toExponential', 'toFixed', 'toLocaleString', 'toPrecision'
273 ])('Function', Function, [
274 'apply', 'call', 'bind'
275 ])('RegExp', RegExp, [
277 ])('Object', Object, [
278 'create', 'defineProperty', 'defineProperties', 'keys',
279 'getPrototypeOf', 'getOwnPropertyDescriptor', 'getOwnPropertyNames',
280 'preventExtensions', 'isExtensible', 'seal', 'isSealed', 'freeze', 'isFrozen'
281 ])('Date', Date, ['now']);
283 Object.extend = extend.overloadSetter();
285 Date.extend('now', function(){
289 new Type('Boolean', Boolean);
291 // fixes NaN returning as Number
293 Number.prototype.$family = function(){
294 return isFinite(this) ? 'number' : 'null';
299 Number.extend('random', function(min, max){
300 return Math.floor(Math.random() * (max - min + 1) + min);
305 var hasOwnProperty = Object.prototype.hasOwnProperty;
306 Object.extend('forEach', function(object, fn, bind){
307 for (var key in object){
308 if (hasOwnProperty.call(object, key)) fn.call(bind, object[key], key, object);
312 Object.each = Object.forEach;
316 forEach: function(fn, bind){
317 for (var i = 0, l = this.length; i < l; i++){
318 if (i in this) fn.call(bind, this[i], i, this);
322 each: function(fn, bind){
323 Array.forEach(this, fn, bind);
329 // Array & Object cloning, Object merging and appending
331 var cloneOf = function(item){
332 switch (typeOf(item)){
333 case 'array': return item.clone();
334 case 'object': return Object.clone(item);
335 default: return item;
339 Array.implement('clone', function(){
340 var i = this.length, clone = new Array(i);
341 while (i--) clone[i] = cloneOf(this[i]);
345 var mergeOne = function(source, key, current){
346 switch (typeOf(current)){
348 if (typeOf(source[key]) == 'object') Object.merge(source[key], current);
349 else source[key] = Object.clone(current);
351 case 'array': source[key] = current.clone(); break;
352 default: source[key] = current;
359 merge: function(source, k, v){
360 if (typeOf(k) == 'string') return mergeOne(source, k, v);
361 for (var i = 1, l = arguments.length; i < l; i++){
362 var object = arguments[i];
363 for (var key in object) mergeOne(source, key, object[key]);
368 clone: function(object){
370 for (var key in object) clone[key] = cloneOf(object[key]);
374 append: function(original){
375 for (var i = 1, l = arguments.length; i < l; i++){
376 var extended = arguments[i] || {};
377 for (var key in extended) original[key] = extended[key];
386 ['Object', 'WhiteSpace', 'TextNode', 'Collection', 'Arguments'].each(function(name){
392 var UID = Date.now();
394 String.extend('uniqueID', function(){
395 return (UID++).toString(36);
400 var Hash = this.Hash = new Type('Hash', function(object){
401 if (typeOf(object) == 'hash') object = Object.clone(object.getClean());
402 for (var key in object) this[key] = object[key];
408 forEach: function(fn, bind){
409 Object.forEach(this, fn, bind);
412 getClean: function(){
414 for (var key in this){
415 if (this.hasOwnProperty(key)) clean[key] = this[key];
420 getLength: function(){
422 for (var key in this){
423 if (this.hasOwnProperty(key)) length++;
430 Hash.alias('each', 'forEach');
432 Object.type = Type.isObject;
434 var Native = this.Native = function(properties){
435 return new Type(properties.name, properties.initialize);
438 Native.type = Type.type;
440 Native.implement = function(objects, methods){
441 for (var i = 0; i < objects.length; i++) objects[i].implement(methods);
445 var arrayType = Array.type;
446 Array.type = function(item){
447 return instanceOf(item, Array) || arrayType(item);
450 this.$A = function(item){
451 return Array.from(item).slice();
454 this.$arguments = function(i){
460 this.$chk = function(obj){
461 return !!(obj || obj === 0);
464 this.$clear = function(timer){
466 clearInterval(timer);
470 this.$defined = function(obj){
471 return (obj != null);
474 this.$each = function(iterable, fn, bind){
475 var type = typeOf(iterable);
476 ((type == 'arguments' || type == 'collection' || type == 'array' || type == 'elements') ? Array : Object).each(iterable, fn, bind);
479 this.$empty = function(){};
481 this.$extend = function(original, extended){
482 return Object.append(original, extended);
485 this.$H = function(object){
486 return new Hash(object);
489 this.$merge = function(){
490 var args = Array.slice(arguments);
492 return Object.merge.apply(null, args);
495 this.$lambda = Function.from;
496 this.$mixin = Object.merge;
497 this.$random = Number.random;
498 this.$splat = Array.from;
499 this.$time = Date.now;
501 this.$type = function(object){
502 var type = typeOf(object);
503 if (type == 'elements') return 'array';
504 return (type == 'null') ? false : type;
507 this.$unlink = function(object){
508 switch (typeOf(object)){
509 case 'object': return Object.clone(object);
510 case 'array': return Array.clone(object);
511 case 'hash': return new Hash(object);
512 default: return object;