Subversion Repositories wimsdev

Rev

Blame | Last modification | View Log | RSS feed

  1. //MooTools, My Object Oriented Javascript Tools. Copyright (c) 2006 Valerio Proietti, <http://mad4milk.net>, MIT Style License.
  2.  
  3. var MooTools = {
  4.         version: '1.11'
  5. };
  6.  
  7. function $defined(obj){
  8.         return (obj != undefined);
  9. };
  10.  
  11. function $type(obj){
  12.         if (!$defined(obj)) return false;
  13.         if (obj.htmlElement) return 'element';
  14.         var type = typeof obj;
  15.         if (type == 'object' && obj.nodeName){
  16.                 switch(obj.nodeType){
  17.                         case 1: return 'element';
  18.                         case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
  19.                 }
  20.         }
  21.         if (type == 'object' || type == 'function'){
  22.                 switch(obj.constructor){
  23.                         case Array: return 'array';
  24.                         case RegExp: return 'regexp';
  25.                         case Class: return 'class';
  26.                 }
  27.                 if (typeof obj.length == 'number'){
  28.                         if (obj.item) return 'collection';
  29.                         if (obj.callee) return 'arguments';
  30.                 }
  31.         }
  32.         return type;
  33. };
  34.  
  35. function $merge(){
  36.         var mix = {};
  37.         for (var i = 0; i < arguments.length; i++){
  38.                 for (var property in arguments[i]){
  39.                         var ap = arguments[i][property];
  40.                         var mp = mix[property];
  41.                         if (mp && $type(ap) == 'object' && $type(mp) == 'object') mix[property] = $merge(mp, ap);
  42.                         else mix[property] = ap;
  43.                 }
  44.         }
  45.         return mix;
  46. };
  47.  
  48. var $extend = function(){
  49.         var args = arguments;
  50.         if (!args[1]) args = [this, args[0]];
  51.         for (var property in args[1]) args[0][property] = args[1][property];
  52.         return args[0];
  53. };
  54.  
  55. var $native = function(){
  56.         for (var i = 0, l = arguments.length; i < l; i++){
  57.                 arguments[i].extend = function(props){
  58.                         for (var prop in props){
  59.                                 if (!this.prototype[prop]) this.prototype[prop] = props[prop];
  60.                                 if (!this[prop]) this[prop] = $native.generic(prop);
  61.                         }
  62.                 };
  63.         }
  64. };
  65.  
  66. $native.generic = function(prop){
  67.         return function(bind){
  68.                 return this.prototype[prop].apply(bind, Array.prototype.slice.call(arguments, 1));
  69.         };
  70. };
  71.  
  72. $native(Function, Array, String, Number);
  73.  
  74. function $chk(obj){
  75.         return !!(obj || obj === 0);
  76. };
  77.  
  78. function $pick(obj, picked){
  79.         return $defined(obj) ? obj : picked;
  80. };
  81.  
  82. function $random(min, max){
  83.         return Math.floor(Math.random() * (max - min + 1) + min);
  84. };
  85.  
  86. function $time(){
  87.         return new Date().getTime();
  88. };
  89.  
  90. function $clear(timer){
  91.         clearTimeout(timer);
  92.         clearInterval(timer);
  93.         return null;
  94. };
  95.  
  96. var Abstract = function(obj){
  97.         obj = obj || {};
  98.         obj.extend = $extend;
  99.         return obj;
  100. };
  101.  
  102. var Window = new Abstract(window);
  103. var Document = new Abstract(document);
  104. document.head = document.getElementsByTagName('head')[0];
  105.  
  106. window.xpath = !!(document.evaluate);
  107. if (window.ActiveXObject) window.ie = window[window.XMLHttpRequest ? 'ie7' : 'ie6'] = true;
  108. else if (document.childNodes && !document.all && !navigator.taintEnabled) window.webkit = window[window.xpath ? 'webkit420' : 'webkit419'] = true;
  109. else if (document.getBoxObjectFor != null) window.gecko = true;
  110.  
  111. window.khtml = window.webkit;
  112.  
  113. Object.extend = $extend;
  114.  
  115. if (typeof HTMLElement == 'undefined'){
  116.         var HTMLElement = function(){};
  117.         if (window.webkit) document.createElement("iframe");
  118.         HTMLElement.prototype = (window.webkit) ? window["[[DOMElement.prototype]]"] : {};
  119. }
  120. HTMLElement.prototype.htmlElement = function(){};
  121.  
  122. if (window.ie6) try {document.execCommand("BackgroundImageCache", false, true);} catch(e){};
  123.  
  124. var Class = function(properties){
  125.         var klass = function(){
  126.                 return (arguments[0] !== null && this.initialize && $type(this.initialize) == 'function') ? this.initialize.apply(this, arguments) : this;
  127.         };
  128.         $extend(klass, this);
  129.         klass.prototype = properties;
  130.         klass.constructor = Class;
  131.         return klass;
  132. };
  133.  
  134. Class.empty = function(){};
  135.  
  136. Class.prototype = {
  137.  
  138.         extend: function(properties){
  139.                 var proto = new this(null);
  140.                 for (var property in properties){
  141.                         var pp = proto[property];
  142.                         proto[property] = Class.Merge(pp, properties[property]);
  143.                 }
  144.                 return new Class(proto);
  145.         },
  146.  
  147.         implement: function(){
  148.                 for (var i = 0, l = arguments.length; i < l; i++) $extend(this.prototype, arguments[i]);
  149.         }
  150.  
  151. };
  152.  
  153. Class.Merge = function(previous, current){
  154.         if (previous && previous != current){
  155.                 var type = $type(current);
  156.                 if (type != $type(previous)) return current;
  157.                 switch(type){
  158.                         case 'function':
  159.                                 var merged = function(){
  160.                                         this.parent = arguments.callee.parent;
  161.                                         return current.apply(this, arguments);
  162.                                 };
  163.                                 merged.parent = previous;
  164.                                 return merged;
  165.                         case 'object': return $merge(previous, current);
  166.                 }
  167.         }
  168.         return current;
  169. };
  170.  
  171. var Chain = new Class({
  172.  
  173.         chain: function(fn){
  174.                 this.chains = this.chains || [];
  175.                 this.chains.push(fn);
  176.                 return this;
  177.         },
  178.  
  179.         callChain: function(){
  180.                 if (this.chains && this.chains.length) this.chains.shift().delay(10, this);
  181.         },
  182.  
  183.         clearChain: function(){
  184.                 this.chains = [];
  185.         }
  186.  
  187. });
  188.  
  189. var Events = new Class({
  190.  
  191.         addEvent: function(type, fn){
  192.                 if (fn != Class.empty){
  193.                         this.$events = this.$events || {};
  194.                         this.$events[type] = this.$events[type] || [];
  195.                         this.$events[type].include(fn);
  196.                 }
  197.                 return this;
  198.         },
  199.  
  200.         fireEvent: function(type, args, delay){
  201.                 if (this.$events && this.$events[type]){
  202.                         this.$events[type].each(function(fn){
  203.                                 fn.create({'bind': this, 'delay': delay, 'arguments': args})();
  204.                         }, this);
  205.                 }
  206.                 return this;
  207.         },
  208.  
  209.         removeEvent: function(type, fn){
  210.                 if (this.$events && this.$events[type]) this.$events[type].remove(fn);
  211.                 return this;
  212.         }
  213.  
  214. });
  215.  
  216. var Options = new Class({
  217.  
  218.         setOptions: function(){
  219.                 this.options = $merge.apply(null, [this.options].extend(arguments));
  220.                 if (this.addEvent){
  221.                         for (var option in this.options){
  222.                                 if ($type(this.options[option] == 'function') && (/^on[A-Z]/).test(option)) this.addEvent(option, this.options[option]);
  223.                         }
  224.                 }
  225.                 return this;
  226.         }
  227.  
  228. });
  229.  
  230. Array.extend({
  231.  
  232.         forEach: function(fn, bind){
  233.                 for (var i = 0, j = this.length; i < j; i++) fn.call(bind, this[i], i, this);
  234.         },
  235.  
  236.         filter: function(fn, bind){
  237.                 var results = [];
  238.                 for (var i = 0, j = this.length; i < j; i++){
  239.                         if (fn.call(bind, this[i], i, this)) results.push(this[i]);
  240.                 }
  241.                 return results;
  242.         },
  243.  
  244.         map: function(fn, bind){
  245.                 var results = [];
  246.                 for (var i = 0, j = this.length; i < j; i++) results[i] = fn.call(bind, this[i], i, this);
  247.                 return results;
  248.         },
  249.  
  250.         every: function(fn, bind){
  251.                 for (var i = 0, j = this.length; i < j; i++){
  252.                         if (!fn.call(bind, this[i], i, this)) return false;
  253.                 }
  254.                 return true;
  255.         },
  256.  
  257.         some: function(fn, bind){
  258.                 for (var i = 0, j = this.length; i < j; i++){
  259.                         if (fn.call(bind, this[i], i, this)) return true;
  260.                 }
  261.                 return false;
  262.         },
  263.  
  264.         indexOf: function(item, from){
  265.                 var len = this.length;
  266.                 for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){
  267.                         if (this[i] === item) return i;
  268.                 }
  269.                 return -1;
  270.         },
  271.  
  272.         copy: function(start, length){
  273.                 start = start || 0;
  274.                 if (start < 0) start = this.length + start;
  275.                 length = length || (this.length - start);
  276.                 var newArray = [];
  277.                 for (var i = 0; i < length; i++) newArray[i] = this[start++];
  278.                 return newArray;
  279.         },
  280.  
  281.         remove: function(item){
  282.                 var i = 0;
  283.                 var len = this.length;
  284.                 while (i < len){
  285.                         if (this[i] === item){
  286.                                 this.splice(i, 1);
  287.                                 len--;
  288.                         } else {
  289.                                 i++;
  290.                         }
  291.                 }
  292.                 return this;
  293.         },
  294.  
  295.         contains: function(item, from){
  296.                 return this.indexOf(item, from) != -1;
  297.         },
  298.  
  299.         associate: function(keys){
  300.                 var obj = {}, length = Math.min(this.length, keys.length);
  301.                 for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
  302.                 return obj;
  303.         },
  304.  
  305.         extend: function(array){
  306.                 for (var i = 0, j = array.length; i < j; i++) this.push(array[i]);
  307.                 return this;
  308.         },
  309.  
  310.         merge: function(array){
  311.                 for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
  312.                 return this;
  313.         },
  314.  
  315.         include: function(item){
  316.                 if (!this.contains(item)) this.push(item);
  317.                 return this;
  318.         },
  319.  
  320.         getRandom: function(){
  321.                 return this[$random(0, this.length - 1)] || null;
  322.         },
  323.  
  324.         getLast: function(){
  325.                 return this[this.length - 1] || null;
  326.         }
  327.  
  328. });
  329.  
  330. Array.prototype.each = Array.prototype.forEach;
  331. Array.each = Array.forEach;
  332.  
  333. function $A(array){
  334.         return Array.copy(array);
  335. };
  336.  
  337. function $each(iterable, fn, bind){
  338.         if (iterable && typeof iterable.length == 'number' && $type(iterable) != 'object'){
  339.                 Array.forEach(iterable, fn, bind);
  340.         } else {
  341.                  for (var name in iterable) fn.call(bind || iterable, iterable[name], name);
  342.         }
  343. };
  344.  
  345. Array.prototype.test = Array.prototype.contains;
  346.  
  347. String.extend({
  348.  
  349.         test: function(regex, params){
  350.                 return (($type(regex) == 'string') ? new RegExp(regex, params) : regex).test(this);
  351.         },
  352.  
  353.         toInt: function(){
  354.                 return parseInt(this, 10);
  355.         },
  356.  
  357.         toFloat: function(){
  358.                 return parseFloat(this);
  359.         },
  360.  
  361.         camelCase: function(){
  362.                 return this.replace(/-\D/g, function(match){
  363.                         return match.charAt(1).toUpperCase();
  364.                 });
  365.         },
  366.  
  367.         hyphenate: function(){
  368.                 return this.replace(/\w[A-Z]/g, function(match){
  369.                         return (match.charAt(0) + '-' + match.charAt(1).toLowerCase());
  370.                 });
  371.         },
  372.  
  373.         capitalize: function(){
  374.                 return this.replace(/\b[a-z]/g, function(match){
  375.                         return match.toUpperCase();
  376.                 });
  377.         },
  378.  
  379.         trim: function(){
  380.                 return this.replace(/^\s+|\s+$/g, '');
  381.         },
  382.  
  383.         clean: function(){
  384.                 return this.replace(/\s{2,}/g, ' ').trim();
  385.         },
  386.  
  387.         rgbToHex: function(array){
  388.                 var rgb = this.match(/\d{1,3}/g);
  389.                 return (rgb) ? rgb.rgbToHex(array) : false;
  390.         },
  391.  
  392.         hexToRgb: function(array){
  393.                 var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
  394.                 return (hex) ? hex.slice(1).hexToRgb(array) : false;
  395.         },
  396.  
  397.         contains: function(string, s){
  398.                 return (s) ? (s + this + s).indexOf(s + string + s) > -1 : this.indexOf(string) > -1;
  399.         },
  400.  
  401.         escapeRegExp: function(){
  402.                 return this.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
  403.         }
  404.  
  405. });
  406.  
  407. Array.extend({
  408.  
  409.         rgbToHex: function(array){
  410.                 if (this.length < 3) return false;
  411.                 if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
  412.                 var hex = [];
  413.                 for (var i = 0; i < 3; i++){
  414.                         var bit = (this[i] - 0).toString(16);
  415.                         hex.push((bit.length == 1) ? '0' + bit : bit);
  416.                 }
  417.                 return array ? hex : '#' + hex.join('');
  418.         },
  419.  
  420.         hexToRgb: function(array){
  421.                 if (this.length != 3) return false;
  422.                 var rgb = [];
  423.                 for (var i = 0; i < 3; i++){
  424.                         rgb.push(parseInt((this[i].length == 1) ? this[i] + this[i] : this[i], 16));
  425.                 }
  426.                 return array ? rgb : 'rgb(' + rgb.join(',') + ')';
  427.         }
  428.  
  429. });
  430.  
  431. Function.extend({
  432.  
  433.         create: function(options){
  434.                 var fn = this;
  435.                 options = $merge({
  436.                         'bind': fn,
  437.                         'event': false,
  438.                         'arguments': null,
  439.                         'delay': false,
  440.                         'periodical': false,
  441.                         'attempt': false
  442.                 }, options);
  443.                 if ($chk(options.arguments) && $type(options.arguments) != 'array') options.arguments = [options.arguments];
  444.                 return function(event){
  445.                         var args;
  446.                         if (options.event){
  447.                                 event = event || window.event;
  448.                                 args = [(options.event === true) ? event : new options.event(event)];
  449.                                 if (options.arguments) args.extend(options.arguments);
  450.                         }
  451.                         else args = options.arguments || arguments;
  452.                         var returns = function(){
  453.                                 return fn.apply($pick(options.bind, fn), args);
  454.                         };
  455.                         if (options.delay) return setTimeout(returns, options.delay);
  456.                         if (options.periodical) return setInterval(returns, options.periodical);
  457.                         if (options.attempt) try {return returns();} catch(err){return false;};
  458.                         return returns();
  459.                 };
  460.         },
  461.  
  462.         pass: function(args, bind){
  463.                 return this.create({'arguments': args, 'bind': bind});
  464.         },
  465.  
  466.         attempt: function(args, bind){
  467.                 return this.create({'arguments': args, 'bind': bind, 'attempt': true})();
  468.         },
  469.  
  470.         bind: function(bind, args){
  471.                 return this.create({'bind': bind, 'arguments': args});
  472.         },
  473.  
  474.         bindAsEventListener: function(bind, args){
  475.                 return this.create({'bind': bind, 'event': true, 'arguments': args});
  476.         },
  477.  
  478.         delay: function(delay, bind, args){
  479.                 return this.create({'delay': delay, 'bind': bind, 'arguments': args})();
  480.         },
  481.  
  482.         periodical: function(interval, bind, args){
  483.                 return this.create({'periodical': interval, 'bind': bind, 'arguments': args})();
  484.         }
  485.  
  486. });
  487.  
  488. Number.extend({
  489.  
  490.         toInt: function(){
  491.                 return parseInt(this);
  492.         },
  493.  
  494.         toFloat: function(){
  495.                 return parseFloat(this);
  496.         },
  497.  
  498.         limit: function(min, max){
  499.                 return Math.min(max, Math.max(min, this));
  500.         },
  501.  
  502.         round: function(precision){
  503.                 precision = Math.pow(10, precision || 0);
  504.                 return Math.round(this * precision) / precision;
  505.         },
  506.  
  507.         times: function(fn){
  508.                 for (var i = 0; i < this; i++) fn(i);
  509.         }
  510.  
  511. });
  512.  
  513. var Element = new Class({
  514.  
  515.         initialize: function(el, props){
  516.                 if ($type(el) == 'string'){
  517.                         if (window.ie && props && (props.name || props.type)){
  518.                                 var name = (props.name) ? ' name="' + props.name + '"' : '';
  519.                                 var type = (props.type) ? ' type="' + props.type + '"' : '';
  520.                                 delete props.name;
  521.                                 delete props.type;
  522.                                 el = '<' + el + name + type + '>';
  523.                         }
  524.                         el = document.createElement(el);
  525.                 }
  526.                 el = $(el);
  527.                 return (!props || !el) ? el : el.set(props);
  528.         }
  529.  
  530. });
  531.  
  532. var Elements = new Class({
  533.  
  534.         initialize: function(elements){
  535.                 return (elements) ? $extend(elements, this) : this;
  536.         }
  537.  
  538. });
  539.  
  540. Elements.extend = function(props){
  541.         for (var prop in props){
  542.                 this.prototype[prop] = props[prop];
  543.                 this[prop] = $native.generic(prop);
  544.         }
  545. };
  546.  
  547. function $(el){
  548.         if (!el) return null;
  549.         if (el.htmlElement) return Garbage.collect(el);
  550.         if ([window, document].contains(el)) return el;
  551.         var type = $type(el);
  552.         if (type == 'string'){
  553.                 el = document.getElementById(el);
  554.                 type = (el) ? 'element' : false;
  555.         }
  556.         if (type != 'element') return null;
  557.         if (el.htmlElement) return Garbage.collect(el);
  558.         if (['object', 'embed'].contains(el.tagName.toLowerCase())) return el;
  559.         $extend(el, Element.prototype);
  560.         el.htmlElement = function(){};
  561.         return Garbage.collect(el);
  562. };
  563.  
  564. document.getElementsBySelector = document.getElementsByTagName;
  565.  
  566. function $$(){
  567.         var elements = [];
  568.         for (var i = 0, j = arguments.length; i < j; i++){
  569.                 var selector = arguments[i];
  570.                 switch($type(selector)){
  571.                         case 'element': elements.push(selector);
  572.                         case 'boolean': break;
  573.                         case false: break;
  574.                         case 'string': selector = document.getElementsBySelector(selector, true);
  575.                         default: elements.extend(selector);
  576.                 }
  577.         }
  578.         return $$.unique(elements);
  579. };
  580.  
  581. $$.unique = function(array){
  582.         var elements = [];
  583.         for (var i = 0, l = array.length; i < l; i++){
  584.                 if (array[i].$included) continue;
  585.                 var element = $(array[i]);
  586.                 if (element && !element.$included){
  587.                         element.$included = true;
  588.                         elements.push(element);
  589.                 }
  590.         }
  591.         for (var n = 0, d = elements.length; n < d; n++) elements[n].$included = null;
  592.         return new Elements(elements);
  593. };
  594.  
  595. Elements.Multi = function(property){
  596.         return function(){
  597.                 var args = arguments;
  598.                 var items = [];
  599.                 var elements = true;
  600.                 for (var i = 0, j = this.length, returns; i < j; i++){
  601.                         returns = this[i][property].apply(this[i], args);
  602.                         if ($type(returns) != 'element') elements = false;
  603.                         items.push(returns);
  604.                 };
  605.                 return (elements) ? $$.unique(items) : items;
  606.         };
  607. };
  608.  
  609. Element.extend = function(properties){
  610.         for (var property in properties){
  611.                 HTMLElement.prototype[property] = properties[property];
  612.                 Element.prototype[property] = properties[property];
  613.                 Element[property] = $native.generic(property);
  614.                 var elementsProperty = (Array.prototype[property]) ? property + 'Elements' : property;
  615.                 Elements.prototype[elementsProperty] = Elements.Multi(property);
  616.         }
  617. };
  618.  
  619. Element.extend({
  620.  
  621.         set: function(props){
  622.                 for (var prop in props){
  623.                         var val = props[prop];
  624.                         switch(prop){
  625.                                 case 'styles': this.setStyles(val); break;
  626.                                 case 'events': if (this.addEvents) this.addEvents(val); break;
  627.                                 case 'properties': this.setProperties(val); break;
  628.                                 default: this.setProperty(prop, val);
  629.                         }
  630.                 }
  631.                 return this;
  632.         },
  633.  
  634.         inject: function(el, where){
  635.                 el = $(el);
  636.                 switch(where){
  637.                         case 'before': el.parentNode.insertBefore(this, el); break;
  638.                         case 'after':
  639.                                 var next = el.getNext();
  640.                                 if (!next) el.parentNode.appendChild(this);
  641.                                 else el.parentNode.insertBefore(this, next);
  642.                                 break;
  643.                         case 'top':
  644.                                 var first = el.firstChild;
  645.                                 if (first){
  646.                                         el.insertBefore(this, first);
  647.                                         break;
  648.                                 }
  649.                         default: el.appendChild(this);
  650.                 }
  651.                 return this;
  652.         },
  653.  
  654.         injectBefore: function(el){
  655.                 return this.inject(el, 'before');
  656.         },
  657.  
  658.         injectAfter: function(el){
  659.                 return this.inject(el, 'after');
  660.         },
  661.  
  662.         injectInside: function(el){
  663.                 return this.inject(el, 'bottom');
  664.         },
  665.  
  666.         injectTop: function(el){
  667.                 return this.inject(el, 'top');
  668.         },
  669.  
  670.         adopt: function(){
  671.                 var elements = [];
  672.                 $each(arguments, function(argument){
  673.                         elements = elements.concat(argument);
  674.                 });
  675.                 $$(elements).inject(this);
  676.                 return this;
  677.         },
  678.  
  679.         remove: function(){
  680.                 return this.parentNode.removeChild(this);
  681.         },
  682.  
  683.         clone: function(contents){
  684.                 var el = $(this.cloneNode(contents !== false));
  685.                 if (!el.$events) return el;
  686.                 el.$events = {};
  687.                 for (var type in this.$events) el.$events[type] = {
  688.                         'keys': $A(this.$events[type].keys),
  689.                         'values': $A(this.$events[type].values)
  690.                 };
  691.                 return el.removeEvents();
  692.         },
  693.  
  694.         replaceWith: function(el){
  695.                 el = $(el);
  696.                 this.parentNode.replaceChild(el, this);
  697.                 return el;
  698.         },
  699.  
  700.         appendText: function(text){
  701.                 this.appendChild(document.createTextNode(text));
  702.                 return this;
  703.         },
  704.  
  705.         hasClass: function(className){
  706.                 return this.className.contains(className, ' ');
  707.         },
  708.  
  709.         addClass: function(className){
  710.                 if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean();
  711.                 return this;
  712.         },
  713.  
  714.         removeClass: function(className){
  715.                 this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1').clean();
  716.                 return this;
  717.         },
  718.  
  719.         toggleClass: function(className){
  720.                 return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
  721.         },
  722.  
  723.         setStyle: function(property, value){
  724.                 switch(property){
  725.                         case 'opacity': return this.setOpacity(parseFloat(value));
  726.                         case 'float': property = (window.ie) ? 'styleFloat' : 'cssFloat';
  727.                 }
  728.                 property = property.camelCase();
  729.                 switch($type(value)){
  730.                         case 'number': if (!['zIndex', 'zoom'].contains(property)) value += 'px'; break;
  731.                         case 'array': value = 'rgb(' + value.join(',') + ')';
  732.                 }
  733.                 this.style[property] = value;
  734.                 return this;
  735.         },
  736.  
  737.         setStyles: function(source){
  738.                 switch($type(source)){
  739.                         case 'object': Element.setMany(this, 'setStyle', source); break;
  740.                         case 'string': this.style.cssText = source;
  741.                 }
  742.                 return this;
  743.         },
  744.  
  745.         setOpacity: function(opacity){
  746.                 if (opacity == 0){
  747.                         if (this.style.visibility != "hidden") this.style.visibility = "hidden";
  748.                 } else {
  749.                         if (this.style.visibility != "visible") this.style.visibility = "visible";
  750.                 }
  751.                 if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1;
  752.                 if (window.ie) this.style.filter = (opacity == 1) ? '' : "alpha(opacity=" + opacity * 100 + ")";
  753.                 this.style.opacity = this.$tmp.opacity = opacity;
  754.                 return this;
  755.         },
  756.  
  757.         getStyle: function(property){
  758.                 property = property.camelCase();
  759.                 var result = this.style[property];
  760.                 if (!$chk(result)){
  761.                         if (property == 'opacity') return this.$tmp.opacity;
  762.                         result = [];
  763.                         for (var style in Element.Styles){
  764.                                 if (property == style){
  765.                                         Element.Styles[style].each(function(s){
  766.                                                 var style = this.getStyle(s);
  767.                                                 result.push(parseInt(style) ? style : '0px');
  768.                                         }, this);
  769.                                         if (property == 'border'){
  770.                                                 var every = result.every(function(bit){
  771.                                                         return (bit == result[0]);
  772.                                                 });
  773.                                                 return (every) ? result[0] : false;
  774.                                         }
  775.                                         return result.join(' ');
  776.                                 }
  777.                         }
  778.                         if (property.contains('border')){
  779.                                 if (Element.Styles.border.contains(property)){
  780.                                         return ['Width', 'Style', 'Color'].map(function(p){
  781.                                                 return this.getStyle(property + p);
  782.                                         }, this).join(' ');
  783.                                 } else if (Element.borderShort.contains(property)){
  784.                                         return ['Top', 'Right', 'Bottom', 'Left'].map(function(p){
  785.                                                 return this.getStyle('border' + p + property.replace('border', ''));
  786.                                         }, this).join(' ');
  787.                                 }
  788.                         }
  789.                         if (document.defaultView) result = document.defaultView.getComputedStyle(this, null).getPropertyValue(property.hyphenate());
  790.                         else if (this.currentStyle) result = this.currentStyle[property];
  791.                 }
  792.                 if (window.ie) result = Element.fixStyle(property, result, this);
  793.                 if (result && property.test(/color/i) && result.contains('rgb')){
  794.                         return result.split('rgb').splice(1,4).map(function(color){
  795.                                 return color.rgbToHex();
  796.                         }).join(' ');
  797.                 }
  798.                 return result;
  799.         },
  800.  
  801.         getStyles: function(){
  802.                 return Element.getMany(this, 'getStyle', arguments);
  803.         },
  804.  
  805.         walk: function(brother, start){
  806.                 brother += 'Sibling';
  807.                 var el = (start) ? this[start] : this[brother];
  808.                 while (el && $type(el) != 'element') el = el[brother];
  809.                 return $(el);
  810.         },
  811.  
  812.         getPrevious: function(){
  813.                 return this.walk('previous');
  814.         },
  815.  
  816.         getNext: function(){
  817.                 return this.walk('next');
  818.         },
  819.  
  820.         getFirst: function(){
  821.                 return this.walk('next', 'firstChild');
  822.         },
  823.  
  824.         getLast: function(){
  825.                 return this.walk('previous', 'lastChild');
  826.         },
  827.  
  828.         getParent: function(){
  829.                 return $(this.parentNode);
  830.         },
  831.  
  832.         getChildren: function(){
  833.                 return $$(this.childNodes);
  834.         },
  835.  
  836.         hasChild: function(el){
  837.                 return !!$A(this.getElementsByTagName('*')).contains(el);
  838.         },
  839.  
  840.         getProperty: function(property){
  841.                 var index = Element.Properties[property];
  842.                 if (index) return this[index];
  843.                 var flag = Element.PropertiesIFlag[property] || 0;
  844.                 if (!window.ie || flag) return this.getAttribute(property, flag);
  845.                 var node = this.attributes[property];
  846.                 return (node) ? node.nodeValue : null;
  847.         },
  848.  
  849.         removeProperty: function(property){
  850.                 var index = Element.Properties[property];
  851.                 if (index) this[index] = '';
  852.                 else this.removeAttribute(property);
  853.                 return this;
  854.         },
  855.  
  856.         getProperties: function(){
  857.                 return Element.getMany(this, 'getProperty', arguments);
  858.         },
  859.  
  860.         setProperty: function(property, value){
  861.                 var index = Element.Properties[property];
  862.                 if (index) this[index] = value;
  863.                 else this.setAttribute(property, value);
  864.                 return this;
  865.         },
  866.  
  867.         setProperties: function(source){
  868.                 return Element.setMany(this, 'setProperty', source);
  869.         },
  870.  
  871.         setHTML: function(){
  872.                 this.innerHTML = $A(arguments).join('');
  873.                 return this;
  874.         },
  875.  
  876.         setText: function(text){
  877.                 var tag = this.getTag();
  878.                 if (['style', 'script'].contains(tag)){
  879.                         if (window.ie){
  880.                                 if (tag == 'style') this.styleSheet.cssText = text;
  881.                                 else if (tag ==  'script') this.setProperty('text', text);
  882.                                 return this;
  883.                         } else {
  884.                                 this.removeChild(this.firstChild);
  885.                                 return this.appendText(text);
  886.                         }
  887.                 }
  888.                 this[$defined(this.innerText) ? 'innerText' : 'textContent'] = text;
  889.                 return this;
  890.         },
  891.  
  892.         getText: function(){
  893.                 var tag = this.getTag();
  894.                 if (['style', 'script'].contains(tag)){
  895.                         if (window.ie){
  896.                                 if (tag == 'style') return this.styleSheet.cssText;
  897.                                 else if (tag ==  'script') return this.getProperty('text');
  898.                         } else {
  899.                                 return this.innerHTML;
  900.                         }
  901.                 }
  902.                 return ($pick(this.innerText, this.textContent));
  903.         },
  904.  
  905.         getTag: function(){
  906.                 return this.tagName.toLowerCase();
  907.         },
  908.  
  909.         empty: function(){
  910.                 Garbage.trash(this.getElementsByTagName('*'));
  911.                 return this.setHTML('');
  912.         }
  913.  
  914. });
  915.  
  916. Element.fixStyle = function(property, result, element){
  917.         if ($chk(parseInt(result))) return result;
  918.         if (['height', 'width'].contains(property)){
  919.                 var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'];
  920.                 var size = 0;
  921.                 values.each(function(value){
  922.                         size += element.getStyle('border-' + value + '-width').toInt() + element.getStyle('padding-' + value).toInt();
  923.                 });
  924.                 return element['offset' + property.capitalize()] - size + 'px';
  925.         } else if (property.test(/border(.+)Width|margin|padding/)){
  926.                 return '0px';
  927.         }
  928.         return result;
  929. };
  930.  
  931. Element.Styles = {'border': [], 'padding': [], 'margin': []};
  932. ['Top', 'Right', 'Bottom', 'Left'].each(function(direction){
  933.         for (var style in Element.Styles) Element.Styles[style].push(style + direction);
  934. });
  935.  
  936. Element.borderShort = ['borderWidth', 'borderStyle', 'borderColor'];
  937.  
  938. Element.getMany = function(el, method, keys){
  939.         var result = {};
  940.         $each(keys, function(key){
  941.                 result[key] = el[method](key);
  942.         });
  943.         return result;
  944. };
  945.  
  946. Element.setMany = function(el, method, pairs){
  947.         for (var key in pairs) el[method](key, pairs[key]);
  948.         return el;
  949. };
  950.  
  951. Element.Properties = new Abstract({
  952.         'class': 'className', 'for': 'htmlFor', 'colspan': 'colSpan', 'rowspan': 'rowSpan',
  953.         'accesskey': 'accessKey', 'tabindex': 'tabIndex', 'maxlength': 'maxLength',
  954.         'readonly': 'readOnly', 'frameborder': 'frameBorder', 'value': 'value',
  955.         'disabled': 'disabled', 'checked': 'checked', 'multiple': 'multiple', 'selected': 'selected'
  956. });
  957. Element.PropertiesIFlag = {
  958.         'href': 2, 'src': 2
  959. };
  960.  
  961. Element.Methods = {
  962.         Listeners: {
  963.                 addListener: function(type, fn){
  964.                         if (this.addEventListener) this.addEventListener(type, fn, false);
  965.                         else this.attachEvent('on' + type, fn);
  966.                         return this;
  967.                 },
  968.  
  969.                 removeListener: function(type, fn){
  970.                         if (this.removeEventListener) this.removeEventListener(type, fn, false);
  971.                         else this.detachEvent('on' + type, fn);
  972.                         return this;
  973.                 }
  974.         }
  975. };
  976.  
  977. window.extend(Element.Methods.Listeners);
  978. document.extend(Element.Methods.Listeners);
  979. Element.extend(Element.Methods.Listeners);
  980.  
  981. var Garbage = {
  982.  
  983.         elements: [],
  984.  
  985.         collect: function(el){
  986.                 if (!el.$tmp){
  987.                         Garbage.elements.push(el);
  988.                         el.$tmp = {'opacity': 1};
  989.                 }
  990.                 return el;
  991.         },
  992.  
  993.         trash: function(elements){
  994.                 for (var i = 0, j = elements.length, el; i < j; i++){
  995.                         if (!(el = elements[i]) || !el.$tmp) continue;
  996.                         if (el.$events) el.fireEvent('trash').removeEvents();
  997.                         for (var p in el.$tmp) el.$tmp[p] = null;
  998.                         for (var d in Element.prototype) el[d] = null;
  999.                         Garbage.elements[Garbage.elements.indexOf(el)] = null;
  1000.                         el.htmlElement = el.$tmp = el = null;
  1001.                 }
  1002.                 Garbage.elements.remove(null);
  1003.         },
  1004.  
  1005.         empty: function(){
  1006.                 Garbage.collect(window);
  1007.                 Garbage.collect(document);
  1008.                 Garbage.trash(Garbage.elements);
  1009.         }
  1010.  
  1011. };
  1012.  
  1013. window.addListener('beforeunload', function(){
  1014.         window.addListener('unload', Garbage.empty);
  1015.         if (window.ie) window.addListener('unload', CollectGarbage);
  1016. });
  1017.  
  1018. var Event = new Class({
  1019.  
  1020.         initialize: function(event){
  1021.                 if (event && event.$extended) return event;
  1022.                 this.$extended = true;
  1023.                 event = event || window.event;
  1024.                 this.event = event;
  1025.                 this.type = event.type;
  1026.                 this.target = event.target || event.srcElement;
  1027.                 if (this.target.nodeType == 3) this.target = this.target.parentNode;
  1028.                 this.shift = event.shiftKey;
  1029.                 this.control = event.ctrlKey;
  1030.                 this.alt = event.altKey;
  1031.                 this.meta = event.metaKey;
  1032.                 if (['DOMMouseScroll', 'mousewheel'].contains(this.type)){
  1033.                         this.wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
  1034.                 } else if (this.type.contains('key')){
  1035.                         this.code = event.which || event.keyCode;
  1036.                         for (var name in Event.keys){
  1037.                                 if (Event.keys[name] == this.code){
  1038.                                         this.key = name;
  1039.                                         break;
  1040.                                 }
  1041.                         }
  1042.                         if (this.type == 'keydown'){
  1043.                                 var fKey = this.code - 111;
  1044.                                 if (fKey > 0 && fKey < 13) this.key = 'f' + fKey;
  1045.                         }
  1046.                         this.key = this.key || String.fromCharCode(this.code).toLowerCase();
  1047.                 } else if (this.type.test(/(click|mouse|menu)/)){
  1048.                         this.page = {
  1049.                                 'x': event.pageX || event.clientX + document.documentElement.scrollLeft,
  1050.                                 'y': event.pageY || event.clientY + document.documentElement.scrollTop
  1051.                         };
  1052.                         this.client = {
  1053.                                 'x': event.pageX ? event.pageX - window.pageXOffset : event.clientX,
  1054.                                 'y': event.pageY ? event.pageY - window.pageYOffset : event.clientY
  1055.                         };
  1056.                         this.rightClick = (event.which == 3) || (event.button == 2);
  1057.                         switch(this.type){
  1058.                                 case 'mouseover': this.relatedTarget = event.relatedTarget || event.fromElement; break;
  1059.                                 case 'mouseout': this.relatedTarget = event.relatedTarget || event.toElement;
  1060.                         }
  1061.                         this.fixRelatedTarget();
  1062.                 }
  1063.                 return this;
  1064.         },
  1065.  
  1066.         stop: function(){
  1067.                 return this.stopPropagation().preventDefault();
  1068.         },
  1069.  
  1070.         stopPropagation: function(){
  1071.                 if (this.event.stopPropagation) this.event.stopPropagation();
  1072.                 else this.event.cancelBubble = true;
  1073.                 return this;
  1074.         },
  1075.  
  1076.         preventDefault: function(){
  1077.                 if (this.event.preventDefault) this.event.preventDefault();
  1078.                 else this.event.returnValue = false;
  1079.                 return this;
  1080.         }
  1081.  
  1082. });
  1083.  
  1084. Event.fix = {
  1085.  
  1086.         relatedTarget: function(){
  1087.                 if (this.relatedTarget && this.relatedTarget.nodeType == 3) this.relatedTarget = this.relatedTarget.parentNode;
  1088.         },
  1089.  
  1090.         relatedTargetGecko: function(){
  1091.                 try {Event.fix.relatedTarget.call(this);} catch(e){this.relatedTarget = this.target;}
  1092.         }
  1093.  
  1094. };
  1095.  
  1096. Event.prototype.fixRelatedTarget = (window.gecko) ? Event.fix.relatedTargetGecko : Event.fix.relatedTarget;
  1097.  
  1098. Event.keys = new Abstract({
  1099.         'enter': 13,
  1100.         'up': 38,
  1101.         'down': 40,
  1102.         'left': 37,
  1103.         'right': 39,
  1104.         'esc': 27,
  1105.         'space': 32,
  1106.         'backspace': 8,
  1107.         'tab': 9,
  1108.         'delete': 46
  1109. });
  1110.  
  1111. Element.Methods.Events = {
  1112.  
  1113.         addEvent: function(type, fn){
  1114.                 this.$events = this.$events || {};
  1115.                 this.$events[type] = this.$events[type] || {'keys': [], 'values': []};
  1116.                 if (this.$events[type].keys.contains(fn)) return this;
  1117.                 this.$events[type].keys.push(fn);
  1118.                 var realType = type;
  1119.                 var custom = Element.Events[type];
  1120.                 if (custom){
  1121.                         if (custom.add) custom.add.call(this, fn);
  1122.                         if (custom.map) fn = custom.map;
  1123.                         if (custom.type) realType = custom.type;
  1124.                 }
  1125.                 if (!this.addEventListener) fn = fn.create({'bind': this, 'event': true});
  1126.                 this.$events[type].values.push(fn);
  1127.                 return (Element.NativeEvents.contains(realType)) ? this.addListener(realType, fn) : this;
  1128.         },
  1129.  
  1130.         removeEvent: function(type, fn){
  1131.                 if (!this.$events || !this.$events[type]) return this;
  1132.                 var pos = this.$events[type].keys.indexOf(fn);
  1133.                 if (pos == -1) return this;
  1134.                 var key = this.$events[type].keys.splice(pos,1)[0];
  1135.                 var value = this.$events[type].values.splice(pos,1)[0];
  1136.                 var custom = Element.Events[type];
  1137.                 if (custom){
  1138.                         if (custom.remove) custom.remove.call(this, fn);
  1139.                         if (custom.type) type = custom.type;
  1140.                 }
  1141.                 return (Element.NativeEvents.contains(type)) ? this.removeListener(type, value) : this;
  1142.         },
  1143.  
  1144.         addEvents: function(source){
  1145.                 return Element.setMany(this, 'addEvent', source);
  1146.         },
  1147.  
  1148.         removeEvents: function(type){
  1149.                 if (!this.$events) return this;
  1150.                 if (!type){
  1151.                         for (var evType in this.$events) this.removeEvents(evType);
  1152.                         this.$events = null;
  1153.                 } else if (this.$events[type]){
  1154.                         this.$events[type].keys.each(function(fn){
  1155.                                 this.removeEvent(type, fn);
  1156.                         }, this);
  1157.                         this.$events[type] = null;
  1158.                 }
  1159.                 return this;
  1160.         },
  1161.  
  1162.         fireEvent: function(type, args, delay){
  1163.                 if (this.$events && this.$events[type]){
  1164.                         this.$events[type].keys.each(function(fn){
  1165.                                 fn.create({'bind': this, 'delay': delay, 'arguments': args})();
  1166.                         }, this);
  1167.                 }
  1168.                 return this;
  1169.         },
  1170.  
  1171.         cloneEvents: function(from, type){
  1172.                 if (!from.$events) return this;
  1173.                 if (!type){
  1174.                         for (var evType in from.$events) this.cloneEvents(from, evType);
  1175.                 } else if (from.$events[type]){
  1176.                         from.$events[type].keys.each(function(fn){
  1177.                                 this.addEvent(type, fn);
  1178.                         }, this);
  1179.                 }
  1180.                 return this;
  1181.         }
  1182.  
  1183. };
  1184.  
  1185. window.extend(Element.Methods.Events);
  1186. document.extend(Element.Methods.Events);
  1187. Element.extend(Element.Methods.Events);
  1188.  
  1189. Element.Events = new Abstract({
  1190.  
  1191.         'mouseenter': {
  1192.                 type: 'mouseover',
  1193.                 map: function(event){
  1194.                         event = new Event(event);
  1195.                         if (event.relatedTarget != this && !this.hasChild(event.relatedTarget)) this.fireEvent('mouseenter', event);
  1196.                 }
  1197.         },
  1198.  
  1199.         'mouseleave': {
  1200.                 type: 'mouseout',
  1201.                 map: function(event){
  1202.                         event = new Event(event);
  1203.                         if (event.relatedTarget != this && !this.hasChild(event.relatedTarget)) this.fireEvent('mouseleave', event);
  1204.                 }
  1205.         },
  1206.  
  1207.         'mousewheel': {
  1208.                 type: (window.gecko) ? 'DOMMouseScroll' : 'mousewheel'
  1209.         }
  1210.  
  1211. });
  1212.  
  1213. Element.NativeEvents = [
  1214.         'click', 'dblclick', 'mouseup', 'mousedown',
  1215.         'mousewheel', 'DOMMouseScroll',
  1216.         'mouseover', 'mouseout', 'mousemove',
  1217.         'keydown', 'keypress', 'keyup',
  1218.         'load', 'unload', 'beforeunload', 'resize', 'move',
  1219.         'focus', 'blur', 'change', 'submit', 'reset', 'select',
  1220.         'error', 'abort', 'contextmenu', 'scroll'
  1221. ];
  1222.  
  1223. Function.extend({
  1224.  
  1225.         bindWithEvent: function(bind, args){
  1226.                 return this.create({'bind': bind, 'arguments': args, 'event': Event});
  1227.         }
  1228.  
  1229. });
  1230.  
  1231. Element.extend({
  1232.  
  1233.         scrollTo: function(x, y){
  1234.                 this.scrollLeft = x;
  1235.                 this.scrollTop = y;
  1236.         },
  1237.  
  1238.         getSize: function(){
  1239.                 return {
  1240.                         'scroll': {'x': this.scrollLeft, 'y': this.scrollTop},
  1241.                         'size': {'x': this.offsetWidth, 'y': this.offsetHeight},
  1242.                         'scrollSize': {'x': this.scrollWidth, 'y': this.scrollHeight}
  1243.                 };
  1244.         },
  1245.  
  1246.         getPosition: function(overflown){
  1247.                 overflown = overflown || [];
  1248.                 var el = this, left = 0, top = 0;
  1249.                 do {
  1250.                         left += el.offsetLeft || 0;
  1251.                         top += el.offsetTop || 0;
  1252.                         el = el.offsetParent;
  1253.                 } while (el);
  1254.                 overflown.each(function(element){
  1255.                         left -= element.scrollLeft || 0;
  1256.                         top -= element.scrollTop || 0;
  1257.                 });
  1258.                 return {'x': left, 'y': top};
  1259.         },
  1260.  
  1261.         getTop: function(overflown){
  1262.                 return this.getPosition(overflown).y;
  1263.         },
  1264.  
  1265.         getLeft: function(overflown){
  1266.                 return this.getPosition(overflown).x;
  1267.         },
  1268.  
  1269.         getCoordinates: function(overflown){
  1270.                 var position = this.getPosition(overflown);
  1271.                 var obj = {
  1272.                         'width': this.offsetWidth,
  1273.                         'height': this.offsetHeight,
  1274.                         'left': position.x,
  1275.                         'top': position.y
  1276.                 };
  1277.                 obj.right = obj.left + obj.width;
  1278.                 obj.bottom = obj.top + obj.height;
  1279.                 return obj;
  1280.         }
  1281.  
  1282. });
  1283.  
  1284. window.extend({
  1285.  
  1286.         getWidth: function(){
  1287.                 if (this.webkit419) return this.innerWidth;
  1288.                 if (this.opera) return document.body.clientWidth;
  1289.                 return document.documentElement.clientWidth;
  1290.         },
  1291.  
  1292.         getHeight: function(){
  1293.                 if (this.webkit419) return this.innerHeight;
  1294.                 if (this.opera) return document.body.clientHeight;
  1295.                 return document.documentElement.clientHeight;
  1296.         },
  1297.  
  1298.         getScrollWidth: function(){
  1299.                 if (this.ie) return Math.max(document.documentElement.offsetWidth, document.documentElement.scrollWidth);
  1300.                 if (this.webkit) return document.body.scrollWidth;
  1301.                 return document.documentElement.scrollWidth;
  1302.         },
  1303.  
  1304.         getScrollHeight: function(){
  1305.                 if (this.ie) return Math.max(document.documentElement.offsetHeight, document.documentElement.scrollHeight);
  1306.                 if (this.webkit) return document.body.scrollHeight;
  1307.                 return document.documentElement.scrollHeight;
  1308.         },
  1309.  
  1310.         getScrollLeft: function(){
  1311.                 return this.pageXOffset || document.documentElement.scrollLeft;
  1312.         },
  1313.  
  1314.         getScrollTop: function(){
  1315.                 return this.pageYOffset || document.documentElement.scrollTop;
  1316.         },
  1317.  
  1318.         getSize: function(){
  1319.                 return {
  1320.                         'size': {'x': this.getWidth(), 'y': this.getHeight()},
  1321.                         'scrollSize': {'x': this.getScrollWidth(), 'y': this.getScrollHeight()},
  1322.                         'scroll': {'x': this.getScrollLeft(), 'y': this.getScrollTop()}
  1323.                 };
  1324.         },
  1325.         getPosition: function(){return {'x': 0, 'y': 0};}
  1326.  
  1327. });
  1328.  
  1329. var Fx = {};
  1330.  
  1331. Fx.Base = new Class({
  1332.  
  1333.         options: {
  1334.                 onStart: Class.empty,
  1335.                 onComplete: Class.empty,
  1336.                 onCancel: Class.empty,
  1337.                 transition: function(p){
  1338.                         return -(Math.cos(Math.PI * p) - 1) / 2;
  1339.                 },
  1340.                 duration: 500,
  1341.                 unit: 'px',
  1342.                 wait: true,
  1343.                 fps: 50
  1344.         },
  1345.  
  1346.         initialize: function(options){
  1347.                 this.element = this.element || null;
  1348.                 this.setOptions(options);
  1349.                 if (this.options.initialize) this.options.initialize.call(this);
  1350.         },
  1351.  
  1352.         step: function(){
  1353.                 var time = $time();
  1354.                 if (time < this.time + this.options.duration){
  1355.                         this.delta = this.options.transition((time - this.time) / this.options.duration);
  1356.                         this.setNow();
  1357.                         this.increase();
  1358.                 } else {
  1359.                         this.stop(true);
  1360.                         this.set(this.to);
  1361.                         this.fireEvent('onComplete', this.element, 10);
  1362.                         this.callChain();
  1363.                 }
  1364.         },
  1365.  
  1366.         set: function(to){
  1367.                 this.now = to;
  1368.                 this.increase();
  1369.                 return this;
  1370.         },
  1371.  
  1372.         setNow: function(){
  1373.                 this.now = this.compute(this.from, this.to);
  1374.         },
  1375.  
  1376.         compute: function(from, to){
  1377.                 return (to - from) * this.delta + from;
  1378.         },
  1379.  
  1380.         start: function(from, to){
  1381.                 if (!this.options.wait) this.stop();
  1382.                 else if (this.timer) return this;
  1383.                 this.from = from;
  1384.                 this.to = to;
  1385.                 this.change = this.to - this.from;
  1386.                 this.time = $time();
  1387.                 this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this);
  1388.                 this.fireEvent('onStart', this.element);
  1389.                 return this;
  1390.         },
  1391.  
  1392.         stop: function(end){
  1393.                 if (!this.timer) return this;
  1394.                 this.timer = $clear(this.timer);
  1395.                 if (!end) this.fireEvent('onCancel', this.element);
  1396.                 return this;
  1397.         }/*compatibility*/,
  1398.  
  1399.         custom: function(from, to){
  1400.                 return this.start(from, to);
  1401.         },
  1402.  
  1403.         clearTimer: function(end){
  1404.                 return this.stop(end);
  1405.         }
  1406.  
  1407. });
  1408.  
  1409. Fx.Base.implement(new Chain, new Events, new Options);
  1410.  
  1411. Fx.CSS = {
  1412.  
  1413.         select: function(property, to){
  1414.                 if (property.test(/color/i)) return this.Color;
  1415.                 var type = $type(to);
  1416.                 if ((type == 'array') || (type == 'string' && to.contains(' '))) return this.Multi;
  1417.                 return this.Single;
  1418.         },
  1419.  
  1420.         parse: function(el, property, fromTo){
  1421.                 if (!fromTo.push) fromTo = [fromTo];
  1422.                 var from = fromTo[0], to = fromTo[1];
  1423.                 if (!$chk(to)){
  1424.                         to = from;
  1425.                         from = el.getStyle(property);
  1426.                 }
  1427.                 var css = this.select(property, to);
  1428.                 return {'from': css.parse(from), 'to': css.parse(to), 'css': css};
  1429.         }
  1430.  
  1431. };
  1432.  
  1433. Fx.CSS.Single = {
  1434.  
  1435.         parse: function(value){
  1436.                 return parseFloat(value);
  1437.         },
  1438.  
  1439.         getNow: function(from, to, fx){
  1440.                 return fx.compute(from, to);
  1441.         },
  1442.  
  1443.         getValue: function(value, unit, property){
  1444.                 if (unit == 'px' && property != 'opacity') value = Math.round(value);
  1445.                 return value + unit;
  1446.         }
  1447.  
  1448. };
  1449.  
  1450. Fx.CSS.Multi = {
  1451.  
  1452.         parse: function(value){
  1453.                 return value.push ? value : value.split(' ').map(function(v){
  1454.                         return parseFloat(v);
  1455.                 });
  1456.         },
  1457.  
  1458.         getNow: function(from, to, fx){
  1459.                 var now = [];
  1460.                 for (var i = 0; i < from.length; i++) now[i] = fx.compute(from[i], to[i]);
  1461.                 return now;
  1462.         },
  1463.  
  1464.         getValue: function(value, unit, property){
  1465.                 if (unit == 'px' && property != 'opacity') value = value.map(Math.round);
  1466.                 return value.join(unit + ' ') + unit;
  1467.         }
  1468.  
  1469. };
  1470.  
  1471. Fx.CSS.Color = {
  1472.  
  1473.         parse: function(value){
  1474.                 return value.push ? value : value.hexToRgb(true);
  1475.         },
  1476.  
  1477.         getNow: function(from, to, fx){
  1478.                 var now = [];
  1479.                 for (var i = 0; i < from.length; i++) now[i] = Math.round(fx.compute(from[i], to[i]));
  1480.                 return now;
  1481.         },
  1482.  
  1483.         getValue: function(value){
  1484.                 return 'rgb(' + value.join(',') + ')';
  1485.         }
  1486.  
  1487. };
  1488.  
  1489. Fx.Style = Fx.Base.extend({
  1490.  
  1491.         initialize: function(el, property, options){
  1492.                 this.element = $(el);
  1493.                 this.property = property;
  1494.                 this.parent(options);
  1495.         },
  1496.  
  1497.         hide: function(){
  1498.                 return this.set(0);
  1499.         },
  1500.  
  1501.         setNow: function(){
  1502.                 this.now = this.css.getNow(this.from, this.to, this);
  1503.         },
  1504.  
  1505.         set: function(to){
  1506.                 this.css = Fx.CSS.select(this.property, to);
  1507.                 return this.parent(this.css.parse(to));
  1508.         },
  1509.  
  1510.         start: function(from, to){
  1511.                 if (this.timer && this.options.wait) return this;
  1512.                 var parsed = Fx.CSS.parse(this.element, this.property, [from, to]);
  1513.                 this.css = parsed.css;
  1514.                 return this.parent(parsed.from, parsed.to);
  1515.         },
  1516.  
  1517.         increase: function(){
  1518.                 this.element.setStyle(this.property, this.css.getValue(this.now, this.options.unit, this.property));
  1519.         }
  1520.  
  1521. });
  1522.  
  1523. Element.extend({
  1524.  
  1525.         effect: function(property, options){
  1526.                 return new Fx.Style(this, property, options);
  1527.         }
  1528.  
  1529. });
  1530.  
  1531. Fx.Styles = Fx.Base.extend({
  1532.  
  1533.         initialize: function(el, options){
  1534.                 this.element = $(el);
  1535.                 this.parent(options);
  1536.         },
  1537.  
  1538.         setNow: function(){
  1539.                 for (var p in this.from) this.now[p] = this.css[p].getNow(this.from[p], this.to[p], this);
  1540.         },
  1541.  
  1542.         set: function(to){
  1543.                 var parsed = {};
  1544.                 this.css = {};
  1545.                 for (var p in to){
  1546.                         this.css[p] = Fx.CSS.select(p, to[p]);
  1547.                         parsed[p] = this.css[p].parse(to[p]);
  1548.                 }
  1549.                 return this.parent(parsed);
  1550.         },
  1551.  
  1552.         start: function(obj){
  1553.                 if (this.timer && this.options.wait) return this;
  1554.                 this.now = {};
  1555.                 this.css = {};
  1556.                 var from = {}, to = {};
  1557.                 for (var p in obj){
  1558.                         var parsed = Fx.CSS.parse(this.element, p, obj[p]);
  1559.                         from[p] = parsed.from;
  1560.                         to[p] = parsed.to;
  1561.                         this.css[p] = parsed.css;
  1562.                 }
  1563.                 return this.parent(from, to);
  1564.         },
  1565.  
  1566.         increase: function(){
  1567.                 for (var p in this.now) this.element.setStyle(p, this.css[p].getValue(this.now[p], this.options.unit, p));
  1568.         }
  1569.  
  1570. });
  1571.  
  1572. Element.extend({
  1573.  
  1574.         effects: function(options){
  1575.                 return new Fx.Styles(this, options);
  1576.         }
  1577.  
  1578. });
  1579.  
  1580. Fx.Elements = Fx.Base.extend({
  1581.  
  1582.         initialize: function(elements, options){
  1583.                 this.elements = $$(elements);
  1584.                 this.parent(options);
  1585.         },
  1586.  
  1587.         setNow: function(){
  1588.                 for (var i in this.from){
  1589.                         var iFrom = this.from[i], iTo = this.to[i], iCss = this.css[i], iNow = this.now[i] = {};
  1590.                         for (var p in iFrom) iNow[p] = iCss[p].getNow(iFrom[p], iTo[p], this);
  1591.                 }
  1592.         },
  1593.  
  1594.         set: function(to){
  1595.                 var parsed = {};
  1596.                 this.css = {};
  1597.                 for (var i in to){
  1598.                         var iTo = to[i], iCss = this.css[i] = {}, iParsed = parsed[i] = {};
  1599.                         for (var p in iTo){
  1600.                                 iCss[p] = Fx.CSS.select(p, iTo[p]);
  1601.                                 iParsed[p] = iCss[p].parse(iTo[p]);
  1602.                         }
  1603.                 }
  1604.                 return this.parent(parsed);
  1605.         },
  1606.  
  1607.         start: function(obj){
  1608.                 if (this.timer && this.options.wait) return this;
  1609.                 this.now = {};
  1610.                 this.css = {};
  1611.                 var from = {}, to = {};
  1612.                 for (var i in obj){
  1613.                         var iProps = obj[i], iFrom = from[i] = {}, iTo = to[i] = {}, iCss = this.css[i] = {};
  1614.                         for (var p in iProps){
  1615.                                 var parsed = Fx.CSS.parse(this.elements[i], p, iProps[p]);
  1616.                                 iFrom[p] = parsed.from;
  1617.                                 iTo[p] = parsed.to;
  1618.                                 iCss[p] = parsed.css;
  1619.                         }
  1620.                 }
  1621.                 return this.parent(from, to);
  1622.         },
  1623.  
  1624.         increase: function(){
  1625.                 for (var i in this.now){
  1626.                         var iNow = this.now[i], iCss = this.css[i];
  1627.                         for (var p in iNow) this.elements[i].setStyle(p, iCss[p].getValue(iNow[p], this.options.unit, p));
  1628.                 }
  1629.         }
  1630.  
  1631. });
  1632.  
  1633. Fx.Scroll = Fx.Base.extend({
  1634.  
  1635.         options: {
  1636.                 overflown: [],
  1637.                 offset: {'x': 0, 'y': 0},
  1638.                 wheelStops: true
  1639.         },
  1640.  
  1641.         initialize: function(element, options){
  1642.                 this.now = [];
  1643.                 this.element = $(element);
  1644.                 this.bound = {'stop': this.stop.bind(this, false)};
  1645.                 this.parent(options);
  1646.                 if (this.options.wheelStops){
  1647.                         this.addEvent('onStart', function(){
  1648.                                 document.addEvent('mousewheel', this.bound.stop);
  1649.                         }.bind(this));
  1650.                         this.addEvent('onComplete', function(){
  1651.                                 document.removeEvent('mousewheel', this.bound.stop);
  1652.                         }.bind(this));
  1653.                 }
  1654.         },
  1655.  
  1656.         setNow: function(){
  1657.                 for (var i = 0; i < 2; i++) this.now[i] = this.compute(this.from[i], this.to[i]);
  1658.         },
  1659.  
  1660.         scrollTo: function(x, y){
  1661.                 if (this.timer && this.options.wait) return this;
  1662.                 var el = this.element.getSize();
  1663.                 var values = {'x': x, 'y': y};
  1664.                 for (var z in el.size){
  1665.                         var max = el.scrollSize[z] - el.size[z];
  1666.                         if ($chk(values[z])) values[z] = ($type(values[z]) == 'number') ? values[z].limit(0, max) : max;
  1667.                         else values[z] = el.scroll[z];
  1668.                         values[z] += this.options.offset[z];
  1669.                 }
  1670.                 return this.start([el.scroll.x, el.scroll.y], [values.x, values.y]);
  1671.         },
  1672.  
  1673.         toTop: function(){
  1674.                 return this.scrollTo(false, 0);
  1675.         },
  1676.  
  1677.         toBottom: function(){
  1678.                 return this.scrollTo(false, 'full');
  1679.         },
  1680.  
  1681.         toLeft: function(){
  1682.                 return this.scrollTo(0, false);
  1683.         },
  1684.  
  1685.         toRight: function(){
  1686.                 return this.scrollTo('full', false);
  1687.         },
  1688.  
  1689.         toElement: function(el){
  1690.                 var parent = this.element.getPosition(this.options.overflown);
  1691.                 var target = $(el).getPosition(this.options.overflown);
  1692.                 return this.scrollTo(target.x - parent.x, target.y - parent.y);
  1693.         },
  1694.  
  1695.         increase: function(){
  1696.                 this.element.scrollTo(this.now[0], this.now[1]);
  1697.         }
  1698.  
  1699. });
  1700.  
  1701. Fx.Slide = Fx.Base.extend({
  1702.  
  1703.         options: {
  1704.                 mode: 'vertical'
  1705.         },
  1706.  
  1707.         initialize: function(el, options){
  1708.                 this.element = $(el);
  1709.                 this.wrapper = new Element('div', {'styles': $extend(this.element.getStyles('margin'), {'overflow': 'hidden'})}).injectAfter(this.element).adopt(this.element);
  1710.                 this.element.setStyle('margin', 0);
  1711.                 this.setOptions(options);
  1712.                 this.now = [];
  1713.                 this.parent(this.options);
  1714.                 this.open = true;
  1715.                 this.addEvent('onComplete', function(){
  1716.                         this.open = (this.now[0] === 0);
  1717.                 });
  1718.                 if (window.webkit419) this.addEvent('onComplete', function(){
  1719.                         if (this.open) this.element.remove().inject(this.wrapper);
  1720.                 });
  1721.         },
  1722.  
  1723.         setNow: function(){
  1724.                 for (var i = 0; i < 2; i++) this.now[i] = this.compute(this.from[i], this.to[i]);
  1725.         },
  1726.  
  1727.         vertical: function(){
  1728.                 this.margin = 'margin-top';
  1729.                 this.layout = 'height';
  1730.                 this.offset = this.element.offsetHeight;
  1731.         },
  1732.  
  1733.         horizontal: function(){
  1734.                 this.margin = 'margin-left';
  1735.                 this.layout = 'width';
  1736.                 this.offset = this.element.offsetWidth;
  1737.         },
  1738.  
  1739.         slideIn: function(mode){
  1740.                 this[mode || this.options.mode]();
  1741.                 return this.start([this.element.getStyle(this.margin).toInt(), this.wrapper.getStyle(this.layout).toInt()], [0, this.offset]);
  1742.         },
  1743.  
  1744.         slideOut: function(mode){
  1745.                 this[mode || this.options.mode]();
  1746.                 return this.start([this.element.getStyle(this.margin).toInt(), this.wrapper.getStyle(this.layout).toInt()], [-this.offset, 0]);
  1747.         },
  1748.  
  1749.         hide: function(mode){
  1750.                 this[mode || this.options.mode]();
  1751.                 this.open = false;
  1752.                 return this.set([-this.offset, 0]);
  1753.         },
  1754.  
  1755.         show: function(mode){
  1756.                 this[mode || this.options.mode]();
  1757.                 this.open = true;
  1758.                 return this.set([0, this.offset]);
  1759.         },
  1760.  
  1761.         toggle: function(mode){
  1762.                 if (this.wrapper.offsetHeight == 0 || this.wrapper.offsetWidth == 0) return this.slideIn(mode);
  1763.                 return this.slideOut(mode);
  1764.         },
  1765.  
  1766.         increase: function(){
  1767.                 this.element.setStyle(this.margin, this.now[0] + this.options.unit);
  1768.                 this.wrapper.setStyle(this.layout, this.now[1] + this.options.unit);
  1769.         }
  1770.  
  1771. });
  1772.  
  1773. Fx.Transition = function(transition, params){
  1774.         params = params || [];
  1775.         if ($type(params) != 'array') params = [params];
  1776.         return $extend(transition, {
  1777.                 easeIn: function(pos){
  1778.                         return transition(pos, params);
  1779.                 },
  1780.                 easeOut: function(pos){
  1781.                         return 1 - transition(1 - pos, params);
  1782.                 },
  1783.                 easeInOut: function(pos){
  1784.                         return (pos <= 0.5) ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2;
  1785.                 }
  1786.         });
  1787. };
  1788.  
  1789. Fx.Transitions = new Abstract({
  1790.  
  1791.         linear: function(p){
  1792.                 return p;
  1793.         }
  1794.  
  1795. });
  1796.  
  1797. Fx.Transitions.extend = function(transitions){
  1798.         for (var transition in transitions){
  1799.                 Fx.Transitions[transition] = new Fx.Transition(transitions[transition]);
  1800.                 Fx.Transitions.compat(transition);
  1801.         }
  1802. };
  1803.  
  1804. Fx.Transitions.compat = function(transition){
  1805.         ['In', 'Out', 'InOut'].each(function(easeType){
  1806.                 Fx.Transitions[transition.toLowerCase() + easeType] = Fx.Transitions[transition]['ease' + easeType];
  1807.         });
  1808. };
  1809.  
  1810. Fx.Transitions.extend({
  1811.  
  1812.         Pow: function(p, x){
  1813.                 return Math.pow(p, x[0] || 6);
  1814.         },
  1815.  
  1816.         Expo: function(p){
  1817.                 return Math.pow(2, 8 * (p - 1));
  1818.         },
  1819.  
  1820.         Circ: function(p){
  1821.                 return 1 - Math.sin(Math.acos(p));
  1822.         },
  1823.  
  1824.         Sine: function(p){
  1825.                 return 1 - Math.sin((1 - p) * Math.PI / 2);
  1826.         },
  1827.  
  1828.         Back: function(p, x){
  1829.                 x = x[0] || 1.618;
  1830.                 return Math.pow(p, 2) * ((x + 1) * p - x);
  1831.         },
  1832.  
  1833.         Bounce: function(p){
  1834.                 var value;
  1835.                 for (var a = 0, b = 1; 1; a += b, b /= 2){
  1836.                         if (p >= (7 - 4 * a) / 11){
  1837.                                 value = - Math.pow((11 - 6 * a - 11 * p) / 4, 2) + b * b;
  1838.                                 break;
  1839.                         }
  1840.                 }
  1841.                 return value;
  1842.         },
  1843.  
  1844.         Elastic: function(p, x){
  1845.                 return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3);
  1846.         }
  1847.  
  1848. });
  1849.  
  1850. ['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){
  1851.         Fx.Transitions[transition] = new Fx.Transition(function(p){
  1852.                 return Math.pow(p, [i + 2]);
  1853.         });
  1854.         Fx.Transitions.compat(transition);
  1855. });
  1856.  
  1857. var Drag = {};
  1858.  
  1859. Drag.Base = new Class({
  1860.  
  1861.         options: {
  1862.                 handle: false,
  1863.                 unit: 'px',
  1864.                 onStart: Class.empty,
  1865.                 onBeforeStart: Class.empty,
  1866.                 onComplete: Class.empty,
  1867.                 onSnap: Class.empty,
  1868.                 onDrag: Class.empty,
  1869.                 limit: false,
  1870.                 modifiers: {x: 'left', y: 'top'},
  1871.                 grid: false,
  1872.                 snap: 6
  1873.         },
  1874.  
  1875.         initialize: function(el, options){
  1876.                 this.setOptions(options);
  1877.                 this.element = $(el);
  1878.                 this.handle = $(this.options.handle) || this.element;
  1879.                 this.mouse = {'now': {}, 'pos': {}};
  1880.                 this.value = {'start': {}, 'now': {}};
  1881.                 this.bound = {
  1882.                         'start': this.start.bindWithEvent(this),
  1883.                         'check': this.check.bindWithEvent(this),
  1884.                         'drag': this.drag.bindWithEvent(this),
  1885.                         'stop': this.stop.bind(this)
  1886.                 };
  1887.                 this.attach();
  1888.                 if (this.options.initialize) this.options.initialize.call(this);
  1889.         },
  1890.  
  1891.         attach: function(){
  1892.                 this.handle.addEvent('mousedown', this.bound.start);
  1893.                 return this;
  1894.         },
  1895.  
  1896.         detach: function(){
  1897.                 this.handle.removeEvent('mousedown', this.bound.start);
  1898.                 return this;
  1899.         },
  1900.  
  1901.         start: function(event){
  1902.                 this.fireEvent('onBeforeStart', this.element);
  1903.                 this.mouse.start = event.page;
  1904.                 var limit = this.options.limit;
  1905.                 this.limit = {'x': [], 'y': []};
  1906.                 for (var z in this.options.modifiers){
  1907.                         if (!this.options.modifiers[z]) continue;
  1908.                         this.value.now[z] = this.element.getStyle(this.options.modifiers[z]).toInt();
  1909.                         this.mouse.pos[z] = event.page[z] - this.value.now[z];
  1910.                         if (limit && limit[z]){
  1911.                                 for (var i = 0; i < 2; i++){
  1912.                                         if ($chk(limit[z][i])) this.limit[z][i] = ($type(limit[z][i]) == 'function') ? limit[z][i]() : limit[z][i];
  1913.                                 }
  1914.                         }
  1915.                 }
  1916.                 if ($type(this.options.grid) == 'number') this.options.grid = {'x': this.options.grid, 'y': this.options.grid};
  1917.                 document.addListener('mousemove', this.bound.check);
  1918.                 document.addListener('mouseup', this.bound.stop);
  1919.                 this.fireEvent('onStart', this.element);
  1920.                 event.stop();
  1921.         },
  1922.  
  1923.         check: function(event){
  1924.                 var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2)));
  1925.                 if (distance > this.options.snap){
  1926.                         document.removeListener('mousemove', this.bound.check);
  1927.                         document.addListener('mousemove', this.bound.drag);
  1928.                         this.drag(event);
  1929.                         this.fireEvent('onSnap', this.element);
  1930.                 }
  1931.                 event.stop();
  1932.         },
  1933.  
  1934.         drag: function(event){
  1935.                 this.out = false;
  1936.                 this.mouse.now = event.page;
  1937.                 for (var z in this.options.modifiers){
  1938.                         if (!this.options.modifiers[z]) continue;
  1939.                         this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z];
  1940.                         if (this.limit[z]){
  1941.                                 if ($chk(this.limit[z][1]) && (this.value.now[z] > this.limit[z][1])){
  1942.                                         this.value.now[z] = this.limit[z][1];
  1943.                                         this.out = true;
  1944.                                 } else if ($chk(this.limit[z][0]) && (this.value.now[z] < this.limit[z][0])){
  1945.                                         this.value.now[z] = this.limit[z][0];
  1946.                                         this.out = true;
  1947.                                 }
  1948.                         }
  1949.                         if (this.options.grid[z]) this.value.now[z] -= (this.value.now[z] % this.options.grid[z]);
  1950.                         this.element.setStyle(this.options.modifiers[z], this.value.now[z] + this.options.unit);
  1951.                 }
  1952.                 this.fireEvent('onDrag', this.element);
  1953.                 event.stop();
  1954.         },
  1955.  
  1956.         stop: function(){
  1957.                 document.removeListener('mousemove', this.bound.check);
  1958.                 document.removeListener('mousemove', this.bound.drag);
  1959.                 document.removeListener('mouseup', this.bound.stop);
  1960.                 this.fireEvent('onComplete', this.element);
  1961.         }
  1962.  
  1963. });
  1964.  
  1965. Drag.Base.implement(new Events, new Options);
  1966.  
  1967. Element.extend({
  1968.  
  1969.         makeResizable: function(options){
  1970.                 return new Drag.Base(this, $merge({modifiers: {x: 'width', y: 'height'}}, options));
  1971.         }
  1972.  
  1973. });
  1974.  
  1975. Drag.Move = Drag.Base.extend({
  1976.  
  1977.         options: {
  1978.                 droppables: [],
  1979.                 container: false,
  1980.                 overflown: []
  1981.         },
  1982.  
  1983.         initialize: function(el, options){
  1984.                 this.setOptions(options);
  1985.                 this.element = $(el);
  1986.                 this.droppables = $$(this.options.droppables);
  1987.                 this.container = $(this.options.container);
  1988.                 this.position = {'element': this.element.getStyle('position'), 'container': false};
  1989.                 if (this.container) this.position.container = this.container.getStyle('position');
  1990.                 if (!['relative', 'absolute', 'fixed'].contains(this.position.element)) this.position.element = 'absolute';
  1991.                 var top = this.element.getStyle('top').toInt();
  1992.                 var left = this.element.getStyle('left').toInt();
  1993.                 if (this.position.element == 'absolute' && !['relative', 'absolute', 'fixed'].contains(this.position.container)){
  1994.                         top = $chk(top) ? top : this.element.getTop(this.options.overflown);
  1995.                         left = $chk(left) ? left : this.element.getLeft(this.options.overflown);
  1996.                 } else {
  1997.                         top = $chk(top) ? top : 0;
  1998.                         left = $chk(left) ? left : 0;
  1999.                 }
  2000.                 this.element.setStyles({'top': top, 'left': left, 'position': this.position.element});
  2001.                 this.parent(this.element);
  2002.         },
  2003.  
  2004.         start: function(event){
  2005.                 this.overed = null;
  2006.                 if (this.container){
  2007.                         var cont = this.container.getCoordinates();
  2008.                         var el = this.element.getCoordinates();
  2009.                         if (this.position.element == 'absolute' && !['relative', 'absolute', 'fixed'].contains(this.position.container)){
  2010.                                 this.options.limit = {
  2011.                                         'x': [cont.left, cont.right - el.width],
  2012.                                         'y': [cont.top, cont.bottom - el.height]
  2013.                                 };
  2014.                         } else {
  2015.                                 this.options.limit = {
  2016.                                         'y': [0, cont.height - el.height],
  2017.                                         'x': [0, cont.width - el.width]
  2018.                                 };
  2019.                         }
  2020.                 }
  2021.                 this.parent(event);
  2022.         },
  2023.  
  2024.         drag: function(event){
  2025.                 this.parent(event);
  2026.                 var overed = this.out ? false : this.droppables.filter(this.checkAgainst, this).getLast();
  2027.                 if (this.overed != overed){
  2028.                         if (this.overed) this.overed.fireEvent('leave', [this.element, this]);
  2029.                         this.overed = overed ? overed.fireEvent('over', [this.element, this]) : null;
  2030.                 }
  2031.                 return this;
  2032.         },
  2033.  
  2034.         checkAgainst: function(el){
  2035.                 el = el.getCoordinates(this.options.overflown);
  2036.                 var now = this.mouse.now;
  2037.                 return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top);
  2038.         },
  2039.  
  2040.         stop: function(){
  2041.                 if (this.overed && !this.out) this.overed.fireEvent('drop', [this.element, this]);
  2042.                 else this.element.fireEvent('emptydrop', this);
  2043.                 this.parent();
  2044.                 return this;
  2045.         }
  2046.  
  2047. });
  2048.  
  2049. Element.extend({
  2050.  
  2051.         makeDraggable: function(options){
  2052.                 return new Drag.Move(this, options);
  2053.         }
  2054.  
  2055. });