/*
---
name: Core
description: The heart of MooTools.
license: MIT-style license.
copyright: Copyright (c) 2006-2010 [Valerio Proietti](http://mad4milk.net/).
authors: The MooTools production team (http://mootools.net/developers/)
inspiration:
- 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)
- Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
provides: [Core, MooTools, Type, typeOf, instanceOf]
...
*/
(function(){
this.MooTools = {
version: '1.3b1.1',
build: '46ffd8e5f27aae417463d1909686cffdfefcaf18'
};
// nil
var nil = this.nil = function(item){
return (item != null && item != nil) ? item : null;
};
Function.prototype.extend = function(object){
for (var key in object) this[key] = object[key];
return this;
};
Function.prototype.implement = function(object){
for (var key in object) this.prototype[key] = object[key];
return this;
};
// typeOf, instanceOf
var typeOf = this.typeOf = function(item){
if (item == null) return 'null';
if (item.$family) return item.$family();
if (item.nodeName){
if (item.nodeType == 1) return 'element';
if (item.nodeType == 3) return (/\S/).test(item.nodeValue) ? 'textnode' : 'whitespace';
} else if (typeof item.length == 'number'){
if (item.callee) return 'arguments';
if ('item' in item) return 'collection';
}
return typeof item;
};
var instanceOf = this.instanceOf = function(item, object){
if (item == null) return false;
var constructor = item.$constructor || item.constructor;
while (constructor){
if (constructor === object) return true;
constructor = constructor.parent;
}
return item instanceof object;
};
// From
Function.from = function(item){
return (typeOf(item) == 'function') ? item : function(){
return item;
};
};
Array.from = function(item){
if (item == null) return [];
return (Type.isEnumerable(item) && typeof item != 'string') ? (typeOf(item) == 'array') ? item : Array.prototype.slice.call(item) : [item];
};
Number.from = function(item){
var number = parseFloat(item);
return isFinite(number) ? number : null;
};
String.from = function(item){
return item + '';
};
// hide, protect
Function.implement({
hide: function(){
this.$hidden = true;
return this;
},
protect: function(){
this.$protected = true;
return this;
}
});
// Type
var Type = this.Type = function(name, object){
var lower = (name || '').toLowerCase();
if (name){
var typeCheck = function(item){
return (typeOf(item) == lower);
};
Type['is' + name] = typeCheck;
if (object != null){
object.prototype.$family = (function(){
return lower;
}).hide();
/**/
object.type = typeCheck;
/**/
}
}
if (object == null) return null;
object.extend(this);
object.$constructor = Type;
object.prototype.$constructor = object;
return object;
};
var toString = Object.prototype.toString;
Type.isEnumerable = function(item){
return (item != null && typeof item.length == 'number' && toString.call(item) != '[object Function]' );
};
var hooks = {};
var hooksOf = function(object){
var type = typeOf(object.prototype);
return hooks[type] || (hooks[type] = []);
};
var implement = function(name, method){
if (method && method.$hidden) return this;
var hooks = hooksOf(this);
for (var i = 0; i < hooks.length; i++){
var hook = hooks[i];
if (typeOf(hook) == 'type') implement.call(hook, name, method);
else hook.call(this, name, method);
}
var previous = this.prototype[name];
if (previous == null || !previous.$protected) this.prototype[name] = method;
if (this[name] == null && typeOf(method) == 'function') extend.call(this, name, function(item){
return method.apply(item, Array.prototype.slice.call(arguments, 1));
});
return this;
};
var extend = function(name, method){
if (method && method.$hidden) return this;
var previous = this[name];
if (previous == null || !previous.$protected) this[name] = method;
return this;
};
Type.implement({
implement: function(a){
for (var key in a) implement.call(this, key, a[key]);
return this;
},
extend: function(object){
for (var key in object) extend.call(this, key, object[key]);
return this;
},
alias: function(object){
for (var key in object) implement.call(this, key, this.prototype[object[key]]);
return this;
},
mirror: function(hook){
hooksOf(this).push(hook);
return this;
}
});
new Type('Type', Type);
// Default Types
var force = function(name, type, methods){
var object = new Type(name, type),
prototype = object.prototype;
for (var i = 0, l = methods.length; i < l; i++){
var key = methods[i],
generic = object[key],
proto = prototype[key];
if (generic) generic.protect();
if (proto){
delete prototype[key];
prototype[key] = proto.protect();
}
}
object.implement(object.prototype);
return force;
};
force('String', String, [
'charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search',
'slice', 'split', 'substr', 'substring', 'toLowerCase', 'toUpperCase'
])('Array', Array, [
'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice',
'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight'
])('Number', Number, [
'toExponential', 'toFixed', 'toLocaleString', 'toPrecision'
])('Function', Function, [
'apply', 'call'
])('RegExp', RegExp, ['exec', 'test'])('Date', Date, ['now']);
Date.extend({now: function(){
return +(new Date);
}});
new Type('Boolean', Boolean);
// fixes NaN returning as Number
Number.prototype.$family = function(){
return isFinite(this) ? 'number' : 'null';
}.hide();
// Number.random
Number.extend({random: function(min, max){
return Math.floor(Math.random() * (max - min + 1) + min);
}});
// forEach, each
Object.extend({forEach: function(object, fn, bind){
for (var key in object) fn.call(bind, object[key], key, object);
}});
Object.each = Object.forEach;
Array.implement({forEach: function(fn, bind){
for (var i = 0, l = this.length; i < l; i++){
if (i in this) fn.call(bind, this[i], i, this);
}
}});
Array.each = Array.forEach;
Array.prototype.each = Array.prototype.forEach;
// Array & Object cloning, Object merging and appending
var cloneOf = function(item){
switch (typeOf(item)){
case 'array': return item.clone();
case 'object': return Object.clone(item);
default: return item;
}
};
Array.implement({clone: function(){
var i = this.length, clone = new Array(i);
while (i--) clone[i] = cloneOf(this[i]);
return clone;
}});
var mergeOne = function(source, key, current){
switch (typeOf(current)){
case 'object':
if (typeOf(source[key]) == 'object') Object.merge(source[key], current);
else source[key] = Object.clone(current);
break;
case 'array': source[key] = current.clone(); break;
default: source[key] = current;
}
return source;
};
Object.extend({
merge: function(source, k, v){
if (typeof k == 'string') return mergeOne(source, k, v);
for (var i = 1, l = arguments.length; i < l; i++){
var object = arguments[i];
for (var key in object) mergeOne(source, key, object[key]);
}
return source;
},
clone: function(object){
var clone = {};
for (var key in object) clone[key] = cloneOf(object[key]);
return clone;
},
append: function(original){
for (var i = 1, l = arguments.length; i < l; i++){
var extended = arguments[i] || {};
for (var key in extended) original[key] = extended[key];
}
return original;
}
});
// Object-less types
['Object', 'WhiteSpace', 'TextNode', 'Collection', 'Arguments'].each(function(name){
new Type(name);
});
var Hash = this.Hash = new Type('Hash', function(object){
if (typeOf(object) == 'hash') object = Object.clone(object.getClean());
for (var key in object) this[key] = object[key];
return this;
});
Hash.implement({
forEach: function(fn, bind){
for (var key in this){
if (this.hasOwnProperty(key)) fn.call(bind, this[key], key, this);
}
},
getClean: function(){
var clean = {};
for (var key in this){
if (this.hasOwnProperty(key)) clean[key] = this[key];
}
return clean;
},
getLength: function(){
var length = 0;
for (var key in this){
if (this.hasOwnProperty(key)) length++;
}
return length;
}
});
Hash.alias({each: 'forEach'});
/**/
Object.type = Type.isObject;
var Native = this.Native = function(properties){
return new Type(properties.name, properties.initialize);
};
Native.implement = function(objects, methods){
for (var i = 0; i < objects.length; i++) objects[i].implement(methods);
return Native;
};
(function(check){
Array.type = function(item){
return instanceOf(item, Array) || check(item);
};
})(Array.type);
this.$A = function(item){
return Array.from(item).slice();
};
this.$arguments = function(i){
return function(){
return arguments[i];
};
};
this.$chk = function(obj){
return !!(obj || obj === 0);
};
this.$clear = function(timer){
clearTimeout(timer);
clearInterval(timer);
return null;
};
this.$defined = function(obj){
return (obj != null);
};
this.$each = function(iterable, fn, bind){
var type = typeOf(iterable);
((type == 'arguments' || type == 'collection' || type == 'array') ? Array : Hash).each(iterable, fn, bind);
};
this.$empty = function(){};
this.$extend = function(original, extended){
for (var key in (extended || {})) original[key] = extended[key];
return original;
};
this.$H = function(object){
return new Hash(object);
};
this.$merge = function(){
var args = Array.slice(arguments);
args.unshift({});
return Object.merge.apply(null, args);
};
this.$lambda = Function.from;
this.$mixin = Object.merge;
this.$random = Number.random;
this.$splat = Array.from;
this.$time = Date.now;
this.$type = function(object){
var type = typeOf(object);
if (type == 'elements') return 'array';
return (type == 'null') ? false : type;
};
this.$unlink = function(object){
switch (typeOf(object)){
case 'object': return Object.clone(object);
case 'array': return Array.clone(object);
case 'hash': return new Hash(object);
default: return object;
}
};
/**/
})();
/*
---
name: Array
description: Contains Array Prototypes like each, contains, and erase.
license: MIT-style license.
requires: Type
provides: Array
...
*/
Array.implement({
invoke: function(methodName){
var args = Array.slice(arguments, 1), results = [];
for (var i = 0, j = this.length; i < j; i++){
var item = this[i];
results.push(item[methodName].apply(item, args));
}
return results;
},
every: function(fn, bind){
for (var i = 0, l = this.length; i < l; i++){
if ((i in this) && !fn.call(bind, this[i], i, this)) return false;
}
return true;
},
filter: function(fn, bind){
var results = [];
for (var i = 0, l = this.length; i < l; i++){
if ((i in this) && fn.call(bind, this[i], i, this)) results.push(this[i]);
}
return results;
},
clean: function(){
return this.filter(function(item){
return item != null;
});
},
indexOf: function(item, from){
var len = this.length;
for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){
if (this[i] === item) return i;
}
return -1;
},
map: function(fn, bind){
var results = [];
for (var i = 0, l = this.length; i < l; i++){
if (i in this) results[i] = fn.call(bind, this[i], i, this);
}
return results;
},
some: function(fn, bind){
for (var i = 0, l = this.length; i < l; i++){
if ((i in this) && fn.call(bind, this[i], i, this)) return true;
}
return false;
},
associate: function(keys){
var obj = {}, length = Math.min(this.length, keys.length);
for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
return obj;
},
link: function(object){
var result = {};
for (var i = 0, l = this.length; i < l; i++){
for (var key in object){
if (object[key](this[i])){
result[key] = this[i];
delete object[key];
break;
}
}
}
return result;
},
contains: function(item, from){
return this.indexOf(item, from) != -1;
},
append: function(array){
for (var i = 0, j = array.length; i < j; i++) this.push(array[i]);
return this;
},
getLast: function(){
return (this.length) ? this[this.length - 1] : null;
},
getRandom: function(){
return (this.length) ? this[Number.random(0, this.length - 1)] : null;
},
include: function(item){
if (!this.contains(item)) this.push(item);
return this;
},
combine: function(array){
for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
return this;
},
erase: function(item){
for (var i = this.length; i--; i){
if (this[i] === item) this.splice(i, 1);
}
return this;
},
empty: function(){
this.length = 0;
return this;
},
flatten: function(){
var array = [];
for (var i = 0, l = this.length; i < l; i++){
var type = typeOf(this[i]);
if (type == 'null') continue;
array = array.concat((type == 'array' || type == 'collection' || type == 'arguments' || instanceOf(this[i], Array)) ? Array.flatten(this[i]) : this[i]);
}
return array;
},
pick: function(){
for (var i = 0, l = this.length; i < l; i++){
if (this[i] != null) return this[i];
}
return null;
},
hexToRgb: function(array){
if (this.length != 3) return null;
var rgb = this.map(function(value){
if (value.length == 1) value += value;
return value.toInt(16);
});
return (array) ? rgb : 'rgb(' + rgb + ')';
},
rgbToHex: function(array){
if (this.length < 3) return null;
if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
var hex = [];
for (var i = 0; i < 3; i++){
var bit = (this[i] - 0).toString(16);
hex.push((bit.length == 1) ? '0' + bit : bit);
}
return (array) ? hex : '#' + hex.join('');
}
});
/**/
Array.alias({extend: 'append'});
var $pick = function(){
return Array.from(arguments).pick();
};
/**/
/*
---
name: String
description: Contains String Prototypes like camelCase, capitalize, test, and toInt.
license: MIT-style license.
requires: Type
provides: String
...
*/
String.implement({
test: function(regex, params){
return ((typeof regex == 'string') ? new RegExp(regex, params) : regex).test(this);
},
contains: function(string, separator){
return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1;
},
trim: function(){
return this.replace(/^\s+|\s+$/g, '');
},
clean: function(){
return this.replace(/\s+/g, ' ').trim();
},
camelCase: function(){
return this.replace(/-\D/g, function(match){
return match.charAt(1).toUpperCase();
});
},
hyphenate: function(){
return this.replace(/[A-Z]/g, function(match){
return ('-' + match.charAt(0).toLowerCase());
});
},
capitalize: function(){
return this.replace(/\b[a-z]/g, function(match){
return match.toUpperCase();
});
},
escapeRegExp: function(){
return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
},
toInt: function(base){
return parseInt(this, base || 10);
},
toFloat: function(){
return parseFloat(this);
},
hexToRgb: function(array){
var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
return (hex) ? hex.slice(1).hexToRgb(array) : null;
},
rgbToHex: function(array){
var rgb = this.match(/\d{1,3}/g);
return (rgb) ? rgb.rgbToHex(array) : null;
},
substitute: function(object, regexp){
return this.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
if (match.charAt(0) == '\\') return match.slice(1);
return (object[name] != undefined) ? object[name] : '';
});
}
});
/*
---
name: Number
description: Contains Number Prototypes like limit, round, times, and ceil.
license: MIT-style license.
requires: Type
provides: Number
...
*/
Number.implement({
limit: function(min, max){
return Math.min(max, Math.max(min, this));
},
round: function(precision){
precision = Math.pow(10, precision || 0).toFixed(precision < 0 ? -precision : 0);
return Math.round(this * precision) / precision;
},
times: function(fn, bind){
for (var i = 0; i < this; i++) fn.call(bind, i, this);
},
toFloat: function(){
return parseFloat(this);
},
toInt: function(base){
return parseInt(this, base || 10);
}
});
Number.alias({each: 'times'});
(function(math){
var methods = {};
math.each(function(name){
if (!Number[name]) methods[name] = function(){
return Math[name].apply(null, [this].concat(Array.from(arguments)));
};
});
Number.implement(methods);
})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
/*
---
name: Function
description: Contains Function Prototypes like create, bind, pass, and delay.
license: MIT-style license.
requires: Type
provides: Function
...
*/
Function.extend({
clear: function(timer){
clearInterval(timer);
clearTimeout(timer);
return null;
},
stab: function(){
for (var i = 0, l = arguments.length; i < l; i++){
try {
return arguments[i]();
} catch (e){}
}
return null;
}
});
Function.implement({
create: function(options){
var self = this;
options = options || {};
return function(event){
var args = options.arguments;
args = (args != undefined) ? Array.from(args) : Array.slice(arguments, (options.event) ? 1 : 0);
if (options.event) args = [event || window.event].append(args);
var returns = function(){
return self.apply(options.bind || null, args);
};
if (options.delay) return setTimeout(returns, options.delay);
if (options.periodical) return setInterval(returns, options.periodical);
if (options.attempt) return Function.stab(returns);
return returns();
};
},
run: function(args, bind){
return this.apply(bind, Array.from(args));
},
pass: function(args, bind){
return this.create({bind: bind, arguments: args});
},
bind: function(bind, args){
return this.create({bind: bind, arguments: args});
},
bindWithEvent: function(bind, args){
return this.create({bind: bind, arguments: args, event: true});
},
attempt: function(args, bind){
return this.create({bind: bind, arguments: args, attempt: true})();
},
delay: function(delay, bind, args){
return this.create({bind: bind, arguments: args, delay: delay})();
},
periodical: function(periodical, bind, args){
return this.create({bind: bind, arguments: args, periodical: periodical})();
}
});
/**/
var $try = Function.stab;
/**/
/*
---
name: Hash
description: Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects.
license: MIT-style license.
requires: Type
provides: Hash
...
*/
Hash.implement({
has: Object.prototype.hasOwnProperty,
keyOf: function(value){
for (var key in this){
if (this.hasOwnProperty(key) && this[key] === value) return key;
}
return null;
},
hasValue: function(value){
return (Hash.keyOf(this, value) !== null);
},
extend: function(properties){
Hash.each(properties || {}, function(value, key){
Hash.set(this, key, value);
}, this);
return this;
},
combine: function(properties){
Hash.each(properties || {}, function(value, key){
Hash.include(this, key, value);
}, this);
return this;
},
erase: function(key){
if (this.hasOwnProperty(key)) delete this[key];
return this;
},
get: function(key){
return (this.hasOwnProperty(key)) ? this[key] : null;
},
set: function(key, value){
if (!this[key] || this.hasOwnProperty(key)) this[key] = value;
return this;
},
empty: function(){
Hash.each(this, function(value, key){
delete this[key];
}, this);
return this;
},
include: function(key, value){
if (this[key] == undefined) this[key] = value;
return this;
},
map: function(fn, bind){
var results = new Hash;
Hash.each(this, function(value, key){
results.set(key, fn.call(bind, value, key, this));
}, this);
return results;
},
filter: function(fn, bind){
var results = new Hash;
Hash.each(this, function(value, key){
if (fn.call(bind, value, key, this)) results.set(key, value);
}, this);
return results;
},
every: function(fn, bind){
for (var key in this){
if (this.hasOwnProperty(key) && !fn.call(bind, this[key], key)) return false;
}
return true;
},
some: function(fn, bind){
for (var key in this){
if (this.hasOwnProperty(key) && fn.call(bind, this[key], key)) return true;
}
return false;
},
getKeys: function(){
var keys = [];
Hash.each(this, function(value, key){
keys.push(key);
});
return keys;
},
getValues: function(){
var values = [];
Hash.each(this, function(value){
values.push(value);
});
return values;
},
toQueryString: function(base){
var queryString = [];
Hash.each(this, function(value, key){
if (base) key = base + '[' + key + ']';
var result;
switch (typeOf(value)){
case 'object': result = Hash.toQueryString(value, key); break;
case 'array':
var qs = {};
value.each(function(val, i){
qs[i] = val;
});
result = Hash.toQueryString(qs, key);
break;
default: result = key + '=' + encodeURIComponent(value);
}
if (value != undefined) queryString.push(result);
});
return queryString.join('&');
}
});
Hash.alias({indexOf: 'keyOf', contains: 'hasValue'});
/*
---
name: Browser
description: The Browser Object. Contains Browser initialization, Window and Document, and the Browser Hash.
license: MIT-style license.
requires: [Array, Function, Number, String]
provides: [Browser, Window, Document]
...
*/
(function(){
var document = this.document;
var window = document.window = this;
var UID = 1;
this.$uid = (window.ActiveXObject) ? function(item){
return (item.uid || (item.uid = [UID++]))[0];
} : function(item){
return item.uid || (item.uid = UID++);
};
$uid(window);
$uid(document);
var UA = navigator.userAgent.toLowerCase().match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/) || [null, 'unknown', 0];
var Browser = this.Browser = {
extend: Function.prototype.extend,
name: (UA[1] == 'version') ? UA[3] : UA[1],
version: parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]),
Platform: {
name: (this.orientation != null) ? 'ipod' : (navigator.platform.toLowerCase().match(/mac|win|linux/) || ['other'])[0]
},
Features: {
xpath: !!(document.evaluate),
air: !!(window.runtime),
query: !!(document.querySelector),
json: !!(window.JSON)
},
Plugins: {}
};
Browser[Browser.name] = true;
Browser[Browser.name + parseInt(Browser.version, 10)] = true;
Browser.Platform[Browser.Platform.name] = true;
// Request
Browser.Request = (function(){
var XMLHTTP = function(){
return new XMLHttpRequest();
};
var MSXML2 = function(){
return new ActiveXObject('MSXML2.XMLHTTP');
};
var MSXML = function(){
return new ActiveXObject('Microsoft.XMLHTTP');
};
return Function.stab(function(){
XMLHTTP();
return XMLHTTP;
}, function(){
MSXML2();
return MSXML2;
}, function(){
MSXML();
return MSXML;
});
})();
Browser.Features.xhr = !!(Browser.Request);
// Flash detection
Browser.Plugins.Flash = (function(){
var version = (Function.stab(function(){
return navigator.plugins['Shockwave Flash'].description;
}, function(){
return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
}) || '0 r0').match(/\d+/g);
return {version: Number(version[0] || 0 + '.' + version[1]) || 0, build: Number(version[2]) || 0};
})();
// String scripts
Browser.exec = function(text){
if (!text) return text;
if (window.execScript){
window.execScript(text);
} else {
var script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.text = text;
document.head.appendChild(script);
document.head.removeChild(script);
}
return text;
};
String.implement({stripScripts: function(exec){
var scripts = '';
var text = this.replace(/