6 description: The core of MooTools, contains all the base functions and the Native and Hash implementations. Required by all the other scripts.
8 license: MIT-style license.
10 copyright: Copyright (c) 2006-2008 [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: [MooTools, Native, Hash.base, Array.each, $util]
25 'build': '008d8f0f2fcc2044e54fdd3635341aaab274e757'
28 var Native = function(options){
29 options = options || {};
30 var name = options.name;
31 var legacy = options.legacy;
32 var protect = options.protect;
33 var methods = options.implement;
34 var generics = options.generics;
35 var initialize = options.initialize;
36 var afterImplement = options.afterImplement || function(){};
37 var object = initialize || legacy;
38 generics = generics !== false;
40 object.constructor = Native;
41 object.$family = {name: 'native'};
42 if (legacy && initialize) object.prototype = legacy.prototype;
43 object.prototype.constructor = object;
46 var family = name.toLowerCase();
47 object.prototype.$family = {name: family};
48 Native.typize(object, family);
51 var add = function(obj, name, method, force){
52 if (!protect || force || !obj.prototype[name]) obj.prototype[name] = method;
53 if (generics) Native.genericize(obj, name, protect);
54 afterImplement.call(obj, name, method);
58 object.alias = function(a1, a2, a3){
59 if (typeof a1 == 'string'){
60 var pa1 = this.prototype[a1];
61 if ((a1 = pa1)) return add(this, a2, a1, a3);
63 for (var a in a1) this.alias(a, a1[a], a2);
67 object.implement = function(a1, a2, a3){
68 if (typeof a1 == 'string') return add(this, a1, a2, a3);
69 for (var p in a1) add(this, p, a1[p], a2);
73 if (methods) object.implement(methods);
78 Native.genericize = function(object, property, check){
79 if ((!check || !object[property]) && typeof object.prototype[property] == 'function') object[property] = function(){
80 var args = Array.prototype.slice.call(arguments);
81 return object.prototype[property].apply(args.shift(), args);
85 Native.implement = function(objects, properties){
86 for (var i = 0, l = objects.length; i < l; i++) objects[i].implement(properties);
89 Native.typize = function(object, family){
90 if (!object.type) object.type = function(item){
91 return ($type(item) === family);
96 var natives = {'Array': Array, 'Date': Date, 'Function': Function, 'Number': Number, 'RegExp': RegExp, 'String': String};
97 for (var n in natives) new Native({name: n, initialize: natives[n], protect: true});
99 var types = {'boolean': Boolean, 'native': Native, 'object': Object};
100 for (var t in types) Native.typize(types[t], t);
103 'Array': ["concat", "indexOf", "join", "lastIndexOf", "pop", "push", "reverse", "shift", "slice", "sort", "splice", "toString", "unshift", "valueOf"],
104 'String': ["charAt", "charCodeAt", "concat", "indexOf", "lastIndexOf", "match", "replace", "search", "slice", "split", "substr", "substring", "toLowerCase", "toUpperCase", "valueOf"]
106 for (var g in generics){
107 for (var i = generics[g].length; i--;) Native.genericize(natives[g], generics[g][i], true);
111 var Hash = new Native({
115 initialize: function(object){
116 if ($type(object) == 'hash') object = $unlink(object.getClean());
117 for (var key in object) this[key] = object[key];
125 forEach: function(fn, bind){
126 for (var key in this){
127 if (this.hasOwnProperty(key)) fn.call(bind, this[key], key, this);
131 getClean: function(){
133 for (var key in this){
134 if (this.hasOwnProperty(key)) clean[key] = this[key];
139 getLength: function(){
141 for (var key in this){
142 if (this.hasOwnProperty(key)) length++;
149 Hash.alias('forEach', 'each');
153 forEach: function(fn, bind){
154 for (var i = 0, l = this.length; i < l; i++) fn.call(bind, this[i], i, this);
159 Array.alias('forEach', 'each');
161 function $A(iterable){
163 var l = iterable.length, array = new Array(l);
164 while (l--) array[l] = iterable[l];
167 return Array.prototype.slice.call(iterable);
170 function $arguments(i){
177 return !!(obj || obj === 0);
180 function $clear(timer){
182 clearInterval(timer);
186 function $defined(obj){
187 return (obj != undefined);
190 function $each(iterable, fn, bind){
191 var type = $type(iterable);
192 ((type == 'arguments' || type == 'collection' || type == 'array') ? Array : Hash).each(iterable, fn, bind);
197 function $extend(original, extended){
198 for (var key in (extended || {})) original[key] = extended[key];
203 return new Hash(object);
206 function $lambda(value){
207 return ($type(value) == 'function') ? value : function(){
213 var args = Array.slice(arguments);
215 return $mixin.apply(null, args);
218 function $mixin(mix){
219 for (var i = 1, l = arguments.length; i < l; i++){
220 var object = arguments[i];
221 if ($type(object) != 'object') continue;
222 for (var key in object){
223 var op = object[key], mp = mix[key];
224 mix[key] = (mp && $type(op) == 'object' && $type(mp) == 'object') ? $mixin(mp, op) : $unlink(op);
231 for (var i = 0, l = arguments.length; i < l; i++){
232 if (arguments[i] != undefined) return arguments[i];
237 function $random(min, max){
238 return Math.floor(Math.random() * (max - min + 1) + min);
241 function $splat(obj){
242 var type = $type(obj);
243 return (type) ? ((type != 'array' && type != 'arguments') ? [obj] : obj) : [];
246 var $time = Date.now || function(){
251 for (var i = 0, l = arguments.length; i < l; i++){
253 return arguments[i]();
260 if (obj == undefined) return false;
261 if (obj.$family) return (obj.$family.name == 'number' && !isFinite(obj)) ? false : obj.$family.name;
263 switch (obj.nodeType){
264 case 1: return 'element';
265 case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
267 } else if (typeof obj.length == 'number'){
268 if (obj.callee) return 'arguments';
269 else if (obj.item) return 'collection';
274 function $unlink(object){
276 switch ($type(object)){
279 for (var p in object) unlinked[p] = $unlink(object[p]);
282 unlinked = new Hash(object);
286 for (var i = 0, l = object.length; i < l; i++) unlinked[i] = $unlink(object[i]);
288 default: return object;
299 description: The Browser Core. Contains Browser initialization, Window and Document, and the Browser Hash.
301 license: MIT-style license.
303 requires: [Native, $util]
305 provides: [Browser, Window, Document, $exec]
310 var Browser = $merge({
312 Engine: {name: 'unknown', version: 0},
314 Platform: {name: (window.orientation != undefined) ? 'ipod' : (navigator.platform.match(/mac|win|linux/i) || ['other'])[0].toLowerCase()},
316 Features: {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)},
323 return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925));
327 return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4);
331 return (navigator.taintEnabled) ? false : ((Browser.Features.xpath) ? ((Browser.Features.query) ? 525 : 420) : 419);
335 return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18);
342 Browser.Platform[Browser.Platform.name] = true;
344 Browser.detect = function(){
346 for (var engine in this.Engines){
347 var version = this.Engines[engine]();
349 this.Engine = {name: engine, version: version};
350 this.Engine[engine] = this.Engine[engine + version] = true;
355 return {name: engine, version: version};
361 Browser.Request = function(){
362 return $try(function(){
363 return new XMLHttpRequest();
365 return new ActiveXObject('MSXML2.XMLHTTP');
367 return new ActiveXObject('Microsoft.XMLHTTP');
371 Browser.Features.xhr = !!(Browser.Request());
373 Browser.Plugins.Flash = (function(){
374 var version = ($try(function(){
375 return navigator.plugins['Shockwave Flash'].description;
377 return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
378 }) || '0 r0').match(/\d+/g);
379 return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0};
382 function $exec(text){
383 if (!text) return text;
384 if (window.execScript){
385 window.execScript(text);
387 var script = document.createElement('script');
388 script.setAttribute('type', 'text/javascript');
389 script[(Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerText' : 'text'] = text;
390 document.head.appendChild(script);
391 document.head.removeChild(script);
398 var $uid = (Browser.Engine.trident) ? function(item){
399 return (item.uid || (item.uid = [Native.UID++]))[0];
401 return item.uid || (item.uid = Native.UID++);
404 var Window = new Native({
408 legacy: (Browser.Engine.trident) ? null: window.Window,
410 initialize: function(win){
413 win.Element = $empty;
414 if (Browser.Engine.webkit) win.document.createElement("iframe"); //fixes safari 2
415 win.Element.prototype = (Browser.Engine.webkit) ? window["[[DOMElement.prototype]]"] : {};
417 win.document.window = win;
418 return $extend(win, Window.Prototype);
421 afterImplement: function(property, value){
422 window[property] = Window.Prototype[property] = value;
427 Window.Prototype = {$family: {name: 'window'}};
431 var Document = new Native({
435 legacy: (Browser.Engine.trident) ? null: window.Document,
437 initialize: function(doc){
439 doc.head = doc.getElementsByTagName('head')[0];
440 doc.html = doc.getElementsByTagName('html')[0];
441 if (Browser.Engine.trident && Browser.Engine.version <= 4) $try(function(){
442 doc.execCommand("BackgroundImageCache", false, true);
444 if (Browser.Engine.trident) doc.window.attachEvent('onunload', function(){
445 doc.window.detachEvent('onunload', arguments.callee);
446 doc.head = doc.html = doc.window = null;
448 return $extend(doc, Document.Prototype);
451 afterImplement: function(property, value){
452 document[property] = Document.Prototype[property] = value;
457 Document.Prototype = {$family: {name: 'document'}};
459 new Document(document);
467 description: Contains Array Prototypes like each, contains, and erase.
469 license: MIT-style license.
471 requires: [$util, Array.each]
480 every: function(fn, bind){
481 for (var i = 0, l = this.length; i < l; i++){
482 if (!fn.call(bind, this[i], i, this)) return false;
487 filter: function(fn, bind){
489 for (var i = 0, l = this.length; i < l; i++){
490 if (fn.call(bind, this[i], i, this)) results.push(this[i]);
496 return this.filter($defined);
499 indexOf: function(item, from){
500 var len = this.length;
501 for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){
502 if (this[i] === item) return i;
507 map: function(fn, bind){
509 for (var i = 0, l = this.length; i < l; i++) results[i] = fn.call(bind, this[i], i, this);
513 some: function(fn, bind){
514 for (var i = 0, l = this.length; i < l; i++){
515 if (fn.call(bind, this[i], i, this)) return true;
520 associate: function(keys){
521 var obj = {}, length = Math.min(this.length, keys.length);
522 for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
526 link: function(object){
528 for (var i = 0, l = this.length; i < l; i++){
529 for (var key in object){
530 if (object[key](this[i])){
531 result[key] = this[i];
540 contains: function(item, from){
541 return this.indexOf(item, from) != -1;
544 extend: function(array){
545 for (var i = 0, j = array.length; i < j; i++) this.push(array[i]);
550 return (this.length) ? this[this.length - 1] : null;
553 getRandom: function(){
554 return (this.length) ? this[$random(0, this.length - 1)] : null;
557 include: function(item){
558 if (!this.contains(item)) this.push(item);
562 combine: function(array){
563 for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
567 erase: function(item){
568 for (var i = this.length; i--; i){
569 if (this[i] === item) this.splice(i, 1);
581 for (var i = 0, l = this.length; i < l; i++){
582 var type = $type(this[i]);
584 array = array.concat((type == 'array' || type == 'collection' || type == 'arguments') ? Array.flatten(this[i]) : this[i]);
589 hexToRgb: function(array){
590 if (this.length != 3) return null;
591 var rgb = this.map(function(value){
592 if (value.length == 1) value += value;
593 return value.toInt(16);
595 return (array) ? rgb : 'rgb(' + rgb + ')';
598 rgbToHex: function(array){
599 if (this.length < 3) return null;
600 if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
602 for (var i = 0; i < 3; i++){
603 var bit = (this[i] - 0).toString(16);
604 hex.push((bit.length == 1) ? '0' + bit : bit);
606 return (array) ? hex : '#' + hex.join('');
617 description: Contains Function Prototypes like create, bind, pass, and delay.
619 license: MIT-style license.
621 requires: [Native, $util]
629 delete Function.prototype.bind;
634 extend: function(properties){
635 for (var property in properties) this[property] = properties[property];
639 create: function(options){
641 options = options || {};
642 return function(event){
643 var args = options.arguments;
644 args = (args != undefined) ? $splat(args) : Array.slice(arguments, (options.event) ? 1 : 0);
645 if (options.event) args = [event || window.event].extend(args);
646 var returns = function(){
647 return self.apply(options.bind || null, args);
649 if (options.delay) return setTimeout(returns, options.delay);
650 if (options.periodical) return setInterval(returns, options.periodical);
651 if (options.attempt) return $try(returns);
656 run: function(args, bind){
657 return this.apply(bind, $splat(args));
660 pass: function(args, bind){
661 return this.create({bind: bind, arguments: args});
664 bind: function(bind, args){
665 return this.create({bind: bind, arguments: args});
668 bindWithEvent: function(bind, args){
669 return this.create({bind: bind, arguments: args, event: true});
672 attempt: function(args, bind){
673 return this.create({bind: bind, arguments: args, attempt: true})();
676 delay: function(delay, bind, args){
677 return this.create({bind: bind, arguments: args, delay: delay})();
680 periodical: function(periodical, bind, args){
681 return this.create({bind: bind, arguments: args, periodical: periodical})();
692 description: Contains Number Prototypes like limit, round, times, and ceil.
694 license: MIT-style license.
696 requires: [Native, $util]
705 limit: function(min, max){
706 return Math.min(max, Math.max(min, this));
709 round: function(precision){
710 precision = Math.pow(10, precision || 0);
711 return Math.round(this * precision) / precision;
714 times: function(fn, bind){
715 for (var i = 0; i < this; i++) fn.call(bind, i, this);
719 return parseFloat(this);
722 toInt: function(base){
723 return parseInt(this, base || 10);
728 Number.alias('times', 'each');
732 math.each(function(name){
733 if (!Number[name]) methods[name] = function(){
734 return Math[name].apply(null, [this].concat($A(arguments)));
737 Number.implement(methods);
738 })(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
746 description: Contains String Prototypes like camelCase, capitalize, test, and toInt.
748 license: MIT-style license.
759 test: function(regex, params){
760 return ((typeof regex == 'string') ? new RegExp(regex, params) : regex).test(this);
763 contains: function(string, separator){
764 return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1;
768 return this.replace(/^\s+|\s+$/g, '');
772 return this.replace(/\s+/g, ' ').trim();
775 camelCase: function(){
776 return this.replace(/-\D/g, function(match){
777 return match.charAt(1).toUpperCase();
781 hyphenate: function(){
782 return this.replace(/[A-Z]/g, function(match){
783 return ('-' + match.charAt(0).toLowerCase());
787 capitalize: function(){
788 return this.replace(/\b[a-z]/g, function(match){
789 return match.toUpperCase();
793 escapeRegExp: function(){
794 return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
797 toInt: function(base){
798 return parseInt(this, base || 10);
802 return parseFloat(this);
805 hexToRgb: function(array){
806 var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
807 return (hex) ? hex.slice(1).hexToRgb(array) : null;
810 rgbToHex: function(array){
811 var rgb = this.match(/\d{1,3}/g);
812 return (rgb) ? rgb.rgbToHex(array) : null;
815 stripScripts: function(option){
817 var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){
818 scripts += arguments[1] + '\n';
821 if (option === true) $exec(scripts);
822 else if ($type(option) == 'function') option(scripts, text);
826 substitute: function(object, regexp){
827 return this.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
828 if (match.charAt(0) == '\\') return match.slice(1);
829 return (object[name] != undefined) ? object[name] : '';
841 description: Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects.
843 license: MIT-style license.
854 has: Object.prototype.hasOwnProperty,
856 keyOf: function(value){
857 for (var key in this){
858 if (this.hasOwnProperty(key) && this[key] === value) return key;
863 hasValue: function(value){
864 return (Hash.keyOf(this, value) !== null);
867 extend: function(properties){
868 Hash.each(properties || {}, function(value, key){
869 Hash.set(this, key, value);
874 combine: function(properties){
875 Hash.each(properties || {}, function(value, key){
876 Hash.include(this, key, value);
881 erase: function(key){
882 if (this.hasOwnProperty(key)) delete this[key];
887 return (this.hasOwnProperty(key)) ? this[key] : null;
890 set: function(key, value){
891 if (!this[key] || this.hasOwnProperty(key)) this[key] = value;
896 Hash.each(this, function(value, key){
902 include: function(key, value){
903 if (this[key] == undefined) this[key] = value;
907 map: function(fn, bind){
908 var results = new Hash;
909 Hash.each(this, function(value, key){
910 results.set(key, fn.call(bind, value, key, this));
915 filter: function(fn, bind){
916 var results = new Hash;
917 Hash.each(this, function(value, key){
918 if (fn.call(bind, value, key, this)) results.set(key, value);
923 every: function(fn, bind){
924 for (var key in this){
925 if (this.hasOwnProperty(key) && !fn.call(bind, this[key], key)) return false;
930 some: function(fn, bind){
931 for (var key in this){
932 if (this.hasOwnProperty(key) && fn.call(bind, this[key], key)) return true;
939 Hash.each(this, function(value, key){
945 getValues: function(){
947 Hash.each(this, function(value){
953 toQueryString: function(base){
954 var queryString = [];
955 Hash.each(this, function(value, key){
956 if (base) key = base + '[' + key + ']';
958 switch ($type(value)){
959 case 'object': result = Hash.toQueryString(value, key); break;
962 value.each(function(val, i){
965 result = Hash.toQueryString(qs, key);
967 default: result = key + '=' + encodeURIComponent(value);
969 if (value != undefined) queryString.push(result);
972 return queryString.join('&');
977 Hash.alias({keyOf: 'indexOf', hasValue: 'contains'});
985 description: Contains the Event Class, to make the event object cross-browser.
987 license: MIT-style license.
989 requires: [Window, Document, Hash, Array, Function, String]
996 var Event = new Native({
1000 initialize: function(event, win){
1001 win = win || window;
1002 var doc = win.document;
1003 event = event || win.event;
1004 if (event.$extended) return event;
1005 this.$extended = true;
1006 var type = event.type;
1007 var target = event.target || event.srcElement;
1008 while (target && target.nodeType == 3) target = target.parentNode;
1010 if (type.test(/key/)){
1011 var code = event.which || event.keyCode;
1012 var key = Event.Keys.keyOf(code);
1013 if (type == 'keydown'){
1014 var fKey = code - 111;
1015 if (fKey > 0 && fKey < 13) key = 'f' + fKey;
1017 key = key || String.fromCharCode(code).toLowerCase();
1018 } else if (type.match(/(click|mouse|menu)/i)){
1019 doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
1021 x: event.pageX || event.clientX + doc.scrollLeft,
1022 y: event.pageY || event.clientY + doc.scrollTop
1025 x: (event.pageX) ? event.pageX - win.pageXOffset : event.clientX,
1026 y: (event.pageY) ? event.pageY - win.pageYOffset : event.clientY
1028 if (type.match(/DOMMouseScroll|mousewheel/)){
1029 var wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
1031 var rightClick = (event.which == 3) || (event.button == 2);
1033 if (type.match(/over|out/)){
1035 case 'mouseover': related = event.relatedTarget || event.fromElement; break;
1036 case 'mouseout': related = event.relatedTarget || event.toElement;
1039 while (related && related.nodeType == 3) related = related.parentNode;
1041 }).create({attempt: Browser.Engine.gecko})()) related = false;
1045 return $extend(this, {
1051 rightClick: rightClick,
1055 relatedTarget: related,
1061 shift: event.shiftKey,
1062 control: event.ctrlKey,
1070 Event.Keys = new Hash({
1086 return this.stopPropagation().preventDefault();
1089 stopPropagation: function(){
1090 if (this.event.stopPropagation) this.event.stopPropagation();
1091 else this.event.cancelBubble = true;
1095 preventDefault: function(){
1096 if (this.event.preventDefault) this.event.preventDefault();
1097 else this.event.returnValue = false;
1109 description: Contains the Class Function for easily creating, extending, and implementing reusable Classes.
1111 license: MIT-style license.
1113 requires: [$util, Native, Array, String, Function, Number, Hash]
1120 function Class(params){
1122 if (params instanceof Function) params = {initialize: params};
1124 var newClass = function(){
1126 if (newClass._prototyping) return this;
1127 this._current = $empty;
1128 var value = (this.initialize) ? this.initialize.apply(this, arguments) : this;
1129 delete this._current; delete this.caller;
1133 newClass.implement(params);
1135 newClass.constructor = Class;
1136 newClass.prototype.constructor = newClass;
1142 Function.prototype.protect = function(){
1143 this._protected = true;
1147 Object.reset = function(object, key){
1150 for (var p in object) Object.reset(object, p);
1156 switch ($type(object[key])){
1158 var F = function(){};
1159 F.prototype = object[key];
1161 object[key] = Object.reset(i);
1163 case 'array': object[key] = $unlink(object[key]); break;
1170 new Native({name: 'Class', initialize: Class}).extend({
1172 instantiate: function(F){
1173 F._prototyping = true;
1175 delete F._prototyping;
1179 wrap: function(self, key, method){
1180 if (method._origin) method = method._origin;
1183 if (method._protected && this._current == null) throw new Error('The method "' + key + '" cannot be called.');
1184 var caller = this.caller, current = this._current;
1185 this.caller = current; this._current = arguments.callee;
1186 var result = method.apply(this, arguments);
1187 this._current = current; this.caller = caller;
1189 }.extend({_owner: self, _origin: method, _name: key});
1197 implement: function(key, value){
1199 if ($type(key) == 'object'){
1200 for (var p in key) this.implement(p, key[p]);
1204 var mutator = Class.Mutators[key];
1207 value = mutator.call(this, value);
1208 if (value == null) return this;
1211 var proto = this.prototype;
1213 switch ($type(value)){
1216 if (value._hidden) return this;
1217 proto[key] = Class.wrap(this, key, value);
1221 var previous = proto[key];
1222 if ($type(previous) == 'object') $mixin(previous, value);
1223 else proto[key] = $unlink(value);
1227 proto[key] = $unlink(value);
1230 default: proto[key] = value;
1242 Extends: function(parent){
1244 this.parent = parent;
1245 this.prototype = Class.instantiate(parent);
1247 this.implement('parent', function(){
1248 var name = this.caller._name, previous = this.caller._owner.parent.prototype[name];
1249 if (!previous) throw new Error('The method "' + name + '" has no parent.');
1250 return previous.apply(this, arguments);
1255 Implements: function(items){
1256 $splat(items).each(function(item){
1257 if (item instanceof Function) item = Class.instantiate(item);
1258 this.implement(item);
1271 description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.
1273 license: MIT-style license.
1277 provides: [Chain, Events, Options, Class.Extras]
1282 var Chain = new Class({
1287 this.$chain.extend(Array.flatten(arguments));
1291 callChain: function(){
1292 return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false;
1295 clearChain: function(){
1296 this.$chain.empty();
1302 var Events = new Class({
1306 addEvent: function(type, fn, internal){
1307 type = Events.removeOn(type);
1309 this.$events[type] = this.$events[type] || [];
1310 this.$events[type].include(fn);
1311 if (internal) fn.internal = true;
1316 addEvents: function(events){
1317 for (var type in events) this.addEvent(type, events[type]);
1321 fireEvent: function(type, args, delay){
1322 type = Events.removeOn(type);
1323 if (!this.$events || !this.$events[type]) return this;
1324 this.$events[type].each(function(fn){
1325 fn.create({'bind': this, 'delay': delay, 'arguments': args})();
1330 removeEvent: function(type, fn){
1331 type = Events.removeOn(type);
1332 if (!this.$events[type]) return this;
1333 if (!fn.internal) this.$events[type].erase(fn);
1337 removeEvents: function(events){
1339 if ($type(events) == 'object'){
1340 for (type in events) this.removeEvent(type, events[type]);
1343 if (events) events = Events.removeOn(events);
1344 for (type in this.$events){
1345 if (events && events != type) continue;
1346 var fns = this.$events[type];
1347 for (var i = fns.length; i--; i) this.removeEvent(type, fns[i]);
1354 Events.removeOn = function(string){
1355 return string.replace(/^on([A-Z])/, function(full, first){
1356 return first.toLowerCase();
1360 var Options = new Class({
1362 setOptions: function(){
1363 this.options = $merge.run([this.options].extend(arguments));
1364 if (!this.addEvent) return this;
1365 for (var option in this.options){
1366 if ($type(this.options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;
1367 this.addEvent(option, this.options[option]);
1368 delete this.options[option];
1382 description: Class for creating, reading, and deleting browser Cookies.
1384 license: MIT-style license.
1386 credits: Based on the functions by Peter-Paul Koch (http://quirksmode.org).
1395 var Cookie = new Class({
1397 Implements: Options,
1407 initialize: function(key, options){
1409 this.setOptions(options);
1412 write: function(value){
1413 value = encodeURIComponent(value);
1414 if (this.options.domain) value += '; domain=' + this.options.domain;
1415 if (this.options.path) value += '; path=' + this.options.path;
1416 if (this.options.duration){
1417 var date = new Date();
1418 date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000);
1419 value += '; expires=' + date.toGMTString();
1421 if (this.options.secure) value += '; secure';
1422 this.options.document.cookie = this.key + '=' + value;
1427 var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)');
1428 return (value) ? decodeURIComponent(value[1]) : null;
1431 dispose: function(){
1432 new Cookie(this.key, $merge(this.options, {duration: -1})).write('');
1438 Cookie.write = function(key, value, options){
1439 return new Cookie(key, options).write(value);
1442 Cookie.read = function(key){
1443 return new Cookie(key).read();
1446 Cookie.dispose = function(key, options){
1447 return new Cookie(key, options).dispose();
1456 description: Powerful all purpose Request Class. Uses XMLHTTPRequest.
1458 license: MIT-style license.
1460 requires: [Element, Chain, Events, Options, Browser]
1467 var Request = new Class({
1469 Implements: [Chain, Events, Options],
1477 onException: $empty,*/
1481 'X-Requested-With': 'XMLHttpRequest',
1482 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
1493 evalResponse: false,
1497 initialize: function(options){
1498 this.xhr = new Browser.Request();
1499 this.setOptions(options);
1500 this.options.isSuccess = this.options.isSuccess || this.isSuccess;
1501 this.headers = new Hash(this.options.headers);
1504 onStateChange: function(){
1505 if (this.xhr.readyState != 4 || !this.running) return;
1506 this.running = false;
1509 this.status = this.xhr.status;
1511 this.xhr.onreadystatechange = $empty;
1512 if (this.options.isSuccess.call(this, this.status)){
1513 this.response = {text: this.xhr.responseText, xml: this.xhr.responseXML};
1514 this.success(this.response.text, this.response.xml);
1516 this.response = {text: null, xml: null};
1521 isSuccess: function(){
1522 return ((this.status >= 200) && (this.status < 300));
1525 processScripts: function(text){
1526 if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return $exec(text);
1527 return text.stripScripts(this.options.evalScripts);
1530 success: function(text, xml){
1531 this.onSuccess(this.processScripts(text), xml);
1534 onSuccess: function(){
1535 this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain();
1538 failure: function(){
1542 onFailure: function(){
1543 this.fireEvent('complete').fireEvent('failure', this.xhr);
1546 setHeader: function(name, value){
1547 this.headers.set(name, value);
1551 getHeader: function(name){
1552 return $try(function(){
1553 return this.xhr.getResponseHeader(name);
1558 if (!this.running) return true;
1559 switch (this.options.link){
1560 case 'cancel': this.cancel(); return true;
1561 case 'chain': this.chain(this.caller.bind(this, arguments)); return false;
1566 send: function(options){
1567 if (!this.check(options)) return this;
1568 this.running = true;
1570 var type = $type(options);
1571 if (type == 'string' || type == 'element') options = {data: options};
1573 var old = this.options;
1574 options = $extend({data: old.data, url: old.url, method: old.method}, options);
1575 var data = options.data, url = String(options.url), method = options.method.toLowerCase();
1577 switch ($type(data)){
1578 case 'element': data = document.id(data).toQueryString(); break;
1579 case 'object': case 'hash': data = Hash.toQueryString(data);
1582 if (this.options.format){
1583 var format = 'format=' + this.options.format;
1584 data = (data) ? format + '&' + data : format;
1587 if (this.options.emulation && !['get', 'post'].contains(method)){
1588 var _method = '_method=' + method;
1589 data = (data) ? _method + '&' + data : _method;
1593 if (this.options.urlEncoded && method == 'post'){
1594 var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
1595 this.headers.set('Content-type', 'application/x-www-form-urlencoded' + encoding);
1598 if (this.options.noCache){
1599 var noCache = 'noCache=' + new Date().getTime();
1600 data = (data) ? noCache + '&' + data : noCache;
1603 var trimPosition = url.lastIndexOf('/');
1604 if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition);
1606 if (data && method == 'get'){
1607 url = url + (url.contains('?') ? '&' : '?') + data;
1611 this.xhr.open(method.toUpperCase(), url, this.options.async);
1613 this.xhr.onreadystatechange = this.onStateChange.bind(this);
1615 this.headers.each(function(value, key){
1617 this.xhr.setRequestHeader(key, value);
1619 this.fireEvent('exception', [key, value]);
1623 this.fireEvent('request');
1624 this.xhr.send(data);
1625 if (!this.options.async) this.onStateChange();
1630 if (!this.running) return this;
1631 this.running = false;
1633 this.xhr.onreadystatechange = $empty;
1634 this.xhr = new Browser.Request();
1635 this.fireEvent('cancel');
1644 ['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){
1645 methods[method] = function(){
1646 var params = Array.link(arguments, {url: String.type, data: $defined});
1647 return this.send($extend(params, {method: method}));
1651 Request.implement(methods);