]> www.average.org Git - mkgallery.git/blob - include/mootools.js
WIP on migratin to phatfusion slideshow
[mkgallery.git] / include / mootools.js
1 /*
2 Script: Core.js
3         Mootools - My Object Oriented javascript.
4
5 License:
6         MIT-style license.
7
8 MooTools Copyright:
9         copyright (c) 2007 Valerio Proietti, <http://mad4milk.net>
10
11 MooTools Credits:
12         - Class is slightly based on Base.js <http://dean.edwards.name/weblog/2006/03/base/> (c) 2006 Dean Edwards, License <http://creativecommons.org/licenses/LGPL/2.1/>
13         - Some functions are inspired by those found in prototype.js <http://prototype.conio.net/> (c) 2005 Sam Stephenson sam [at] conio [dot] net, MIT-style license
14         - Documentation by Aaron Newton (aaron.newton [at] cnet [dot] com) and Valerio Proietti.
15 */
16
17 var MooTools = {
18         version: '1.11'
19 };
20
21 /* Section: Core Functions */
22
23 /*
24 Function: $defined
25         Returns true if the passed in value/object is defined, that means is not null or undefined.
26
27 Arguments:
28         obj - object to inspect
29 */
30
31 function $defined(obj){
32         return (obj != undefined);
33 };
34
35 /*
36 Function: $type
37         Returns the type of object that matches the element passed in.
38
39 Arguments:
40         obj - the object to inspect.
41
42 Example:
43         >var myString = 'hello';
44         >$type(myString); //returns "string"
45
46 Returns:
47         'element' - if obj is a DOM element node
48         'textnode' - if obj is a DOM text node
49         'whitespace' - if obj is a DOM whitespace node
50         'arguments' - if obj is an arguments object
51         'object' - if obj is an object
52         'string' - if obj is a string
53         'number' - if obj is a number
54         'boolean' - if obj is a boolean
55         'function' - if obj is a function
56         'regexp' - if obj is a regular expression
57         'class' - if obj is a Class. (created with new Class, or the extend of another class).
58         'collection' - if obj is a native htmlelements collection, such as childNodes, getElementsByTagName .. etc.
59         false - (boolean) if the object is not defined or none of the above.
60 */
61
62 function $type(obj){
63         if (!$defined(obj)) return false;
64         if (obj.htmlElement) return 'element';
65         var type = typeof obj;
66         if (type == 'object' && obj.nodeName){
67                 switch(obj.nodeType){
68                         case 1: return 'element';
69                         case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
70                 }
71         }
72         if (type == 'object' || type == 'function'){
73                 switch(obj.constructor){
74                         case Array: return 'array';
75                         case RegExp: return 'regexp';
76                         case Class: return 'class';
77                 }
78                 if (typeof obj.length == 'number'){
79                         if (obj.item) return 'collection';
80                         if (obj.callee) return 'arguments';
81                 }
82         }
83         return type;
84 };
85
86 /*
87 Function: $merge
88         merges a number of objects recursively without referencing them or their sub-objects.
89
90 Arguments:
91         any number of objects.
92
93 Example:
94         >var mergedObj = $merge(obj1, obj2, obj3);
95         >//obj1, obj2, and obj3 are unaltered
96 */
97
98 function $merge(){
99         var mix = {};
100         for (var i = 0; i < arguments.length; i++){
101                 for (var property in arguments[i]){
102                         var ap = arguments[i][property];
103                         var mp = mix[property];
104                         if (mp && $type(ap) == 'object' && $type(mp) == 'object') mix[property] = $merge(mp, ap);
105                         else mix[property] = ap;
106                 }
107         }
108         return mix;
109 };
110
111 /*
112 Function: $extend
113         Copies all the properties from the second passed object to the first passed Object.
114         If you do myWhatever.extend = $extend the first parameter will become myWhatever, and your extend function will only need one parameter.
115
116 Example:
117         (start code)
118         var firstOb = {
119                 'name': 'John',
120                 'lastName': 'Doe'
121         };
122         var secondOb = {
123                 'age': '20',
124                 'sex': 'male',
125                 'lastName': 'Dorian'
126         };
127         $extend(firstOb, secondOb);
128         //firstOb will become:
129         {
130                 'name': 'John',
131                 'lastName': 'Dorian',
132                 'age': '20',
133                 'sex': 'male'
134         };
135         (end)
136
137 Returns:
138         The first object, extended.
139 */
140
141 var $extend = function(){
142         var args = arguments;
143         if (!args[1]) args = [this, args[0]];
144         for (var property in args[1]) args[0][property] = args[1][property];
145         return args[0];
146 };
147
148 /*
149 Function: $native
150         Will add a .extend method to the objects passed as a parameter, but the property passed in will be copied to the object's prototype only if non previously existent.
151         Its handy if you dont want the .extend method of an object to overwrite existing methods.
152         Used automatically in MooTools to implement Array/String/Function/Number methods to browser that dont support them whitout manual checking.
153
154 Arguments:
155         a number of classes/native javascript objects
156
157 */
158
159 var $native = function(){
160         for (var i = 0, l = arguments.length; i < l; i++){
161                 arguments[i].extend = function(props){
162                         for (var prop in props){
163                                 if (!this.prototype[prop]) this.prototype[prop] = props[prop];
164                                 if (!this[prop]) this[prop] = $native.generic(prop);
165                         }
166                 };
167         }
168 };
169
170 $native.generic = function(prop){
171         return function(bind){
172                 return this.prototype[prop].apply(bind, Array.prototype.slice.call(arguments, 1));
173         };
174 };
175
176 $native(Function, Array, String, Number);
177
178 /*
179 Function: $chk
180         Returns true if the passed in value/object exists or is 0, otherwise returns false.
181         Useful to accept zeroes.
182
183 Arguments:
184         obj - object to inspect
185 */
186
187 function $chk(obj){
188         return !!(obj || obj === 0);
189 };
190
191 /*
192 Function: $pick
193         Returns the first object if defined, otherwise returns the second.
194
195 Arguments:
196         obj - object to test
197         picked - the default to return
198
199 Example:
200         (start code)
201                 function say(msg){
202                         alert($pick(msg, 'no meessage supplied'));
203                 }
204         (end)
205 */
206
207 function $pick(obj, picked){
208         return $defined(obj) ? obj : picked;
209 };
210
211 /*
212 Function: $random
213         Returns a random integer number between the two passed in values.
214
215 Arguments:
216         min - integer, the minimum value (inclusive).
217         max - integer, the maximum value (inclusive).
218
219 Returns:
220         a random integer between min and max.
221 */
222
223 function $random(min, max){
224         return Math.floor(Math.random() * (max - min + 1) + min);
225 };
226
227 /*
228 Function: $time
229         Returns the current timestamp
230
231 Returns:
232         a timestamp integer.
233 */
234
235 function $time(){
236         return new Date().getTime();
237 };
238
239 /*
240 Function: $clear
241         clears a timeout or an Interval.
242
243 Returns:
244         null
245
246 Arguments:
247         timer - the setInterval or setTimeout to clear.
248
249 Example:
250         >var myTimer = myFunction.delay(5000); //wait 5 seconds and execute my function.
251         >myTimer = $clear(myTimer); //nevermind
252
253 See also:
254         <Function.delay>, <Function.periodical>
255 */
256
257 function $clear(timer){
258         clearTimeout(timer);
259         clearInterval(timer);
260         return null;
261 };
262
263 /*
264 Class: Abstract
265         Abstract class, to be used as singleton. Will add .extend to any object
266
267 Arguments:
268         an object
269
270 Returns:
271         the object with an .extend property, equivalent to <$extend>.
272 */
273
274 var Abstract = function(obj){
275         obj = obj || {};
276         obj.extend = $extend;
277         return obj;
278 };
279
280 //window, document
281
282 var Window = new Abstract(window);
283 var Document = new Abstract(document);
284 document.head = document.getElementsByTagName('head')[0];
285
286 /*
287 Class: window
288         Some properties are attached to the window object by the browser detection.
289         
290 Note:
291         browser detection is entirely object-based. We dont sniff.
292
293 Properties:
294         window.ie - will be set to true if the current browser is internet explorer (any).
295         window.ie6 - will be set to true if the current browser is internet explorer 6.
296         window.ie7 - will be set to true if the current browser is internet explorer 7.
297         window.gecko - will be set to true if the current browser is Mozilla/Gecko.
298         window.webkit - will be set to true if the current browser is Safari/Konqueror.
299         window.webkit419 - will be set to true if the current browser is Safari2 / webkit till version 419.
300         window.webkit420 - will be set to true if the current browser is Safari3 (Webkit SVN Build) / webkit over version 419.
301         window.opera - is set to true by opera itself.
302 */
303
304 window.xpath = !!(document.evaluate);
305 if (window.ActiveXObject) window.ie = window[window.XMLHttpRequest ? 'ie7' : 'ie6'] = true;
306 else if (document.childNodes && !document.all && !navigator.taintEnabled) window.webkit = window[window.xpath ? 'webkit420' : 'webkit419'] = true;
307 else if (document.getBoxObjectFor != null) window.gecko = true;
308
309 /*compatibility*/
310
311 window.khtml = window.webkit;
312
313 Object.extend = $extend;
314
315 /*end compatibility*/
316
317 //htmlelement
318
319 if (typeof HTMLElement == 'undefined'){
320         var HTMLElement = function(){};
321         if (window.webkit) document.createElement("iframe"); //fixes safari
322         HTMLElement.prototype = (window.webkit) ? window["[[DOMElement.prototype]]"] : {};
323 }
324 HTMLElement.prototype.htmlElement = function(){};
325
326 //enables background image cache for internet explorer 6
327
328 if (window.ie6) try {document.execCommand("BackgroundImageCache", false, true);} catch(e){};
329
330 /*
331 Script: Class.js
332         Contains the Class Function, aims to ease the creation of reusable Classes.
333
334 License:
335         MIT-style license.
336 */
337
338 /*
339 Class: Class
340         The base class object of the <http://mootools.net> framework.
341         Creates a new class, its initialize method will fire upon class instantiation.
342         Initialize wont fire on instantiation when you pass *null*.
343
344 Arguments:
345         properties - the collection of properties that apply to the class.
346
347 Example:
348         (start code)
349         var Cat = new Class({
350                 initialize: function(name){
351                         this.name = name;
352                 }
353         });
354         var myCat = new Cat('Micia');
355         alert(myCat.name); //alerts 'Micia'
356         (end)
357 */
358
359 var Class = function(properties){
360         var klass = function(){
361                 return (arguments[0] !== null && this.initialize && $type(this.initialize) == 'function') ? this.initialize.apply(this, arguments) : this;
362         };
363         $extend(klass, this);
364         klass.prototype = properties;
365         klass.constructor = Class;
366         return klass;
367 };
368
369 /*
370 Property: empty
371         Returns an empty function
372 */
373
374 Class.empty = function(){};
375
376 Class.prototype = {
377
378         /*
379         Property: extend
380                 Returns the copy of the Class extended with the passed in properties.
381
382         Arguments:
383                 properties - the properties to add to the base class in this new Class.
384
385         Example:
386                 (start code)
387                 var Animal = new Class({
388                         initialize: function(age){
389                                 this.age = age;
390                         }
391                 });
392                 var Cat = Animal.extend({
393                         initialize: function(name, age){
394                                 this.parent(age); //will call the previous initialize;
395                                 this.name = name;
396                         }
397                 });
398                 var myCat = new Cat('Micia', 20);
399                 alert(myCat.name); //alerts 'Micia'
400                 alert(myCat.age); //alerts 20
401                 (end)
402         */
403
404         extend: function(properties){
405                 var proto = new this(null);
406                 for (var property in properties){
407                         var pp = proto[property];
408                         proto[property] = Class.Merge(pp, properties[property]);
409                 }
410                 return new Class(proto);
411         },
412
413         /*
414         Property: implement
415                 Implements the passed in properties to the base Class prototypes, altering the base class, unlike <Class.extend>.
416
417         Arguments:
418                 properties - the properties to add to the base class.
419
420         Example:
421                 (start code)
422                 var Animal = new Class({
423                         initialize: function(age){
424                                 this.age = age;
425                         }
426                 });
427                 Animal.implement({
428                         setName: function(name){
429                                 this.name = name
430                         }
431                 });
432                 var myAnimal = new Animal(20);
433                 myAnimal.setName('Micia');
434                 alert(myAnimal.name); //alerts 'Micia'
435                 (end)
436         */
437
438         implement: function(){
439                 for (var i = 0, l = arguments.length; i < l; i++) $extend(this.prototype, arguments[i]);
440         }
441
442 };
443
444 //internal
445
446 Class.Merge = function(previous, current){
447         if (previous && previous != current){
448                 var type = $type(current);
449                 if (type != $type(previous)) return current;
450                 switch(type){
451                         case 'function':
452                                 var merged = function(){
453                                         this.parent = arguments.callee.parent;
454                                         return current.apply(this, arguments);
455                                 };
456                                 merged.parent = previous;
457                                 return merged;
458                         case 'object': return $merge(previous, current);
459                 }
460         }
461         return current;
462 };
463
464 /*
465 Script: Class.Extras.js
466         Contains common implementations for custom classes. In Mootools is implemented in <Ajax>, <XHR> and <Fx.Base> and many more.
467
468 License:
469         MIT-style license.
470 */
471
472 /*
473 Class: Chain
474         An "Utility" Class. Its methods can be implemented with <Class.implement> into any <Class>.
475         Currently implemented in <Fx.Base>, <XHR> and <Ajax>. In <Fx.Base> for example, is used to execute a list of function, one after another, once the effect is completed.
476         The functions will not be fired all togheter, but one every completion, to create custom complex animations.
477
478 Example:
479         (start code)
480         var myFx = new Fx.Style('element', 'opacity');
481
482         myFx.start(1,0).chain(function(){
483                 myFx.start(0,1);
484         }).chain(function(){
485                 myFx.start(1,0);
486         }).chain(function(){
487                 myFx.start(0,1);
488         });
489         //the element will appear and disappear three times
490         (end)
491 */
492
493 var Chain = new Class({
494
495         /*
496         Property: chain
497                 adds a function to the Chain instance stack.
498
499         Arguments:
500                 fn - the function to append.
501         */
502
503         chain: function(fn){
504                 this.chains = this.chains || [];
505                 this.chains.push(fn);
506                 return this;
507         },
508
509         /*
510         Property: callChain
511                 Executes the first function of the Chain instance stack, then removes it. The first function will then become the second.
512         */
513
514         callChain: function(){
515                 if (this.chains && this.chains.length) this.chains.shift().delay(10, this);
516         },
517
518         /*
519         Property: clearChain
520                 Clears the stack of a Chain instance.
521         */
522
523         clearChain: function(){
524                 this.chains = [];
525         }
526
527 });
528
529 /*
530 Class: Events
531         An "Utility" Class. Its methods can be implemented with <Class.implement> into any <Class>.
532         In <Fx.Base> Class, for example, is used to give the possibility add any number of functions to the Effects events, like onComplete, onStart, onCancel.
533         Events in a Class that implements <Events> can be either added as an option, or with addEvent. Never with .options.onEventName.
534
535 Example:
536         (start code)
537         var myFx = new Fx.Style('element', 'opacity').addEvent('onComplete', function(){
538                 alert('the effect is completed');
539         }).addEvent('onComplete', function(){
540                 alert('I told you the effect is completed');
541         });
542
543         myFx.start(0,1);
544         //upon completion it will display the 2 alerts, in order.
545         (end)
546
547 Implementing:
548         This class can be implemented into other classes to add the functionality to them.
549         Goes well with the <Options> class.
550
551 Example:
552         (start code)
553         var Widget = new Class({
554                 initialize: function(){},
555                 finish: function(){
556                         this.fireEvent('onComplete');
557                 }
558         });
559         Widget.implement(new Events);
560         //later...
561         var myWidget = new Widget();
562         myWidget.addEvent('onComplete', myfunction);
563         (end)
564 */
565
566 var Events = new Class({
567
568         /*
569         Property: addEvent
570                 adds an event to the stack of events of the Class instance.
571
572         Arguments:
573                 type - string; the event name (e.g. 'onComplete')
574                 fn - function to execute
575         */
576
577         addEvent: function(type, fn){
578                 if (fn != Class.empty){
579                         this.$events = this.$events || {};
580                         this.$events[type] = this.$events[type] || [];
581                         this.$events[type].include(fn);
582                 }
583                 return this;
584         },
585
586         /*
587         Property: fireEvent
588                 fires all events of the specified type in the Class instance.
589
590         Arguments:
591                 type - string; the event name (e.g. 'onComplete')
592                 args - array or single object; arguments to pass to the function; if more than one argument, must be an array
593                 delay - (integer) delay (in ms) to wait to execute the event
594
595         Example:
596         (start code)
597         var Widget = new Class({
598                 initialize: function(arg1, arg2){
599                         ...
600                         this.fireEvent("onInitialize", [arg1, arg2], 50);
601                 }
602         });
603         Widget.implement(new Events);
604         (end)
605         */
606
607         fireEvent: function(type, args, delay){
608                 if (this.$events && this.$events[type]){
609                         this.$events[type].each(function(fn){
610                                 fn.create({'bind': this, 'delay': delay, 'arguments': args})();
611                         }, this);
612                 }
613                 return this;
614         },
615
616         /*
617         Property: removeEvent
618                 removes an event from the stack of events of the Class instance.
619
620         Arguments:
621                 type - string; the event name (e.g. 'onComplete')
622                 fn - function that was added
623         */
624
625         removeEvent: function(type, fn){
626                 if (this.$events && this.$events[type]) this.$events[type].remove(fn);
627                 return this;
628         }
629
630 });
631
632 /*
633 Class: Options
634         An "Utility" Class. Its methods can be implemented with <Class.implement> into any <Class>.
635         Used to automate the options settings, also adding Class <Events> when the option begins with on.
636
637         Example:
638                 (start code)
639                 var Widget = new Class({
640                         options: {
641                                 color: '#fff',
642                                 size: {
643                                         width: 100
644                                         height: 100
645                                 }
646                         },
647                         initialize: function(options){
648                                 this.setOptions(options);
649                         }
650                 });
651                 Widget.implement(new Options);
652                 //later...
653                 var myWidget = new Widget({
654                         color: '#f00',
655                         size: {
656                                 width: 200
657                         }
658                 });
659                 //myWidget.options = {color: #f00, size: {width: 200, height: 100}}
660                 (end)
661 */
662
663 var Options = new Class({
664
665         /*
666         Property: setOptions
667                 sets this.options
668
669         Arguments:
670                 defaults - object; the default set of options
671                 options - object; the user entered options. can be empty too.
672
673         Note:
674                 if your Class has <Events> implemented, every option beginning with on, followed by a capital letter (onComplete) becomes an Class instance event.
675         */
676
677         setOptions: function(){
678                 this.options = $merge.apply(null, [this.options].extend(arguments));
679                 if (this.addEvent){
680                         for (var option in this.options){
681                                 if ($type(this.options[option] == 'function') && (/^on[A-Z]/).test(option)) this.addEvent(option, this.options[option]);
682                         }
683                 }
684                 return this;
685         }
686
687 });
688
689 /*
690 Script: Array.js
691         Contains Array prototypes, <$A>, <$each>
692
693 License:
694         MIT-style license.
695 */
696
697 /*
698 Class: Array
699         A collection of The Array Object prototype methods.
700 */
701
702 //custom methods
703
704 Array.extend({
705
706         /*
707         Property: forEach
708                 Iterates through an array; This method is only available for browsers without native *forEach* support.
709                 For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:forEach>
710
711                 *forEach* executes the provided function (callback) once for each element present in the array. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.
712
713         Arguments:
714                 fn - function to execute with each item in the array; passed the item and the index of that item in the array
715                 bind - the object to bind "this" to (see <Function.bind>)
716
717         Example:
718                 >['apple','banana','lemon'].each(function(item, index){
719                 >       alert(index + " = " + item); //alerts "0 = apple" etc.
720                 >}, bindObj); //optional second arg for binding, not used here
721         */
722
723         forEach: function(fn, bind){
724                 for (var i = 0, j = this.length; i < j; i++) fn.call(bind, this[i], i, this);
725         },
726
727         /*
728         Property: filter
729                 This method is provided only for browsers without native *filter* support.
730                 For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:filter>
731
732                 *filter* calls a provided callback function once for each element in an array, and constructs a new array of all the values for which callback returns a true value. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values. Array elements which do not pass the callback test are simply skipped, and are not included in the new array.
733
734         Arguments:
735                 fn - function to execute with each item in the array; passed the item and the index of that item in the array
736                 bind - the object to bind "this" to (see <Function.bind>)
737
738         Example:
739                 >var biggerThanTwenty = [10,3,25,100].filter(function(item, index){
740                 > return item > 20;
741                 >});
742                 >//biggerThanTwenty = [25,100]
743         */
744
745         filter: function(fn, bind){
746                 var results = [];
747                 for (var i = 0, j = this.length; i < j; i++){
748                         if (fn.call(bind, this[i], i, this)) results.push(this[i]);
749                 }
750                 return results;
751         },
752
753         /*
754         Property: map
755                 This method is provided only for browsers without native *map* support.
756                 For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:map>
757
758                 *map* calls a provided callback function once for each element in an array, in order, and constructs a new array from the results. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.
759
760         Arguments:
761                 fn - function to execute with each item in the array; passed the item and the index of that item in the array
762                 bind - the object to bind "this" to (see <Function.bind>)
763
764         Example:
765                 >var timesTwo = [1,2,3].map(function(item, index){
766                 > return item*2;
767                 >});
768                 >//timesTwo = [2,4,6];
769         */
770
771         map: function(fn, bind){
772                 var results = [];
773                 for (var i = 0, j = this.length; i < j; i++) results[i] = fn.call(bind, this[i], i, this);
774                 return results;
775         },
776
777         /*
778         Property: every
779                 This method is provided only for browsers without native *every* support.
780                 For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every>
781
782                 *every* executes the provided callback function once for each element present in the array until it finds one where callback returns a false value. If such an element is found, the every method immediately returns false. Otherwise, if callback returned a true value for all elements, every will return true. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.
783
784         Arguments:
785                 fn - function to execute with each item in the array; passed the item and the index of that item in the array
786                 bind - the object to bind "this" to (see <Function.bind>)
787
788         Example:
789                 >var areAllBigEnough = [10,4,25,100].every(function(item, index){
790                 > return item > 20;
791                 >});
792                 >//areAllBigEnough = false
793         */
794
795         every: function(fn, bind){
796                 for (var i = 0, j = this.length; i < j; i++){
797                         if (!fn.call(bind, this[i], i, this)) return false;
798                 }
799                 return true;
800         },
801
802         /*
803         Property: some
804                 This method is provided only for browsers without native *some* support.
805                 For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some>
806
807                 *some* executes the callback function once for each element present in the array until it finds one where callback returns a true value. If such an element is found, some immediately returns true. Otherwise, some returns false. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.
808
809         Arguments:
810                 fn - function to execute with each item in the array; passed the item and the index of that item in the array
811                 bind - the object to bind "this" to (see <Function.bind>)
812
813         Example:
814                 >var isAnyBigEnough = [10,4,25,100].some(function(item, index){
815                 > return item > 20;
816                 >});
817                 >//isAnyBigEnough = true
818         */
819
820         some: function(fn, bind){
821                 for (var i = 0, j = this.length; i < j; i++){
822                         if (fn.call(bind, this[i], i, this)) return true;
823                 }
824                 return false;
825         },
826
827         /*
828         Property: indexOf
829                 This method is provided only for browsers without native *indexOf* support.
830                 For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf>
831
832                 *indexOf* compares a search element to elements of the Array using strict equality (the same method used by the ===, or triple-equals, operator).
833
834         Arguments:
835                 item - any type of object; element to locate in the array
836                 from - integer; optional; the index of the array at which to begin the search (defaults to 0)
837
838         Example:
839                 >['apple','lemon','banana'].indexOf('lemon'); //returns 1
840                 >['apple','lemon'].indexOf('banana'); //returns -1
841         */
842
843         indexOf: function(item, from){
844                 var len = this.length;
845                 for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){
846                         if (this[i] === item) return i;
847                 }
848                 return -1;
849         },
850
851         /*
852         Property: each
853                 Same as <Array.forEach>.
854
855         Arguments:
856                 fn - function to execute with each item in the array; passed the item and the index of that item in the array
857                 bind - optional, the object that the "this" of the function will refer to.
858
859         Example:
860                 >var Animals = ['Cat', 'Dog', 'Coala'];
861                 >Animals.each(function(animal){
862                 >       document.write(animal)
863                 >});
864         */
865
866         /*
867         Property: copy
868                 returns a copy of the array.
869
870         Returns:
871                 a new array which is a copy of the current one.
872
873         Arguments:
874                 start - integer; optional; the index where to start the copy, default is 0. If negative, it is taken as the offset from the end of the array.
875                 length - integer; optional; the number of elements to copy. By default, copies all elements from start to the end of the array.
876
877         Example:
878                 >var letters = ["a","b","c"];
879                 >var copy = letters.copy();             // ["a","b","c"] (new instance)
880         */
881
882         copy: function(start, length){
883                 start = start || 0;
884                 if (start < 0) start = this.length + start;
885                 length = length || (this.length - start);
886                 var newArray = [];
887                 for (var i = 0; i < length; i++) newArray[i] = this[start++];
888                 return newArray;
889         },
890
891         /*
892         Property: remove
893                 Removes all occurrences of an item from the array.
894
895         Arguments:
896                 item - the item to remove
897
898         Returns:
899                 the Array with all occurrences of the item removed.
900
901         Example:
902                 >["1","2","3","2"].remove("2") // ["1","3"];
903         */
904
905         remove: function(item){
906                 var i = 0;
907                 var len = this.length;
908                 while (i < len){
909                         if (this[i] === item){
910                                 this.splice(i, 1);
911                                 len--;
912                         } else {
913                                 i++;
914                         }
915                 }
916                 return this;
917         },
918
919         /*
920         Property: contains
921                 Tests an array for the presence of an item.
922
923         Arguments:
924                 item - the item to search for in the array.
925                 from - integer; optional; the index at which to begin the search, default is 0. If negative, it is taken as the offset from the end of the array.
926
927         Returns:
928                 true - the item was found
929                 false - it wasn't
930
931         Example:
932                 >["a","b","c"].contains("a"); // true
933                 >["a","b","c"].contains("d"); // false
934         */
935
936         contains: function(item, from){
937                 return this.indexOf(item, from) != -1;
938         },
939
940         /*
941         Property: associate
942                 Creates an object with key-value pairs based on the array of keywords passed in
943                 and the current content of the array.
944
945         Arguments:
946                 keys - the array of keywords.
947
948         Example:
949                 (start code)
950                 var Animals = ['Cat', 'Dog', 'Coala', 'Lizard'];
951                 var Speech = ['Miao', 'Bau', 'Fruuu', 'Mute'];
952                 var Speeches = Animals.associate(Speech);
953                 //Speeches['Miao'] is now Cat.
954                 //Speeches['Bau'] is now Dog.
955                 //...
956                 (end)
957         */
958
959         associate: function(keys){
960                 var obj = {}, length = Math.min(this.length, keys.length);
961                 for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
962                 return obj;
963         },
964
965         /*
966         Property: extend
967                 Extends an array with another one.
968
969         Arguments:
970                 array - the array to extend ours with
971
972         Example:
973                 >var Animals = ['Cat', 'Dog', 'Coala'];
974                 >Animals.extend(['Lizard']);
975                 >//Animals is now: ['Cat', 'Dog', 'Coala', 'Lizard'];
976         */
977
978         extend: function(array){
979                 for (var i = 0, j = array.length; i < j; i++) this.push(array[i]);
980                 return this;
981         },
982
983         /*
984         Property: merge
985                 merges an array in another array, without duplicates. (case- and type-sensitive)
986
987         Arguments:
988                 array - the array to merge from.
989
990         Example:
991                 >['Cat','Dog'].merge(['Dog','Coala']); //returns ['Cat','Dog','Coala']
992         */
993
994         merge: function(array){
995                 for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
996                 return this;
997         },
998
999         /*
1000         Property: include
1001                 includes the passed in element in the array, only if its not already present. (case- and type-sensitive)
1002
1003         Arguments:
1004                 item - item to add to the array (if not present)
1005
1006         Example:
1007                 >['Cat','Dog'].include('Dog'); //returns ['Cat','Dog']
1008                 >['Cat','Dog'].include('Coala'); //returns ['Cat','Dog','Coala']
1009         */
1010
1011         include: function(item){
1012                 if (!this.contains(item)) this.push(item);
1013                 return this;
1014         },
1015
1016         /*
1017         Property: getRandom
1018                 returns a random item in the Array
1019         */
1020
1021         getRandom: function(){
1022                 return this[$random(0, this.length - 1)] || null;
1023         },
1024
1025         /*
1026         Property: getLast
1027                 returns the last item in the Array
1028         */
1029
1030         getLast: function(){
1031                 return this[this.length - 1] || null;
1032         }
1033
1034 });
1035
1036 //copies
1037
1038 Array.prototype.each = Array.prototype.forEach;
1039 Array.each = Array.forEach;
1040
1041 /* Section: Utility Functions */
1042
1043 /*
1044 Function: $A()
1045         Same as <Array.copy>, but as function.
1046         Useful to apply Array prototypes to iterable objects, as a collection of DOM elements or the arguments object.
1047
1048 Example:
1049         (start code)
1050         function myFunction(){
1051                 $A(arguments).each(argument, function(){
1052                         alert(argument);
1053                 });
1054         };
1055         //the above will alert all the arguments passed to the function myFunction.
1056         (end)
1057 */
1058
1059 function $A(array){
1060         return Array.copy(array);
1061 };
1062
1063 /*
1064 Function: $each
1065         Use to iterate through iterables that are not regular arrays, such as builtin getElementsByTagName calls, arguments of a function, or an object.
1066
1067 Arguments:
1068         iterable - an iterable element or an objct.
1069         function - function to apply to the iterable.
1070         bind - optional, the 'this' of the function will refer to this object.
1071
1072 Function argument:
1073         The function argument will be passed the following arguments.
1074
1075         item - the current item in the iterator being procesed
1076         index - integer; the index of the item, or key in case of an object.
1077
1078 Examples:
1079         (start code)
1080         $each(['Sun','Mon','Tue'], function(day, index){
1081                 alert('name:' + day + ', index: ' + index);
1082         });
1083         //alerts "name: Sun, index: 0", "name: Mon, index: 1", etc.
1084         //over an object
1085         $each({first: "Sunday", second: "Monday", third: "Tuesday"}, function(value, key){
1086                 alert("the " + key + " day of the week is " + value);
1087         });
1088         //alerts "the first day of the week is Sunday",
1089         //"the second day of the week is Monday", etc.
1090         (end)
1091 */
1092
1093 function $each(iterable, fn, bind){
1094         if (iterable && typeof iterable.length == 'number' && $type(iterable) != 'object'){
1095                 Array.forEach(iterable, fn, bind);
1096         } else {
1097                  for (var name in iterable) fn.call(bind || iterable, iterable[name], name);
1098         }
1099 };
1100
1101 /*compatibility*/
1102
1103 Array.prototype.test = Array.prototype.contains;
1104
1105 /*end compatibility*/
1106
1107 /*
1108 Script: String.js
1109         Contains String prototypes.
1110
1111 License:
1112         MIT-style license.
1113 */
1114
1115 /*
1116 Class: String
1117         A collection of The String Object prototype methods.
1118 */
1119
1120 String.extend({
1121
1122         /*
1123         Property: test
1124                 Tests a string with a regular expression.
1125
1126         Arguments:
1127                 regex - a string or regular expression object, the regular expression you want to match the string with
1128                 params - optional, if first parameter is a string, any parameters you want to pass to the regex ('g' has no effect)
1129
1130         Returns:
1131                 true if a match for the regular expression is found in the string, false if not.
1132                 See <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:RegExp:test>
1133
1134         Example:
1135                 >"I like cookies".test("cookie"); // returns true
1136                 >"I like cookies".test("COOKIE", "i") // ignore case, returns true
1137                 >"I like cookies".test("cake"); // returns false
1138         */
1139
1140         test: function(regex, params){
1141                 return (($type(regex) == 'string') ? new RegExp(regex, params) : regex).test(this);
1142         },
1143
1144         /*
1145         Property: toInt
1146                 parses a string to an integer.
1147
1148         Returns:
1149                 either an int or "NaN" if the string is not a number.
1150
1151         Example:
1152                 >var value = "10px".toInt(); // value is 10
1153         */
1154
1155         toInt: function(){
1156                 return parseInt(this, 10);
1157         },
1158
1159         /*
1160         Property: toFloat
1161                 parses a string to an float.
1162
1163         Returns:
1164                 either a float or "NaN" if the string is not a number.
1165
1166         Example:
1167                 >var value = "10.848".toFloat(); // value is 10.848
1168         */
1169
1170         toFloat: function(){
1171                 return parseFloat(this);
1172         },
1173
1174         /*
1175         Property: camelCase
1176                 Converts a hiphenated string to a camelcase string.
1177
1178         Example:
1179                 >"I-like-cookies".camelCase(); //"ILikeCookies"
1180
1181         Returns:
1182                 the camel cased string
1183         */
1184
1185         camelCase: function(){
1186                 return this.replace(/-\D/g, function(match){
1187                         return match.charAt(1).toUpperCase();
1188                 });
1189         },
1190
1191         /*
1192         Property: hyphenate
1193                 Converts a camelCased string to a hyphen-ated string.
1194
1195         Example:
1196                 >"ILikeCookies".hyphenate(); //"I-like-cookies"
1197         */
1198
1199         hyphenate: function(){
1200                 return this.replace(/\w[A-Z]/g, function(match){
1201                         return (match.charAt(0) + '-' + match.charAt(1).toLowerCase());
1202                 });
1203         },
1204
1205         /*
1206         Property: capitalize
1207                 Converts the first letter in each word of a string to Uppercase.
1208
1209         Example:
1210                 >"i like cookies".capitalize(); //"I Like Cookies"
1211
1212         Returns:
1213                 the capitalized string
1214         */
1215
1216         capitalize: function(){
1217                 return this.replace(/\b[a-z]/g, function(match){
1218                         return match.toUpperCase();
1219                 });
1220         },
1221
1222         /*
1223         Property: trim
1224                 Trims the leading and trailing spaces off a string.
1225
1226         Example:
1227                 >"    i like cookies     ".trim() //"i like cookies"
1228
1229         Returns:
1230                 the trimmed string
1231         */
1232
1233         trim: function(){
1234                 return this.replace(/^\s+|\s+$/g, '');
1235         },
1236
1237         /*
1238         Property: clean
1239                 trims (<String.trim>) a string AND removes all the double spaces in a string.
1240
1241         Returns:
1242                 the cleaned string
1243
1244         Example:
1245                 >" i      like     cookies      \n\n".clean() //"i like cookies"
1246         */
1247
1248         clean: function(){
1249                 return this.replace(/\s{2,}/g, ' ').trim();
1250         },
1251
1252         /*
1253         Property: rgbToHex
1254                 Converts an RGB value to hexidecimal. The string must be in the format of "rgb(255,255,255)" or "rgba(255,255,255,1)";
1255
1256         Arguments:
1257                 array - boolean value, defaults to false. Use true if you want the array ['FF','33','00'] as output instead of "#FF3300"
1258
1259         Returns:
1260                 hex string or array. returns "transparent" if the output is set as string and the fourth value of rgba in input string is 0.
1261
1262         Example:
1263                 >"rgb(17,34,51)".rgbToHex(); //"#112233"
1264                 >"rgba(17,34,51,0)".rgbToHex(); //"transparent"
1265                 >"rgb(17,34,51)".rgbToHex(true); //['11','22','33']
1266         */
1267
1268         rgbToHex: function(array){
1269                 var rgb = this.match(/\d{1,3}/g);
1270                 return (rgb) ? rgb.rgbToHex(array) : false;
1271         },
1272
1273         /*
1274         Property: hexToRgb
1275                 Converts a hexidecimal color value to RGB. Input string must be the hex color value (with or without the hash). Also accepts triplets ('333');
1276
1277         Arguments:
1278                 array - boolean value, defaults to false. Use true if you want the array [255,255,255] as output instead of "rgb(255,255,255)";
1279
1280         Returns:
1281                 rgb string or array.
1282
1283         Example:
1284                 >"#112233".hexToRgb(); //"rgb(17,34,51)"
1285                 >"#112233".hexToRgb(true); //[17,34,51]
1286         */
1287
1288         hexToRgb: function(array){
1289                 var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
1290                 return (hex) ? hex.slice(1).hexToRgb(array) : false;
1291         },
1292
1293         /*
1294         Property: contains
1295                 checks if the passed in string is contained in the String. also accepts an optional second parameter, to check if the string is contained in a list of separated values.
1296
1297         Example:
1298                 >'a b c'.contains('c', ' '); //true
1299                 >'a bc'.contains('bc'); //true
1300                 >'a bc'.contains('b', ' '); //false
1301         */
1302
1303         contains: function(string, s){
1304                 return (s) ? (s + this + s).indexOf(s + string + s) > -1 : this.indexOf(string) > -1;
1305         },
1306
1307         /*
1308         Property: escapeRegExp
1309                 Returns string with escaped regular expression characters
1310
1311         Example:
1312                 >var search = 'animals.sheeps[1]'.escapeRegExp(); // search is now 'animals\.sheeps\[1\]'
1313
1314         Returns:
1315                 Escaped string
1316         */
1317
1318         escapeRegExp: function(){
1319                 return this.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
1320         }
1321
1322 });
1323
1324 Array.extend({
1325
1326         /*
1327         Property: rgbToHex
1328                 see <String.rgbToHex>, but as an array method.
1329         */
1330
1331         rgbToHex: function(array){
1332                 if (this.length < 3) return false;
1333                 if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
1334                 var hex = [];
1335                 for (var i = 0; i < 3; i++){
1336                         var bit = (this[i] - 0).toString(16);
1337                         hex.push((bit.length == 1) ? '0' + bit : bit);
1338                 }
1339                 return array ? hex : '#' + hex.join('');
1340         },
1341
1342         /*
1343         Property: hexToRgb
1344                 same as <String.hexToRgb>, but as an array method.
1345         */
1346
1347         hexToRgb: function(array){
1348                 if (this.length != 3) return false;
1349                 var rgb = [];
1350                 for (var i = 0; i < 3; i++){
1351                         rgb.push(parseInt((this[i].length == 1) ? this[i] + this[i] : this[i], 16));
1352                 }
1353                 return array ? rgb : 'rgb(' + rgb.join(',') + ')';
1354         }
1355
1356 });
1357
1358 /* 
1359 Script: Function.js
1360         Contains Function prototypes and utility functions .
1361
1362 License:
1363         MIT-style license.
1364
1365 Credits:
1366         - Some functions are inspired by those found in prototype.js <http://prototype.conio.net/> (c) 2005 Sam Stephenson sam [at] conio [dot] net, MIT-style license
1367 */
1368
1369 /*
1370 Class: Function
1371         A collection of The Function Object prototype methods.
1372 */
1373
1374 Function.extend({
1375
1376         /*
1377         Property: create
1378                 Main function to create closures.
1379
1380         Returns:
1381                 a function.
1382
1383         Arguments:
1384                 options - An Options object.
1385
1386         Options:
1387                 bind - The object that the "this" of the function will refer to. Default is the current function.
1388                 event - If set to true, the function will act as an event listener and receive an event as first argument.
1389                                 If set to a class name, the function will receive a new instance of this class (with the event passed as argument's constructor) as first argument.
1390                                 Default is false.
1391                 arguments - A single argument or array of arguments that will be passed to the function when called.
1392                 
1393                                         If both the event and arguments options are set, the event is passed as first argument and the arguments array will follow.
1394                                         
1395                                         Default is no custom arguments, the function will receive the standard arguments when called.
1396                                         
1397                 delay - Numeric value: if set, the returned function will delay the actual execution by this amount of milliseconds and return a timer handle when called.
1398                                 Default is no delay.
1399                 periodical - Numeric value: if set, the returned function will periodically perform the actual execution with this specified interval and return a timer handle when called.
1400                                 Default is no periodical execution.
1401                 attempt - If set to true, the returned function will try to execute and return either the results or false on error. Default is false.
1402         */
1403
1404         create: function(options){
1405                 var fn = this;
1406                 options = $merge({
1407                         'bind': fn,
1408                         'event': false,
1409                         'arguments': null,
1410                         'delay': false,
1411                         'periodical': false,
1412                         'attempt': false
1413                 }, options);
1414                 if ($chk(options.arguments) && $type(options.arguments) != 'array') options.arguments = [options.arguments];
1415                 return function(event){
1416                         var args;
1417                         if (options.event){
1418                                 event = event || window.event;
1419                                 args = [(options.event === true) ? event : new options.event(event)];
1420                                 if (options.arguments) args.extend(options.arguments);
1421                         }
1422                         else args = options.arguments || arguments;
1423                         var returns = function(){
1424                                 return fn.apply($pick(options.bind, fn), args);
1425                         };
1426                         if (options.delay) return setTimeout(returns, options.delay);
1427                         if (options.periodical) return setInterval(returns, options.periodical);
1428                         if (options.attempt) try {return returns();} catch(err){return false;};
1429                         return returns();
1430                 };
1431         },
1432
1433         /*
1434         Property: pass
1435                 Shortcut to create closures with arguments and bind.
1436
1437         Returns:
1438                 a function.
1439
1440         Arguments:
1441                 args - the arguments passed. must be an array if arguments > 1
1442                 bind - optional, the object that the "this" of the function will refer to.
1443
1444         Example:
1445                 >myFunction.pass([arg1, arg2], myElement);
1446         */
1447
1448         pass: function(args, bind){
1449                 return this.create({'arguments': args, 'bind': bind});
1450         },
1451
1452         /*
1453         Property: attempt
1454                 Tries to execute the function, returns either the result of the function or false on error.
1455
1456         Arguments:
1457                 args - the arguments passed. must be an array if arguments > 1
1458                 bind - optional, the object that the "this" of the function will refer to.
1459
1460         Example:
1461                 >myFunction.attempt([arg1, arg2], myElement);
1462         */
1463
1464         attempt: function(args, bind){
1465                 return this.create({'arguments': args, 'bind': bind, 'attempt': true})();
1466         },
1467
1468         /*
1469         Property: bind
1470                 method to easily create closures with "this" altered.
1471
1472         Arguments:
1473                 bind - optional, the object that the "this" of the function will refer to.
1474                 args - optional, the arguments passed. must be an array if arguments > 1
1475
1476         Returns:
1477                 a function.
1478
1479         Example:
1480                 >function myFunction(){
1481                 >       this.setStyle('color', 'red');
1482                 >       // note that 'this' here refers to myFunction, not an element
1483                 >       // we'll need to bind this function to the element we want to alter
1484                 >};
1485                 >var myBoundFunction = myFunction.bind(myElement);
1486                 >myBoundFunction(); // this will make the element myElement red.
1487         */
1488
1489         bind: function(bind, args){
1490                 return this.create({'bind': bind, 'arguments': args});
1491         },
1492
1493         /*
1494         Property: bindAsEventListener
1495                 cross browser method to pass event firer
1496
1497         Arguments:
1498                 bind - optional, the object that the "this" of the function will refer to.
1499                 args - optional, the arguments passed. must be an array if arguments > 1
1500
1501         Returns:
1502                 a function with the parameter bind as its "this" and as a pre-passed argument event or window.event, depending on the browser.
1503
1504         Example:
1505                 >function myFunction(event){
1506                 >       alert(event.clientx) //returns the coordinates of the mouse..
1507                 >};
1508                 >myElement.onclick = myFunction.bindAsEventListener(myElement);
1509         */
1510
1511         bindAsEventListener: function(bind, args){
1512                 return this.create({'bind': bind, 'event': true, 'arguments': args});
1513         },
1514
1515         /*
1516         Property: delay
1517                 Delays the execution of a function by a specified duration.
1518
1519         Arguments:
1520                 delay - the duration to wait in milliseconds.
1521                 bind - optional, the object that the "this" of the function will refer to.
1522                 args - optional, the arguments passed. must be an array if arguments > 1
1523
1524         Example:
1525                 >myFunction.delay(50, myElement) //wait 50 milliseconds, then call myFunction and bind myElement to it
1526                 >(function(){alert('one second later...')}).delay(1000); //wait a second and alert
1527         */
1528
1529         delay: function(delay, bind, args){
1530                 return this.create({'delay': delay, 'bind': bind, 'arguments': args})();
1531         },
1532
1533         /*
1534         Property: periodical
1535                 Executes a function in the specified intervals of time
1536
1537         Arguments:
1538                 interval - the duration of the intervals between executions.
1539                 bind - optional, the object that the "this" of the function will refer to.
1540                 args - optional, the arguments passed. must be an array if arguments > 1
1541         */
1542
1543         periodical: function(interval, bind, args){
1544                 return this.create({'periodical': interval, 'bind': bind, 'arguments': args})();
1545         }
1546
1547 });
1548
1549 /*
1550 Script: Number.js
1551         Contains the Number prototypes.
1552
1553 License:
1554         MIT-style license.
1555 */
1556
1557 /*
1558 Class: Number
1559         A collection of The Number Object prototype methods.
1560 */
1561
1562 Number.extend({
1563
1564         /*
1565         Property: toInt
1566                 Returns this number; useful because toInt must work on both Strings and Numbers.
1567         */
1568
1569         toInt: function(){
1570                 return parseInt(this);
1571         },
1572
1573         /*
1574         Property: toFloat
1575                 Returns this number as a float; useful because toFloat must work on both Strings and Numbers.
1576         */
1577
1578         toFloat: function(){
1579                 return parseFloat(this);
1580         },
1581
1582         /*
1583         Property: limit
1584                 Limits the number.
1585
1586         Arguments:
1587                 min - number, minimum value
1588                 max - number, maximum value
1589
1590         Returns:
1591                 the number in the given limits.
1592
1593         Example:
1594                 >(12).limit(2, 6.5)  // returns 6.5
1595                 >(-4).limit(2, 6.5)  // returns 2
1596                 >(4.3).limit(2, 6.5) // returns 4.3
1597         */
1598
1599         limit: function(min, max){
1600                 return Math.min(max, Math.max(min, this));
1601         },
1602
1603         /*
1604         Property: round
1605                 Returns the number rounded to specified precision.
1606
1607         Arguments:
1608                 precision - integer, number of digits after the decimal point. Can also be negative or zero (default).
1609
1610         Example:
1611                 >12.45.round() // returns 12
1612                 >12.45.round(1) // returns 12.5
1613                 >12.45.round(-1) // returns 10
1614
1615         Returns:
1616                 The rounded number.
1617         */
1618
1619         round: function(precision){
1620                 precision = Math.pow(10, precision || 0);
1621                 return Math.round(this * precision) / precision;
1622         },
1623
1624         /*
1625         Property: times
1626                 Executes a passed in function the specified number of times
1627
1628         Arguments:
1629                 function - the function to be executed on each iteration of the loop
1630
1631         Example:
1632                 >(4).times(alert);
1633         */
1634
1635         times: function(fn){
1636                 for (var i = 0; i < this; i++) fn(i);
1637         }
1638
1639 });
1640
1641 /*
1642 Script: Element.js
1643         Contains useful Element prototypes, to be used with the dollar function <$>.
1644
1645 License:
1646         MIT-style license.
1647
1648 Credits:
1649         - Some functions are inspired by those found in prototype.js <http://prototype.conio.net/> (c) 2005 Sam Stephenson sam [at] conio [dot] net, MIT-style license
1650 */
1651
1652 /*
1653 Class: Element
1654         Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
1655 */
1656
1657 var Element = new Class({
1658
1659         /*
1660         Property: initialize
1661                 Creates a new element of the type passed in.
1662
1663         Arguments:
1664                 el - string; the tag name for the element you wish to create. you can also pass in an element reference, in which case it will be extended.
1665                 props - object; the properties you want to add to your element.
1666                 Accepts the same keys as <Element.setProperties>, but also allows events and styles
1667
1668         Props:
1669                 the key styles will be used as setStyles, the key events will be used as addEvents. any other key is used as setProperty.
1670
1671         Example:
1672                 (start code)
1673                 new Element('a', {
1674                         'styles': {
1675                                 'display': 'block',
1676                                 'border': '1px solid black'
1677                         },
1678                         'events': {
1679                                 'click': function(){
1680                                         //aaa
1681                                 },
1682                                 'mousedown': function(){
1683                                         //aaa
1684                                 }
1685                         },
1686                         'class': 'myClassSuperClass',
1687                         'href': 'http://mad4milk.net'
1688                 });
1689
1690                 (end)
1691         */
1692
1693         initialize: function(el, props){
1694                 if ($type(el) == 'string'){
1695                         if (window.ie && props && (props.name || props.type)){
1696                                 var name = (props.name) ? ' name="' + props.name + '"' : '';
1697                                 var type = (props.type) ? ' type="' + props.type + '"' : '';
1698                                 delete props.name;
1699                                 delete props.type;
1700                                 el = '<' + el + name + type + '>';
1701                         }
1702                         el = document.createElement(el);
1703                 }
1704                 el = $(el);
1705                 return (!props || !el) ? el : el.set(props);
1706         }
1707
1708 });
1709
1710 /*
1711 Class: Elements
1712         - Every dom function such as <$$>, or in general every function that returns a collection of nodes in mootools, returns them as an Elements class.
1713         - The purpose of the Elements class is to allow <Element> methods to work also on <Elements> array.
1714         - Elements is also an Array, so it accepts all the <Array> methods.
1715         - Every node of the Elements instance is already extended with <$>.
1716
1717 Example:
1718         >$$('myselector').each(function(el){
1719         > //...
1720         >});
1721
1722         some iterations here, $$('myselector') is also an array.
1723
1724         >$$('myselector').setStyle('color', 'red');
1725         every element returned by $$('myselector') also accepts <Element> methods, in this example every element will be made red.
1726 */
1727
1728 var Elements = new Class({
1729
1730         initialize: function(elements){
1731                 return (elements) ? $extend(elements, this) : this;
1732         }
1733
1734 });
1735
1736 Elements.extend = function(props){
1737         for (var prop in props){
1738                 this.prototype[prop] = props[prop];
1739                 this[prop] = $native.generic(prop);
1740         }
1741 };
1742
1743 /*
1744 Section: Utility Functions
1745
1746 Function: $
1747         returns the element passed in with all the Element prototypes applied.
1748
1749 Arguments:
1750         el - a reference to an actual element or a string representing the id of an element
1751
1752 Example:
1753         >$('myElement') // gets a DOM element by id with all the Element prototypes applied.
1754         >var div = document.getElementById('myElement');
1755         >$(div) //returns an Element also with all the mootools extentions applied.
1756
1757         You'll use this when you aren't sure if a variable is an actual element or an id, as
1758         well as just shorthand for document.getElementById().
1759
1760 Returns:
1761         a DOM element or false (if no id was found).
1762
1763 Note:
1764         you need to call $ on an element only once to get all the prototypes.
1765         But its no harm to call it multiple times, as it will detect if it has been already extended.
1766 */
1767
1768 function $(el){
1769         if (!el) return null;
1770         if (el.htmlElement) return Garbage.collect(el);
1771         if ([window, document].contains(el)) return el;
1772         var type = $type(el);
1773         if (type == 'string'){
1774                 el = document.getElementById(el);
1775                 type = (el) ? 'element' : false;
1776         }
1777         if (type != 'element') return null;
1778         if (el.htmlElement) return Garbage.collect(el);
1779         if (['object', 'embed'].contains(el.tagName.toLowerCase())) return el;
1780         $extend(el, Element.prototype);
1781         el.htmlElement = function(){};
1782         return Garbage.collect(el);
1783 };
1784
1785 /*
1786 Function: $$
1787         Selects, and extends DOM elements. Elements arrays returned with $$ will also accept all the <Element> methods.
1788         The return type of element methods run through $$ is always an array. If the return array is only made by elements,
1789         $$ will be applied automatically.
1790
1791 Arguments:
1792         HTML Collections, arrays of elements, arrays of strings as element ids, elements, strings as selectors.
1793         Any number of the above as arguments are accepted.
1794
1795 Note:
1796         if you load <Element.Selectors.js>, $$ will also accept CSS Selectors, otherwise the only selectors supported are tag names.
1797
1798 Example:
1799         >$$('a') //an array of all anchor tags on the page
1800         >$$('a', 'b') //an array of all anchor and bold tags on the page
1801         >$$('#myElement') //array containing only the element with id = myElement. (only with <Element.Selectors.js>)
1802         >$$('#myElement a.myClass') //an array of all anchor tags with the class "myClass"
1803         >//within the DOM element with id "myElement" (only with <Element.Selectors.js>)
1804         >$$(myelement, myelement2, 'a', ['myid', myid2, 'myid3'], document.getElementsByTagName('div')) //an array containing:
1805         >// the element referenced as myelement if existing,
1806         >// the element referenced as myelement2 if existing,
1807         >// all the elements with a as tag in the page,
1808         >// the element with id = myid if existing
1809         >// the element with id = myid2 if existing
1810         >// the element with id = myid3 if existing
1811         >// all the elements with div as tag in the page
1812
1813 Returns:
1814         array - array of all the dom elements matched, extended with <$>.  Returns as <Elements>.
1815 */
1816
1817 document.getElementsBySelector = document.getElementsByTagName;
1818
1819 function $$(){
1820         var elements = [];
1821         for (var i = 0, j = arguments.length; i < j; i++){
1822                 var selector = arguments[i];
1823                 switch($type(selector)){
1824                         case 'element': elements.push(selector);
1825                         case 'boolean': break;
1826                         case false: break;
1827                         case 'string': selector = document.getElementsBySelector(selector, true);
1828                         default: elements.extend(selector);
1829                 }
1830         }
1831         return $$.unique(elements);
1832 };
1833
1834 $$.unique = function(array){
1835         var elements = [];
1836         for (var i = 0, l = array.length; i < l; i++){
1837                 if (array[i].$included) continue;
1838                 var element = $(array[i]);
1839                 if (element && !element.$included){
1840                         element.$included = true;
1841                         elements.push(element);
1842                 }
1843         }
1844         for (var n = 0, d = elements.length; n < d; n++) elements[n].$included = null;
1845         return new Elements(elements);
1846 };
1847
1848 Elements.Multi = function(property){
1849         return function(){
1850                 var args = arguments;
1851                 var items = [];
1852                 var elements = true;
1853                 for (var i = 0, j = this.length, returns; i < j; i++){
1854                         returns = this[i][property].apply(this[i], args);
1855                         if ($type(returns) != 'element') elements = false;
1856                         items.push(returns);
1857                 };
1858                 return (elements) ? $$.unique(items) : items;
1859         };
1860 };
1861
1862 Element.extend = function(properties){
1863         for (var property in properties){
1864                 HTMLElement.prototype[property] = properties[property];
1865                 Element.prototype[property] = properties[property];
1866                 Element[property] = $native.generic(property);
1867                 var elementsProperty = (Array.prototype[property]) ? property + 'Elements' : property;
1868                 Elements.prototype[elementsProperty] = Elements.Multi(property);
1869         }
1870 };
1871
1872 /*
1873 Class: Element
1874         Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
1875 */
1876
1877 Element.extend({
1878
1879         /*
1880         Property: set
1881                 you can set events, styles and properties with this shortcut. same as calling new Element.
1882         */
1883
1884         set: function(props){
1885                 for (var prop in props){
1886                         var val = props[prop];
1887                         switch(prop){
1888                                 case 'styles': this.setStyles(val); break;
1889                                 case 'events': if (this.addEvents) this.addEvents(val); break;
1890                                 case 'properties': this.setProperties(val); break;
1891                                 default: this.setProperty(prop, val);
1892                         }
1893                 }
1894                 return this;
1895         },
1896
1897         inject: function(el, where){
1898                 el = $(el);
1899                 switch(where){
1900                         case 'before': el.parentNode.insertBefore(this, el); break;
1901                         case 'after':
1902                                 var next = el.getNext();
1903                                 if (!next) el.parentNode.appendChild(this);
1904                                 else el.parentNode.insertBefore(this, next);
1905                                 break;
1906                         case 'top':
1907                                 var first = el.firstChild;
1908                                 if (first){
1909                                         el.insertBefore(this, first);
1910                                         break;
1911                                 }
1912                         default: el.appendChild(this);
1913                 }
1914                 return this;
1915         },
1916
1917         /*
1918         Property: injectBefore
1919                 Inserts the Element before the passed element.
1920
1921         Arguments:
1922                 el - an element reference or the id of the element to be injected in.
1923
1924         Example:
1925                 >html:
1926                 ><div id="myElement"></div>
1927                 ><div id="mySecondElement"></div>
1928                 >js:
1929                 >$('mySecondElement').injectBefore('myElement');
1930                 >resulting html:
1931                 ><div id="mySecondElement"></div>
1932                 ><div id="myElement"></div>
1933         */
1934
1935         injectBefore: function(el){
1936                 return this.inject(el, 'before');
1937         },
1938
1939         /*
1940         Property: injectAfter
1941                 Same as <Element.injectBefore>, but inserts the element after.
1942         */
1943
1944         injectAfter: function(el){
1945                 return this.inject(el, 'after');
1946         },
1947
1948         /*
1949         Property: injectInside
1950                 Same as <Element.injectBefore>, but inserts the element inside.
1951         */
1952
1953         injectInside: function(el){
1954                 return this.inject(el, 'bottom');
1955         },
1956
1957         /*
1958         Property: injectTop
1959                 Same as <Element.injectInside>, but inserts the element inside, at the top.
1960         */
1961
1962         injectTop: function(el){
1963                 return this.inject(el, 'top');
1964         },
1965
1966         /*
1967         Property: adopt
1968                 Inserts the passed elements inside the Element.
1969
1970         Arguments:
1971                 accepts elements references, element ids as string, selectors ($$('stuff')) / array of elements, array of ids as strings and collections.
1972         */
1973
1974         adopt: function(){
1975                 var elements = [];
1976                 $each(arguments, function(argument){
1977                         elements = elements.concat(argument);
1978                 });
1979                 $$(elements).inject(this);
1980                 return this;
1981         },
1982
1983         /*
1984         Property: remove
1985                 Removes the Element from the DOM.
1986
1987         Example:
1988                 >$('myElement').remove() //bye bye
1989         */
1990
1991         remove: function(){
1992                 return this.parentNode.removeChild(this);
1993         },
1994
1995         /*
1996         Property: clone
1997                 Clones the Element and returns the cloned one.
1998
1999         Arguments:
2000                 contents - boolean, when true the Element is cloned with childNodes, default true
2001
2002         Returns:
2003                 the cloned element
2004
2005         Example:
2006                 >var clone = $('myElement').clone().injectAfter('myElement');
2007                 >//clones the Element and append the clone after the Element.
2008         */
2009
2010         clone: function(contents){
2011                 var el = $(this.cloneNode(contents !== false));
2012                 if (!el.$events) return el;
2013                 el.$events = {};
2014                 for (var type in this.$events) el.$events[type] = {
2015                         'keys': $A(this.$events[type].keys),
2016                         'values': $A(this.$events[type].values)
2017                 };
2018                 return el.removeEvents();
2019         },
2020
2021         /*
2022         Property: replaceWith
2023                 Replaces the Element with an element passed.
2024
2025         Arguments:
2026                 el - a string representing the element to be injected in (myElementId, or div), or an element reference.
2027                 If you pass div or another tag, the element will be created.
2028
2029         Returns:
2030                 the passed in element
2031
2032         Example:
2033                 >$('myOldElement').replaceWith($('myNewElement')); //$('myOldElement') is gone, and $('myNewElement') is in its place.
2034         */
2035
2036         replaceWith: function(el){
2037                 el = $(el);
2038                 this.parentNode.replaceChild(el, this);
2039                 return el;
2040         },
2041
2042         /*
2043         Property: appendText
2044                 Appends text node to a DOM element.
2045
2046         Arguments:
2047                 text - the text to append.
2048
2049         Example:
2050                 ><div id="myElement">hey</div>
2051                 >$('myElement').appendText(' howdy'); //myElement innerHTML is now "hey howdy"
2052         */
2053
2054         appendText: function(text){
2055                 this.appendChild(document.createTextNode(text));
2056                 return this;
2057         },
2058
2059         /*
2060         Property: hasClass
2061                 Tests the Element to see if it has the passed in className.
2062
2063         Returns:
2064                 true - the Element has the class
2065                 false - it doesn't
2066
2067         Arguments:
2068                 className - string; the class name to test.
2069
2070         Example:
2071                 ><div id="myElement" class="testClass"></div>
2072                 >$('myElement').hasClass('testClass'); //returns true
2073         */
2074
2075         hasClass: function(className){
2076                 return this.className.contains(className, ' ');
2077         },
2078
2079         /*
2080         Property: addClass
2081                 Adds the passed in class to the Element, if the element doesnt already have it.
2082
2083         Arguments:
2084                 className - string; the class name to add
2085
2086         Example:
2087                 ><div id="myElement" class="testClass"></div>
2088                 >$('myElement').addClass('newClass'); //<div id="myElement" class="testClass newClass"></div>
2089         */
2090
2091         addClass: function(className){
2092                 if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean();
2093                 return this;
2094         },
2095
2096         /*
2097         Property: removeClass
2098                 Works like <Element.addClass>, but removes the class from the element.
2099         */
2100
2101         removeClass: function(className){
2102                 this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1').clean();
2103                 return this;
2104         },
2105
2106         /*
2107         Property: toggleClass
2108                 Adds or removes the passed in class name to the element, depending on if it's present or not.
2109
2110         Arguments:
2111                 className - the class to add or remove
2112
2113         Example:
2114                 ><div id="myElement" class="myClass"></div>
2115                 >$('myElement').toggleClass('myClass');
2116                 ><div id="myElement" class=""></div>
2117                 >$('myElement').toggleClass('myClass');
2118                 ><div id="myElement" class="myClass"></div>
2119         */
2120
2121         toggleClass: function(className){
2122                 return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
2123         },
2124
2125         /*
2126         Property: setStyle
2127                 Sets a css property to the Element.
2128
2129                 Arguments:
2130                         property - the property to set
2131                         value - the value to which to set it; for numeric values that require "px" you can pass an integer
2132
2133                 Example:
2134                         >$('myElement').setStyle('width', '300px'); //the width is now 300px
2135                         >$('myElement').setStyle('width', 300); //the width is now 300px
2136         */
2137
2138         setStyle: function(property, value){
2139                 switch(property){
2140                         case 'opacity': return this.setOpacity(parseFloat(value));
2141                         case 'float': property = (window.ie) ? 'styleFloat' : 'cssFloat';
2142                 }
2143                 property = property.camelCase();
2144                 switch($type(value)){
2145                         case 'number': if (!['zIndex', 'zoom'].contains(property)) value += 'px'; break;
2146                         case 'array': value = 'rgb(' + value.join(',') + ')';
2147                 }
2148                 this.style[property] = value;
2149                 return this;
2150         },
2151
2152         /*
2153         Property: setStyles
2154                 Applies a collection of styles to the Element.
2155
2156         Arguments:
2157                 source - an object or string containing all the styles to apply. When its a string it overrides old style.
2158
2159         Examples:
2160                 >$('myElement').setStyles({
2161                 >       border: '1px solid #000',
2162                 >       width: 300,
2163                 >       height: 400
2164                 >});
2165
2166                 OR
2167
2168                 >$('myElement').setStyles('border: 1px solid #000; width: 300px; height: 400px;');
2169         */
2170
2171         setStyles: function(source){
2172                 switch($type(source)){
2173                         case 'object': Element.setMany(this, 'setStyle', source); break;
2174                         case 'string': this.style.cssText = source;
2175                 }
2176                 return this;
2177         },
2178
2179         /*
2180         Property: setOpacity
2181                 Sets the opacity of the Element, and sets also visibility == "hidden" if opacity == 0, and visibility = "visible" if opacity > 0.
2182
2183         Arguments:
2184                 opacity - float; Accepts values from 0 to 1.
2185
2186         Example:
2187                 >$('myElement').setOpacity(0.5) //make it 50% transparent
2188         */
2189
2190         setOpacity: function(opacity){
2191                 if (opacity == 0){
2192                         if (this.style.visibility != "hidden") this.style.visibility = "hidden";
2193                 } else {
2194                         if (this.style.visibility != "visible") this.style.visibility = "visible";
2195                 }
2196                 if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1;
2197                 if (window.ie) this.style.filter = (opacity == 1) ? '' : "alpha(opacity=" + opacity * 100 + ")";
2198                 this.style.opacity = this.$tmp.opacity = opacity;
2199                 return this;
2200         },
2201
2202         /*
2203         Property: getStyle
2204                 Returns the style of the Element given the property passed in.
2205
2206         Arguments:
2207                 property - the css style property you want to retrieve
2208
2209         Example:
2210                 >$('myElement').getStyle('width'); //returns "400px"
2211                 >//but you can also use
2212                 >$('myElement').getStyle('width').toInt(); //returns 400
2213
2214         Returns:
2215                 the style as a string
2216         */
2217
2218         getStyle: function(property){
2219                 property = property.camelCase();
2220                 var result = this.style[property];
2221                 if (!$chk(result)){
2222                         if (property == 'opacity') return this.$tmp.opacity;
2223                         result = [];
2224                         for (var style in Element.Styles){
2225                                 if (property == style){
2226                                         Element.Styles[style].each(function(s){
2227                                                 var style = this.getStyle(s);
2228                                                 result.push(parseInt(style) ? style : '0px');
2229                                         }, this);
2230                                         if (property == 'border'){
2231                                                 var every = result.every(function(bit){
2232                                                         return (bit == result[0]);
2233                                                 });
2234                                                 return (every) ? result[0] : false;
2235                                         }
2236                                         return result.join(' ');
2237                                 }
2238                         }
2239                         if (property.contains('border')){
2240                                 if (Element.Styles.border.contains(property)){
2241                                         return ['Width', 'Style', 'Color'].map(function(p){
2242                                                 return this.getStyle(property + p);
2243                                         }, this).join(' ');
2244                                 } else if (Element.borderShort.contains(property)){
2245                                         return ['Top', 'Right', 'Bottom', 'Left'].map(function(p){
2246                                                 return this.getStyle('border' + p + property.replace('border', ''));
2247                                         }, this).join(' ');
2248                                 }
2249                         }
2250                         if (document.defaultView) result = document.defaultView.getComputedStyle(this, null).getPropertyValue(property.hyphenate());
2251                         else if (this.currentStyle) result = this.currentStyle[property];
2252                 }
2253                 if (window.ie) result = Element.fixStyle(property, result, this);
2254                 if (result && property.test(/color/i) && result.contains('rgb')){
2255                         return result.split('rgb').splice(1,4).map(function(color){
2256                                 return color.rgbToHex();
2257                         }).join(' ');
2258                 }
2259                 return result;
2260         },
2261
2262         /*
2263         Property: getStyles
2264                 Returns an object of styles of the Element for each argument passed in.
2265                 Arguments:
2266                 properties - strings; any number of style properties
2267         Example:
2268                 >$('myElement').getStyles('width','height','padding');
2269                 >//returns an object like:
2270                 >{width: "10px", height: "10px", padding: "10px 0px 10px 0px"}
2271         */
2272
2273         getStyles: function(){
2274                 return Element.getMany(this, 'getStyle', arguments);
2275         },
2276
2277         walk: function(brother, start){
2278                 brother += 'Sibling';
2279                 var el = (start) ? this[start] : this[brother];
2280                 while (el && $type(el) != 'element') el = el[brother];
2281                 return $(el);
2282         },
2283
2284         /*
2285         Property: getPrevious
2286                 Returns the previousSibling of the Element, excluding text nodes.
2287
2288         Example:
2289                 >$('myElement').getPrevious(); //get the previous DOM element from myElement
2290
2291         Returns:
2292                 the sibling element or undefined if none found.
2293         */
2294
2295         getPrevious: function(){
2296                 return this.walk('previous');
2297         },
2298
2299         /*
2300         Property: getNext
2301                 Works as Element.getPrevious, but tries to find the nextSibling.
2302         */
2303
2304         getNext: function(){
2305                 return this.walk('next');
2306         },
2307
2308         /*
2309         Property: getFirst
2310                 Works as <Element.getPrevious>, but tries to find the firstChild.
2311         */
2312
2313         getFirst: function(){
2314                 return this.walk('next', 'firstChild');
2315         },
2316
2317         /*
2318         Property: getLast
2319                 Works as <Element.getPrevious>, but tries to find the lastChild.
2320         */
2321
2322         getLast: function(){
2323                 return this.walk('previous', 'lastChild');
2324         },
2325
2326         /*
2327         Property: getParent
2328                 returns the $(element.parentNode)
2329         */
2330
2331         getParent: function(){
2332                 return $(this.parentNode);
2333         },
2334
2335         /*
2336         Property: getChildren
2337                 returns all the $(element.childNodes), excluding text nodes. Returns as <Elements>.
2338         */
2339
2340         getChildren: function(){
2341                 return $$(this.childNodes);
2342         },
2343
2344         /*
2345         Property: hasChild
2346                 returns true if the passed in element is a child of the $(element).
2347         */
2348
2349         hasChild: function(el){
2350                 return !!$A(this.getElementsByTagName('*')).contains(el);
2351         },
2352
2353         /*
2354         Property: getProperty
2355                 Gets the an attribute of the Element.
2356
2357         Arguments:
2358                 property - string; the attribute to retrieve
2359
2360         Example:
2361                 >$('myImage').getProperty('src') // returns whatever.gif
2362
2363         Returns:
2364                 the value, or an empty string
2365         */
2366
2367         getProperty: function(property){
2368                 var index = Element.Properties[property];
2369                 if (index) return this[index];
2370                 var flag = Element.PropertiesIFlag[property] || 0;
2371                 if (!window.ie || flag) return this.getAttribute(property, flag);
2372                 var node = this.attributes[property];
2373                 return (node) ? node.nodeValue : null;
2374         },
2375
2376         /*
2377         Property: removeProperty
2378                 Removes an attribute from the Element
2379
2380         Arguments:
2381                 property - string; the attribute to remove
2382         */
2383
2384         removeProperty: function(property){
2385                 var index = Element.Properties[property];
2386                 if (index) this[index] = '';
2387                 else this.removeAttribute(property);
2388                 return this;
2389         },
2390
2391         /*
2392         Property: getProperties
2393                 same as <Element.getStyles>, but for properties
2394         */
2395
2396         getProperties: function(){
2397                 return Element.getMany(this, 'getProperty', arguments);
2398         },
2399
2400         /*
2401         Property: setProperty
2402                 Sets an attribute for the Element.
2403
2404         Arguments:
2405                 property - string; the property to assign the value passed in
2406                 value - the value to assign to the property passed in
2407
2408         Example:
2409                 >$('myImage').setProperty('src', 'whatever.gif'); //myImage now points to whatever.gif for its source
2410         */
2411
2412         setProperty: function(property, value){
2413                 var index = Element.Properties[property];
2414                 if (index) this[index] = value;
2415                 else this.setAttribute(property, value);
2416                 return this;
2417         },
2418
2419         /*
2420         Property: setProperties
2421                 Sets numerous attributes for the Element.
2422
2423         Arguments:
2424                 source - an object with key/value pairs.
2425
2426         Example:
2427                 (start code)
2428                 $('myElement').setProperties({
2429                         src: 'whatever.gif',
2430                         alt: 'whatever dude'
2431                 });
2432                 <img src="whatever.gif" alt="whatever dude">
2433                 (end)
2434         */
2435
2436         setProperties: function(source){
2437                 return Element.setMany(this, 'setProperty', source);
2438         },
2439
2440         /*
2441         Property: setHTML
2442                 Sets the innerHTML of the Element.
2443
2444         Arguments:
2445                 html - string; the new innerHTML for the element.
2446
2447         Example:
2448                 >$('myElement').setHTML(newHTML) //the innerHTML of myElement is now = newHTML
2449         */
2450
2451         setHTML: function(){
2452                 this.innerHTML = $A(arguments).join('');
2453                 return this;
2454         },
2455
2456         /*
2457         Property: setText
2458                 Sets the inner text of the Element.
2459
2460         Arguments:
2461                 text - string; the new text content for the element.
2462
2463         Example:
2464                 >$('myElement').setText('some text') //the text of myElement is now = 'some text'
2465         */
2466
2467         setText: function(text){
2468                 var tag = this.getTag();
2469                 if (['style', 'script'].contains(tag)){
2470                         if (window.ie){
2471                                 if (tag == 'style') this.styleSheet.cssText = text;
2472                                 else if (tag ==  'script') this.setProperty('text', text);
2473                                 return this;
2474                         } else {
2475                                 this.removeChild(this.firstChild);
2476                                 return this.appendText(text);
2477                         }
2478                 }
2479                 this[$defined(this.innerText) ? 'innerText' : 'textContent'] = text;
2480                 return this;
2481         },
2482
2483         /*
2484         Property: getText
2485                 Gets the inner text of the Element.
2486         */
2487
2488         getText: function(){
2489                 var tag = this.getTag();
2490                 if (['style', 'script'].contains(tag)){
2491                         if (window.ie){
2492                                 if (tag == 'style') return this.styleSheet.cssText;
2493                                 else if (tag ==  'script') return this.getProperty('text');
2494                         } else {
2495                                 return this.innerHTML;
2496                         }
2497                 }
2498                 return ($pick(this.innerText, this.textContent));
2499         },
2500
2501         /*
2502         Property: getTag
2503                 Returns the tagName of the element in lower case.
2504
2505         Example:
2506                 >$('myImage').getTag() // returns 'img'
2507
2508         Returns:
2509                 The tag name in lower case
2510         */
2511
2512         getTag: function(){
2513                 return this.tagName.toLowerCase();
2514         },
2515
2516         /*
2517         Property: empty
2518                 Empties an element of all its children.
2519
2520         Example:
2521                 >$('myDiv').empty() // empties the Div and returns it
2522
2523         Returns:
2524                 The element.
2525         */
2526
2527         empty: function(){
2528                 Garbage.trash(this.getElementsByTagName('*'));
2529                 return this.setHTML('');
2530         }
2531
2532 });
2533
2534 Element.fixStyle = function(property, result, element){
2535         if ($chk(parseInt(result))) return result;
2536         if (['height', 'width'].contains(property)){
2537                 var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'];
2538                 var size = 0;
2539                 values.each(function(value){
2540                         size += element.getStyle('border-' + value + '-width').toInt() + element.getStyle('padding-' + value).toInt();
2541                 });
2542                 return element['offset' + property.capitalize()] - size + 'px';
2543         } else if (property.test(/border(.+)Width|margin|padding/)){
2544                 return '0px';
2545         }
2546         return result;
2547 };
2548
2549 Element.Styles = {'border': [], 'padding': [], 'margin': []};
2550 ['Top', 'Right', 'Bottom', 'Left'].each(function(direction){
2551         for (var style in Element.Styles) Element.Styles[style].push(style + direction);
2552 });
2553
2554 Element.borderShort = ['borderWidth', 'borderStyle', 'borderColor'];
2555
2556 Element.getMany = function(el, method, keys){
2557         var result = {};
2558         $each(keys, function(key){
2559                 result[key] = el[method](key);
2560         });
2561         return result;
2562 };
2563
2564 Element.setMany = function(el, method, pairs){
2565         for (var key in pairs) el[method](key, pairs[key]);
2566         return el;
2567 };
2568
2569 Element.Properties = new Abstract({
2570         'class': 'className', 'for': 'htmlFor', 'colspan': 'colSpan', 'rowspan': 'rowSpan',
2571         'accesskey': 'accessKey', 'tabindex': 'tabIndex', 'maxlength': 'maxLength',
2572         'readonly': 'readOnly', 'frameborder': 'frameBorder', 'value': 'value',
2573         'disabled': 'disabled', 'checked': 'checked', 'multiple': 'multiple', 'selected': 'selected'
2574 });
2575 Element.PropertiesIFlag = {
2576         'href': 2, 'src': 2
2577 };
2578
2579 Element.Methods = {
2580         Listeners: {
2581                 addListener: function(type, fn){
2582                         if (this.addEventListener) this.addEventListener(type, fn, false);
2583                         else this.attachEvent('on' + type, fn);
2584                         return this;
2585                 },
2586
2587                 removeListener: function(type, fn){
2588                         if (this.removeEventListener) this.removeEventListener(type, fn, false);
2589                         else this.detachEvent('on' + type, fn);
2590                         return this;
2591                 }
2592         }
2593 };
2594
2595 window.extend(Element.Methods.Listeners);
2596 document.extend(Element.Methods.Listeners);
2597 Element.extend(Element.Methods.Listeners);
2598
2599 var Garbage = {
2600
2601         elements: [],
2602
2603         collect: function(el){
2604                 if (!el.$tmp){
2605                         Garbage.elements.push(el);
2606                         el.$tmp = {'opacity': 1};
2607                 }
2608                 return el;
2609         },
2610
2611         trash: function(elements){
2612                 for (var i = 0, j = elements.length, el; i < j; i++){
2613                         if (!(el = elements[i]) || !el.$tmp) continue;
2614                         if (el.$events) el.fireEvent('trash').removeEvents();
2615                         for (var p in el.$tmp) el.$tmp[p] = null;
2616                         for (var d in Element.prototype) el[d] = null;
2617                         Garbage.elements[Garbage.elements.indexOf(el)] = null;
2618                         el.htmlElement = el.$tmp = el = null;
2619                 }
2620                 Garbage.elements.remove(null);
2621         },
2622
2623         empty: function(){
2624                 Garbage.collect(window);
2625                 Garbage.collect(document);
2626                 Garbage.trash(Garbage.elements);
2627         }
2628
2629 };
2630
2631 window.addListener('beforeunload', function(){
2632         window.addListener('unload', Garbage.empty);
2633         if (window.ie) window.addListener('unload', CollectGarbage);
2634 });
2635
2636 /*
2637 Script: Element.Event.js
2638         Contains the Event Class, Element methods to deal with Element events, custom Events, and the Function prototype bindWithEvent.
2639
2640 License:
2641         MIT-style license.
2642 */
2643
2644 /*
2645 Class: Event
2646         Cross browser methods to manage events.
2647
2648 Arguments:
2649         event - the event
2650
2651 Properties:
2652         shift - true if the user pressed the shift
2653         control - true if the user pressed the control
2654         alt - true if the user pressed the alt
2655         meta - true if the user pressed the meta key
2656         wheel - the amount of third button scrolling
2657         code - the keycode of the key pressed
2658         page.x - the x position of the mouse, relative to the full window
2659         page.y - the y position of the mouse, relative to the full window
2660         client.x - the x position of the mouse, relative to the viewport
2661         client.y - the y position of the mouse, relative to the viewport
2662         key - the key pressed as a lowercase string. key also returns 'enter', 'up', 'down', 'left', 'right', 'space', 'backspace', 'delete', 'esc'. Handy for these special keys.
2663         target - the event target
2664         relatedTarget - the event related target
2665
2666 Example:
2667         (start code)
2668         $('myLink').onkeydown = function(event){
2669                 var event = new Event(event);
2670                 //event is now the Event class.
2671                 alert(event.key); //returns the lowercase letter pressed
2672                 alert(event.shift); //returns true if the key pressed is shift
2673                 if (event.key == 's' && event.control) alert('document saved');
2674         };
2675         (end)
2676 */
2677
2678 var Event = new Class({
2679
2680         initialize: function(event){
2681                 if (event && event.$extended) return event;
2682                 this.$extended = true;
2683                 event = event || window.event;
2684                 this.event = event;
2685                 this.type = event.type;
2686                 this.target = event.target || event.srcElement;
2687                 if (this.target.nodeType == 3) this.target = this.target.parentNode;
2688                 this.shift = event.shiftKey;
2689                 this.control = event.ctrlKey;
2690                 this.alt = event.altKey;
2691                 this.meta = event.metaKey;
2692                 if (['DOMMouseScroll', 'mousewheel'].contains(this.type)){
2693                         this.wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
2694                 } else if (this.type.contains('key')){
2695                         this.code = event.which || event.keyCode;
2696                         for (var name in Event.keys){
2697                                 if (Event.keys[name] == this.code){
2698                                         this.key = name;
2699                                         break;
2700                                 }
2701                         }
2702                         if (this.type == 'keydown'){
2703                                 var fKey = this.code - 111;
2704                                 if (fKey > 0 && fKey < 13) this.key = 'f' + fKey;
2705                         }
2706                         this.key = this.key || String.fromCharCode(this.code).toLowerCase();
2707                 } else if (this.type.test(/(click|mouse|menu)/)){
2708                         this.page = {
2709                                 'x': event.pageX || event.clientX + document.documentElement.scrollLeft,
2710                                 'y': event.pageY || event.clientY + document.documentElement.scrollTop
2711                         };
2712                         this.client = {
2713                                 'x': event.pageX ? event.pageX - window.pageXOffset : event.clientX,
2714                                 'y': event.pageY ? event.pageY - window.pageYOffset : event.clientY
2715                         };
2716                         this.rightClick = (event.which == 3) || (event.button == 2);
2717                         switch(this.type){
2718                                 case 'mouseover': this.relatedTarget = event.relatedTarget || event.fromElement; break;
2719                                 case 'mouseout': this.relatedTarget = event.relatedTarget || event.toElement;
2720                         }
2721                         this.fixRelatedTarget();
2722                 }
2723                 return this;
2724         },
2725
2726         /*
2727         Property: stop
2728                 cross browser method to stop an event
2729         */
2730
2731         stop: function(){
2732                 return this.stopPropagation().preventDefault();
2733         },
2734
2735         /*
2736         Property: stopPropagation
2737                 cross browser method to stop the propagation of an event
2738         */
2739
2740         stopPropagation: function(){
2741                 if (this.event.stopPropagation) this.event.stopPropagation();
2742                 else this.event.cancelBubble = true;
2743                 return this;
2744         },
2745
2746         /*
2747         Property: preventDefault
2748                 cross browser method to prevent the default action of the event
2749         */
2750
2751         preventDefault: function(){
2752                 if (this.event.preventDefault) this.event.preventDefault();
2753                 else this.event.returnValue = false;
2754                 return this;
2755         }
2756
2757 });
2758
2759 Event.fix = {
2760
2761         relatedTarget: function(){
2762                 if (this.relatedTarget && this.relatedTarget.nodeType == 3) this.relatedTarget = this.relatedTarget.parentNode;
2763         },
2764
2765         relatedTargetGecko: function(){
2766                 try {Event.fix.relatedTarget.call(this);} catch(e){this.relatedTarget = this.target;}
2767         }
2768
2769 };
2770
2771 Event.prototype.fixRelatedTarget = (window.gecko) ? Event.fix.relatedTargetGecko : Event.fix.relatedTarget;
2772
2773 /*
2774 Property: keys
2775         you can add additional Event keys codes this way:
2776
2777 Example:
2778         (start code)
2779         Event.keys.whatever = 80;
2780         $(myelement).addEvent(keydown, function(event){
2781                 event = new Event(event);
2782                 if (event.key == 'whatever') console.log(whatever key clicked).
2783         });
2784         (end)
2785 */
2786
2787 Event.keys = new Abstract({
2788         'enter': 13,
2789         'up': 38,
2790         'down': 40,
2791         'left': 37,
2792         'right': 39,
2793         'esc': 27,
2794         'space': 32,
2795         'backspace': 8,
2796         'tab': 9,
2797         'delete': 46
2798 });
2799
2800 /*
2801 Class: Element
2802         Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
2803 */
2804
2805 Element.Methods.Events = {
2806
2807         /*
2808         Property: addEvent
2809                 Attaches an event listener to a DOM element.
2810
2811         Arguments:
2812                 type - the event to monitor ('click', 'load', etc) without the prefix 'on'.
2813                 fn - the function to execute
2814
2815         Example:
2816                 >$('myElement').addEvent('click', function(){alert('clicked!')});
2817         */
2818
2819         addEvent: function(type, fn){
2820                 this.$events = this.$events || {};
2821                 this.$events[type] = this.$events[type] || {'keys': [], 'values': []};
2822                 if (this.$events[type].keys.contains(fn)) return this;
2823                 this.$events[type].keys.push(fn);
2824                 var realType = type;
2825                 var custom = Element.Events[type];
2826                 if (custom){
2827                         if (custom.add) custom.add.call(this, fn);
2828                         if (custom.map) fn = custom.map;
2829                         if (custom.type) realType = custom.type;
2830                 }
2831                 if (!this.addEventListener) fn = fn.create({'bind': this, 'event': true});
2832                 this.$events[type].values.push(fn);
2833                 return (Element.NativeEvents.contains(realType)) ? this.addListener(realType, fn) : this;
2834         },
2835
2836         /*
2837         Property: removeEvent
2838                 Works as Element.addEvent, but instead removes the previously added event listener.
2839         */
2840
2841         removeEvent: function(type, fn){
2842                 if (!this.$events || !this.$events[type]) return this;
2843                 var pos = this.$events[type].keys.indexOf(fn);
2844                 if (pos == -1) return this;
2845                 var key = this.$events[type].keys.splice(pos,1)[0];
2846                 var value = this.$events[type].values.splice(pos,1)[0];
2847                 var custom = Element.Events[type];
2848                 if (custom){
2849                         if (custom.remove) custom.remove.call(this, fn);
2850                         if (custom.type) type = custom.type;
2851                 }
2852                 return (Element.NativeEvents.contains(type)) ? this.removeListener(type, value) : this;
2853         },
2854
2855         /*
2856         Property: addEvents
2857                 As <addEvent>, but accepts an object and add multiple events at once.
2858         */
2859
2860         addEvents: function(source){
2861                 return Element.setMany(this, 'addEvent', source);
2862         },
2863
2864         /*
2865         Property: removeEvents
2866                 removes all events of a certain type from an element. if no argument is passed in, removes all events.
2867
2868         Arguments:
2869                 type - string; the event name (e.g. 'click')
2870         */
2871
2872         removeEvents: function(type){
2873                 if (!this.$events) return this;
2874                 if (!type){
2875                         for (var evType in this.$events) this.removeEvents(evType);
2876                         this.$events = null;
2877                 } else if (this.$events[type]){
2878                         this.$events[type].keys.each(function(fn){
2879                                 this.removeEvent(type, fn);
2880                         }, this);
2881                         this.$events[type] = null;
2882                 }
2883                 return this;
2884         },
2885
2886         /*
2887         Property: fireEvent
2888                 executes all events of the specified type present in the element.
2889
2890         Arguments:
2891                 type - string; the event name (e.g. 'click')
2892                 args - array or single object; arguments to pass to the function; if more than one argument, must be an array
2893                 delay - (integer) delay (in ms) to wait to execute the event
2894         */
2895
2896         fireEvent: function(type, args, delay){
2897                 if (this.$events && this.$events[type]){
2898                         this.$events[type].keys.each(function(fn){
2899                                 fn.create({'bind': this, 'delay': delay, 'arguments': args})();
2900                         }, this);
2901                 }
2902                 return this;
2903         },
2904
2905         /*
2906         Property: cloneEvents
2907                 Clones all events from an element to this element.
2908
2909         Arguments:
2910                 from - element, copy all events from this element
2911                 type - optional, copies only events of this type
2912         */
2913
2914         cloneEvents: function(from, type){
2915                 if (!from.$events) return this;
2916                 if (!type){
2917                         for (var evType in from.$events) this.cloneEvents(from, evType);
2918                 } else if (from.$events[type]){
2919                         from.$events[type].keys.each(function(fn){
2920                                 this.addEvent(type, fn);
2921                         }, this);
2922                 }
2923                 return this;
2924         }
2925
2926 };
2927
2928 window.extend(Element.Methods.Events);
2929 document.extend(Element.Methods.Events);
2930 Element.extend(Element.Methods.Events);
2931
2932 /* Section: Custom Events */
2933
2934 Element.Events = new Abstract({
2935
2936         /*
2937         Event: mouseenter
2938                 In addition to the standard javascript events (load, mouseover, mouseout, click, etc.) <Event.js> contains two custom events
2939                 this event fires when the mouse enters the area of the dom element; will not be fired again if the mouse crosses over children of the element (unlike mouseover)
2940
2941
2942         Example:
2943                 >$(myElement).addEvent('mouseenter', myFunction);
2944         */
2945
2946         'mouseenter': {
2947                 type: 'mouseover',
2948                 map: function(event){
2949                         event = new Event(event);
2950                         if (event.relatedTarget != this && !this.hasChild(event.relatedTarget)) this.fireEvent('mouseenter', event);
2951                 }
2952         },
2953
2954         /*
2955         Event: mouseleave
2956                 this event fires when the mouse exits the area of the dom element; will not be fired again if the mouse crosses over children of the element (unlike mouseout)
2957
2958
2959         Example:
2960                 >$(myElement).addEvent('mouseleave', myFunction);
2961         */
2962
2963         'mouseleave': {
2964                 type: 'mouseout',
2965                 map: function(event){
2966                         event = new Event(event);
2967                         if (event.relatedTarget != this && !this.hasChild(event.relatedTarget)) this.fireEvent('mouseleave', event);
2968                 }
2969         },
2970
2971         'mousewheel': {
2972                 type: (window.gecko) ? 'DOMMouseScroll' : 'mousewheel'
2973         }
2974
2975 });
2976
2977 Element.NativeEvents = [
2978         'click', 'dblclick', 'mouseup', 'mousedown', //mouse buttons
2979         'mousewheel', 'DOMMouseScroll', //mouse wheel
2980         'mouseover', 'mouseout', 'mousemove', //mouse movement
2981         'keydown', 'keypress', 'keyup', //keys
2982         'load', 'unload', 'beforeunload', 'resize', 'move', //window
2983         'focus', 'blur', 'change', 'submit', 'reset', 'select', //forms elements
2984         'error', 'abort', 'contextmenu', 'scroll' //misc
2985 ];
2986
2987 /*
2988 Class: Function
2989         A collection of The Function Object prototype methods.
2990 */
2991
2992 Function.extend({
2993
2994         /*
2995         Property: bindWithEvent
2996                 automatically passes MooTools Event Class.
2997
2998         Arguments:
2999                 bind - optional, the object that the "this" of the function will refer to.
3000                 args - optional, an argument to pass to the function; if more than one argument, it must be an array of arguments.
3001
3002         Returns:
3003                 a function with the parameter bind as its "this" and as a pre-passed argument event or window.event, depending on the browser.
3004
3005         Example:
3006                 >function myFunction(event){
3007                 >       alert(event.client.x) //returns the coordinates of the mouse..
3008                 >};
3009                 >myElement.addEvent('click', myFunction.bindWithEvent(myElement));
3010         */
3011
3012         bindWithEvent: function(bind, args){
3013                 return this.create({'bind': bind, 'arguments': args, 'event': Event});
3014         }
3015
3016 });
3017
3018
3019 /*
3020 Script: Element.Filters.js
3021         add Filters capability to <Elements>.
3022
3023 License:
3024         MIT-style license.
3025 */
3026
3027 /*
3028 Class: Elements
3029         A collection of methods to be used with <$$> elements collections.
3030 */
3031
3032 Elements.extend({
3033         
3034         /*
3035         Property: filterByTag
3036                 Filters the collection by a specified tag name.
3037                 Returns a new Elements collection, while the original remains untouched.
3038         */
3039         
3040         filterByTag: function(tag){
3041                 return new Elements(this.filter(function(el){
3042                         return (Element.getTag(el) == tag);
3043                 }));
3044         },
3045         
3046         /*
3047         Property: filterByClass
3048                 Filters the collection by a specified class name.
3049                 Returns a new Elements collection, while the original remains untouched.
3050         */
3051         
3052         filterByClass: function(className, nocash){
3053                 var elements = this.filter(function(el){
3054                         return (el.className && el.className.contains(className, ' '));
3055                 });
3056                 return (nocash) ? elements : new Elements(elements);
3057         },
3058         
3059         /*
3060         Property: filterById
3061                 Filters the collection by a specified ID.
3062                 Returns a new Elements collection, while the original remains untouched.
3063         */
3064         
3065         filterById: function(id, nocash){
3066                 var elements = this.filter(function(el){
3067                         return (el.id == id);
3068                 });
3069                 return (nocash) ? elements : new Elements(elements);
3070         },
3071         
3072         /*
3073         Property: filterByAttribute
3074                 Filters the collection by a specified attribute.
3075                 Returns a new Elements collection, while the original remains untouched.
3076                 
3077         Arguments:
3078                 name - the attribute name.
3079                 operator - optional, the attribute operator.
3080                 value - optional, the attribute value, only valid if the operator is specified.
3081         */
3082         
3083         filterByAttribute: function(name, operator, value, nocash){
3084                 var elements = this.filter(function(el){
3085                         var current = Element.getProperty(el, name);
3086                         if (!current) return false;
3087                         if (!operator) return true;
3088                         switch(operator){
3089                                 case '=': return (current == value);
3090                                 case '*=': return (current.contains(value));
3091                                 case '^=': return (current.substr(0, value.length) == value);
3092                                 case '$=': return (current.substr(current.length - value.length) == value);
3093                                 case '!=': return (current != value);
3094                                 case '~=': return current.contains(value, ' ');
3095                         }
3096                         return false;
3097                 });
3098                 return (nocash) ? elements : new Elements(elements);
3099         }
3100
3101 });
3102
3103 /*
3104 Script: Element.Selectors.js
3105         Css Query related functions and <Element> extensions
3106
3107 License:
3108         MIT-style license.
3109 */
3110
3111 /* Section: Utility Functions */
3112
3113 /*
3114 Function: $E
3115         Selects a single (i.e. the first found) Element based on the selector passed in and an optional filter element.
3116         Returns as <Element>.
3117
3118 Arguments:
3119         selector - string; the css selector to match
3120         filter - optional; a DOM element to limit the scope of the selector match; defaults to document.
3121
3122 Example:
3123         >$E('a', 'myElement') //find the first anchor tag inside the DOM element with id 'myElement'
3124
3125 Returns:
3126         a DOM element - the first element that matches the selector
3127 */
3128
3129 function $E(selector, filter){
3130         return ($(filter) || document).getElement(selector);
3131 };
3132
3133 /*
3134 Function: $ES
3135         Returns a collection of Elements that match the selector passed in limited to the scope of the optional filter.
3136         See Also: <Element.getElements> for an alternate syntax.
3137         Returns as <Elements>.
3138
3139 Returns:
3140         an array of dom elements that match the selector within the filter
3141
3142 Arguments:
3143         selector - string; css selector to match
3144         filter - optional; a DOM element to limit the scope of the selector match; defaults to document.
3145
3146 Examples:
3147         >$ES("a") //gets all the anchor tags; synonymous with $$("a")
3148         >$ES('a','myElement') //get all the anchor tags within $('myElement')
3149 */
3150
3151 function $ES(selector, filter){
3152         return ($(filter) || document).getElementsBySelector(selector);
3153 };
3154
3155 $$.shared = {
3156
3157         'regexp': /^(\w*|\*)(?:#([\w-]+)|\.([\w-]+))?(?:\[(\w+)(?:([!*^$]?=)["']?([^"'\]]*)["']?)?])?$/,
3158         
3159         'xpath': {
3160
3161                 getParam: function(items, context, param, i){
3162                         var temp = [context.namespaceURI ? 'xhtml:' : '', param[1]];
3163                         if (param[2]) temp.push('[@id="', param[2], '"]');
3164                         if (param[3]) temp.push('[contains(concat(" ", @class, " "), " ', param[3], ' ")]');
3165                         if (param[4]){
3166                                 if (param[5] && param[6]){
3167                                         switch(param[5]){
3168                                                 case '*=': temp.push('[contains(@', param[4], ', "', param[6], '")]'); break;
3169                                                 case '^=': temp.push('[starts-with(@', param[4], ', "', param[6], '")]'); break;
3170                                                 case '$=': temp.push('[substring(@', param[4], ', string-length(@', param[4], ') - ', param[6].length, ' + 1) = "', param[6], '"]'); break;
3171                                                 case '=': temp.push('[@', param[4], '="', param[6], '"]'); break;
3172                                                 case '!=': temp.push('[@', param[4], '!="', param[6], '"]');
3173                                         }
3174                                 } else {
3175                                         temp.push('[@', param[4], ']');
3176                                 }
3177                         }
3178                         items.push(temp.join(''));
3179                         return items;
3180                 },
3181                 
3182                 getItems: function(items, context, nocash){
3183                         var elements = [];
3184                         var xpath = document.evaluate('.//' + items.join('//'), context, $$.shared.resolver, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
3185                         for (var i = 0, j = xpath.snapshotLength; i < j; i++) elements.push(xpath.snapshotItem(i));
3186                         return (nocash) ? elements : new Elements(elements.map($));
3187                 }
3188
3189         },
3190         
3191         'normal': {
3192                 
3193                 getParam: function(items, context, param, i){
3194                         if (i == 0){
3195                                 if (param[2]){
3196                                         var el = context.getElementById(param[2]);
3197                                         if (!el || ((param[1] != '*') && (Element.getTag(el) != param[1]))) return false;
3198                                         items = [el];
3199                                 } else {
3200                                         items = $A(context.getElementsByTagName(param[1]));
3201                                 }
3202                         } else {
3203                                 items = $$.shared.getElementsByTagName(items, param[1]);
3204                                 if (param[2]) items = Elements.filterById(items, param[2], true);
3205                         }
3206                         if (param[3]) items = Elements.filterByClass(items, param[3], true);
3207                         if (param[4]) items = Elements.filterByAttribute(items, param[4], param[5], param[6], true);
3208                         return items;
3209                 },
3210
3211                 getItems: function(items, context, nocash){
3212                         return (nocash) ? items : $$.unique(items);
3213                 }
3214
3215         },
3216
3217         resolver: function(prefix){
3218                 return (prefix == 'xhtml') ? 'http://www.w3.org/1999/xhtml' : false;
3219         },
3220
3221         getElementsByTagName: function(context, tagName){
3222                 var found = [];
3223                 for (var i = 0, j = context.length; i < j; i++) found.extend(context[i].getElementsByTagName(tagName));
3224                 return found;
3225         }
3226
3227 };
3228
3229 $$.shared.method = (window.xpath) ? 'xpath' : 'normal';
3230
3231 /*
3232 Class: Element
3233         Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
3234 */
3235
3236 Element.Methods.Dom = {
3237
3238         /*
3239         Property: getElements
3240                 Gets all the elements within an element that match the given (single) selector.
3241                 Returns as <Elements>.
3242
3243         Arguments:
3244                 selector - string; the css selector to match
3245
3246         Examples:
3247                 >$('myElement').getElements('a'); // get all anchors within myElement
3248                 >$('myElement').getElements('input[name=dialog]') //get all input tags with name 'dialog'
3249                 >$('myElement').getElements('input[name$=log]') //get all input tags with names ending with 'log'
3250
3251         Notes:
3252                 Supports these operators in attribute selectors:
3253
3254                 - = : is equal to
3255                 - ^= : starts-with
3256                 - $= : ends-with
3257                 - != : is not equal to
3258
3259                 Xpath is used automatically for compliant browsers.
3260         */
3261
3262         getElements: function(selector, nocash){
3263                 var items = [];
3264                 selector = selector.trim().split(' ');
3265                 for (var i = 0, j = selector.length; i < j; i++){
3266                         var sel = selector[i];
3267                         var param = sel.match($$.shared.regexp);
3268                         if (!param) break;
3269                         param[1] = param[1] || '*';
3270                         var temp = $$.shared[$$.shared.method].getParam(items, this, param, i);
3271                         if (!temp) break;
3272                         items = temp;
3273                 }
3274                 return $$.shared[$$.shared.method].getItems(items, this, nocash);
3275         },
3276
3277         /*
3278         Property: getElement
3279                 Same as <Element.getElements>, but returns only the first. Alternate syntax for <$E>, where filter is the Element.
3280                 Returns as <Element>.
3281
3282         Arguments:
3283                 selector - string; css selector
3284         */
3285
3286         getElement: function(selector){
3287                 return $(this.getElements(selector, true)[0] || false);
3288         },
3289
3290         /*
3291         Property: getElementsBySelector
3292                 Same as <Element.getElements>, but allows for comma separated selectors, as in css. Alternate syntax for <$$>, where filter is the Element.
3293                 Returns as <Elements>.
3294
3295         Arguments:
3296                 selector - string; css selector
3297         */
3298
3299         getElementsBySelector: function(selector, nocash){
3300                 var elements = [];
3301                 selector = selector.split(',');
3302                 for (var i = 0, j = selector.length; i < j; i++) elements = elements.concat(this.getElements(selector[i], true));
3303                 return (nocash) ? elements : $$.unique(elements);
3304         }
3305
3306 };
3307
3308 Element.extend({
3309
3310         /*
3311         Property: getElementById
3312                 Targets an element with the specified id found inside the Element. Does not overwrite document.getElementById.
3313
3314         Arguments:
3315                 id - string; the id of the element to find.
3316         */
3317
3318         getElementById: function(id){
3319                 var el = document.getElementById(id);
3320                 if (!el) return false;
3321                 for (var parent = el.parentNode; parent != this; parent = parent.parentNode){
3322                         if (!parent) return false;
3323                 }
3324                 return el;
3325         }/*compatibility*/,
3326         
3327         getElementsByClassName: function(className){ 
3328                 return this.getElements('.' + className); 
3329         }
3330         
3331         /*end compatibility*/
3332
3333 });
3334
3335 document.extend(Element.Methods.Dom);
3336 Element.extend(Element.Methods.Dom);
3337
3338 /*
3339 Script: Element.Form.js
3340         Contains Element prototypes to deal with Forms and their elements.
3341
3342 License:
3343         MIT-style license.
3344 */
3345
3346 /*
3347 Class: Element
3348         Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
3349 */
3350
3351 Element.extend({
3352
3353         /*
3354         Property: getValue
3355                 Returns the value of the Element, if its tag is textarea, select or input. getValue called on a multiple select will return an array.
3356         */
3357
3358         getValue: function(){
3359                 switch(this.getTag()){
3360                         case 'select':
3361                                 var values = [];
3362                                 $each(this.options, function(option){
3363                                         if (option.selected) values.push($pick(option.value, option.text));
3364                                 });
3365                                 return (this.multiple) ? values : values[0];
3366                         case 'input': if (!(this.checked && ['checkbox', 'radio'].contains(this.type)) && !['hidden', 'text', 'password'].contains(this.type)) break;
3367                         case 'textarea': return this.value;
3368                 }
3369                 return false;
3370         },
3371
3372         getFormElements: function(){
3373                 return $$(this.getElementsByTagName('input'), this.getElementsByTagName('select'), this.getElementsByTagName('textarea'));
3374         },
3375
3376         /*
3377         Property: toQueryString
3378                 Reads the children inputs of the Element and generates a query string, based on their values. Used internally in <Ajax>
3379
3380         Example:
3381                 (start code)
3382                 <form id="myForm" action="submit.php">
3383                 <input name="email" value="bob@bob.com">
3384                 <input name="zipCode" value="90210">
3385                 </form>
3386
3387                 <script>
3388                  $('myForm').toQueryString()
3389                 </script>
3390                 (end)
3391
3392                 Returns:
3393                         email=bob@bob.com&zipCode=90210
3394         */
3395
3396         toQueryString: function(){
3397                 var queryString = [];
3398                 this.getFormElements().each(function(el){
3399                         var name = el.name;
3400                         var value = el.getValue();
3401                         if (value === false || !name || el.disabled) return;
3402                         var qs = function(val){
3403                                 queryString.push(name + '=' + encodeURIComponent(val));
3404                         };
3405                         if ($type(value) == 'array') value.each(qs);
3406                         else qs(value);
3407                 });
3408                 return queryString.join('&');
3409         }
3410
3411 });
3412
3413 /*
3414 Script: Element.Dimensions.js
3415         Contains Element prototypes to deal with Element size and position in space.
3416
3417 Note:
3418         The functions in this script require n XHTML doctype.
3419
3420 License:
3421         MIT-style license.
3422 */
3423
3424 /*
3425 Class: Element
3426         Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
3427 */
3428
3429 Element.extend({
3430
3431         /*
3432         Property: scrollTo
3433                 Scrolls the element to the specified coordinated (if the element has an overflow)
3434
3435         Arguments:
3436                 x - the x coordinate
3437                 y - the y coordinate
3438
3439         Example:
3440                 >$('myElement').scrollTo(0, 100)
3441         */
3442
3443         scrollTo: function(x, y){
3444                 this.scrollLeft = x;
3445                 this.scrollTop = y;
3446         },
3447
3448         /*
3449         Property: getSize
3450                 Return an Object representing the size/scroll values of the element.
3451
3452         Example:
3453                 (start code)
3454                 $('myElement').getSize();
3455                 (end)
3456
3457         Returns:
3458                 (start code)
3459                 {
3460                         'scroll': {'x': 100, 'y': 100},
3461                         'size': {'x': 200, 'y': 400},
3462                         'scrollSize': {'x': 300, 'y': 500}
3463                 }
3464                 (end)
3465         */
3466
3467         getSize: function(){
3468                 return {
3469                         'scroll': {'x': this.scrollLeft, 'y': this.scrollTop},
3470                         'size': {'x': this.offsetWidth, 'y': this.offsetHeight},
3471                         'scrollSize': {'x': this.scrollWidth, 'y': this.scrollHeight}
3472                 };
3473         },
3474
3475         /*
3476         Property: getPosition
3477                 Returns the real offsets of the element.
3478
3479         Arguments:
3480                 overflown - optional, an array of nested scrolling containers for scroll offset calculation, use this if your element is inside any element containing scrollbars
3481
3482         Example:
3483                 >$('element').getPosition();
3484
3485         Returns:
3486                 >{x: 100, y:500};
3487         */
3488
3489         getPosition: function(overflown){
3490                 overflown = overflown || [];
3491                 var el = this, left = 0, top = 0;
3492                 do {
3493                         left += el.offsetLeft || 0;
3494                         top += el.offsetTop || 0;
3495                         el = el.offsetParent;
3496                 } while (el);
3497                 overflown.each(function(element){
3498                         left -= element.scrollLeft || 0;
3499                         top -= element.scrollTop || 0;
3500                 });
3501                 return {'x': left, 'y': top};
3502         },
3503
3504         /*
3505         Property: getTop
3506                 Returns the distance from the top of the window to the Element.
3507
3508         Arguments:
3509                 overflown - optional, an array of nested scrolling containers, see Element::getPosition
3510         */
3511
3512         getTop: function(overflown){
3513                 return this.getPosition(overflown).y;
3514         },
3515
3516         /*
3517         Property: getLeft
3518                 Returns the distance from the left of the window to the Element.
3519
3520         Arguments:
3521                 overflown - optional, an array of nested scrolling containers, see Element::getPosition
3522         */
3523
3524         getLeft: function(overflown){
3525                 return this.getPosition(overflown).x;
3526         },
3527
3528         /*
3529         Property: getCoordinates
3530                 Returns an object with width, height, left, right, top, and bottom, representing the values of the Element
3531
3532         Arguments:
3533                 overflown - optional, an array of nested scrolling containers, see Element::getPosition
3534
3535         Example:
3536                 (start code)
3537                 var myValues = $('myElement').getCoordinates();
3538                 (end)
3539
3540         Returns:
3541                 (start code)
3542                 {
3543                         width: 200,
3544                         height: 300,
3545                         left: 100,
3546                         top: 50,
3547                         right: 300,
3548                         bottom: 350
3549                 }
3550                 (end)
3551         */
3552
3553         getCoordinates: function(overflown){
3554                 var position = this.getPosition(overflown);
3555                 var obj = {
3556                         'width': this.offsetWidth,
3557                         'height': this.offsetHeight,
3558                         'left': position.x,
3559                         'top': position.y
3560                 };
3561                 obj.right = obj.left + obj.width;
3562                 obj.bottom = obj.top + obj.height;
3563                 return obj;
3564         }
3565
3566 });
3567
3568 /*
3569 Script: Window.DomReady.js
3570         Contains the custom event domready, for window.
3571
3572 License:
3573         MIT-style license.
3574 */
3575
3576 /* Section: Custom Events */
3577
3578 /*
3579 Event: domready
3580         executes a function when the dom tree is loaded, without waiting for images. Only works when called from window.
3581
3582 Credits:
3583         (c) Dean Edwards/Matthias Miller/John Resig, remastered for MooTools.
3584
3585 Arguments:
3586         fn - the function to execute when the DOM is ready
3587
3588 Example:
3589         > window.addEvent('domready', function(){
3590         >       alert('the dom is ready');
3591         > });
3592 */
3593
3594 Element.Events.domready = {
3595
3596         add: function(fn){
3597                 if (window.loaded){
3598                         fn.call(this);
3599                         return;
3600                 }
3601                 var domReady = function(){
3602                         if (window.loaded) return;
3603                         window.loaded = true;
3604                         window.timer = $clear(window.timer);
3605                         this.fireEvent('domready');
3606                 }.bind(this);
3607                 if (document.readyState && window.webkit){
3608                         window.timer = function(){
3609                                 if (['loaded','complete'].contains(document.readyState)) domReady();
3610                         }.periodical(50);
3611                 } else if (document.readyState && window.ie){
3612                         if (!$('ie_ready')){
3613                                 var src = (window.location.protocol == 'https:') ? '://0' : 'javascript:void(0)';
3614                                 document.write('<script id="ie_ready" defer src="' + src + '"><\/script>');
3615                                 $('ie_ready').onreadystatechange = function(){
3616                                         if (this.readyState == 'complete') domReady();
3617                                 };
3618                         }
3619                 } else {
3620                         window.addListener("load", domReady);
3621                         document.addListener("DOMContentLoaded", domReady);
3622                 }
3623         }
3624
3625 };
3626
3627 /*compatibility*/
3628
3629 window.onDomReady = function(fn){ 
3630         return this.addEvent('domready', fn); 
3631 };
3632
3633 /*end compatibility*/
3634
3635 /*
3636 Script: Window.Size.js
3637         Window cross-browser dimensions methods.
3638         
3639 Note:
3640         The Functions in this script require an XHTML doctype.
3641
3642 License:
3643         MIT-style license.
3644 */
3645
3646 /*
3647 Class: window
3648         Cross browser methods to get various window dimensions.
3649         Warning: All these methods require that the browser operates in strict mode, not quirks mode.
3650 */
3651
3652 window.extend({
3653
3654         /*
3655         Property: getWidth
3656                 Returns an integer representing the width of the browser window (without the scrollbar).
3657         */
3658
3659         getWidth: function(){
3660                 if (this.webkit419) return this.innerWidth;
3661                 if (this.opera) return document.body.clientWidth;
3662                 return document.documentElement.clientWidth;
3663         },
3664
3665         /*
3666         Property: getHeight
3667                 Returns an integer representing the height of the browser window (without the scrollbar).
3668         */
3669
3670         getHeight: function(){
3671                 if (this.webkit419) return this.innerHeight;
3672                 if (this.opera) return document.body.clientHeight;
3673                 return document.documentElement.clientHeight;
3674         },
3675
3676         /*
3677         Property: getScrollWidth
3678                 Returns an integer representing the scrollWidth of the window.
3679                 This value is equal to or bigger than <getWidth>.
3680
3681         See Also:
3682                 <http://developer.mozilla.org/en/docs/DOM:element.scrollWidth>
3683         */
3684
3685         getScrollWidth: function(){
3686                 if (this.ie) return Math.max(document.documentElement.offsetWidth, document.documentElement.scrollWidth);
3687                 if (this.webkit) return document.body.scrollWidth;
3688                 return document.documentElement.scrollWidth;
3689         },
3690
3691         /*
3692         Property: getScrollHeight
3693                 Returns an integer representing the scrollHeight of the window.
3694                 This value is equal to or bigger than <getHeight>.
3695
3696         See Also:
3697                 <http://developer.mozilla.org/en/docs/DOM:element.scrollHeight>
3698         */
3699
3700         getScrollHeight: function(){
3701                 if (this.ie) return Math.max(document.documentElement.offsetHeight, document.documentElement.scrollHeight);
3702                 if (this.webkit) return document.body.scrollHeight;
3703                 return document.documentElement.scrollHeight;
3704         },
3705
3706         /*
3707         Property: getScrollLeft
3708                 Returns an integer representing the scrollLeft of the window (the number of pixels the window has scrolled from the left).
3709
3710         See Also:
3711                 <http://developer.mozilla.org/en/docs/DOM:element.scrollLeft>
3712         */
3713
3714         getScrollLeft: function(){
3715                 return this.pageXOffset || document.documentElement.scrollLeft;
3716         },
3717
3718         /*
3719         Property: getScrollTop
3720                 Returns an integer representing the scrollTop of the window (the number of pixels the window has scrolled from the top).
3721
3722         See Also:
3723                 <http://developer.mozilla.org/en/docs/DOM:element.scrollTop>
3724         */
3725
3726         getScrollTop: function(){
3727                 return this.pageYOffset || document.documentElement.scrollTop;
3728         },
3729
3730         /*
3731         Property: getSize
3732                 Same as <Element.getSize>
3733         */
3734
3735         getSize: function(){
3736                 return {
3737                         'size': {'x': this.getWidth(), 'y': this.getHeight()},
3738                         'scrollSize': {'x': this.getScrollWidth(), 'y': this.getScrollHeight()},
3739                         'scroll': {'x': this.getScrollLeft(), 'y': this.getScrollTop()}
3740                 };
3741         },
3742
3743         //ignore
3744         getPosition: function(){return {'x': 0, 'y': 0};}
3745
3746 });
3747
3748 /*
3749 Script: Fx.Base.js
3750         Contains <Fx.Base>, the foundamentals of the MooTools Effects.
3751
3752 License:
3753         MIT-style license.
3754 */
3755
3756 var Fx = {};
3757
3758 /*
3759 Class: Fx.Base
3760         Base class for the Effects.
3761
3762 Options:
3763         transition - the equation to use for the effect see <Fx.Transitions>; default is <Fx.Transitions.Sine.easeInOut>
3764         duration - the duration of the effect in ms; 500 is the default.
3765         unit - the unit is 'px' by default (other values include things like 'em' for fonts or '%').
3766         wait - boolean: to wait or not to wait for a current transition to end before running another of the same instance. defaults to true.
3767         fps - the frames per second for the transition; default is 50
3768         
3769 Events:
3770         onStart - the function to execute as the effect begins; nothing (<Class.empty>) by default.
3771         onComplete - the function to execute after the effect has processed; nothing (<Class.empty>) by default.
3772         onCancel - the function to execute when you manually stop the effect.
3773 */
3774
3775 Fx.Base = new Class({
3776
3777         options: {
3778                 onStart: Class.empty,
3779                 onComplete: Class.empty,
3780                 onCancel: Class.empty,
3781                 transition: function(p){
3782                         return -(Math.cos(Math.PI * p) - 1) / 2;
3783                 },
3784                 duration: 500,
3785                 unit: 'px',
3786                 wait: true,
3787                 fps: 50
3788         },
3789
3790         initialize: function(options){
3791                 this.element = this.element || null;
3792                 this.setOptions(options);
3793                 if (this.options.initialize) this.options.initialize.call(this);
3794         },
3795
3796         step: function(){
3797                 var time = $time();
3798                 if (time < this.time + this.options.duration){
3799                         this.delta = this.options.transition((time - this.time) / this.options.duration);
3800                         this.setNow();
3801                         this.increase();
3802                 } else {
3803                         this.stop(true);
3804                         this.set(this.to);
3805                         this.fireEvent('onComplete', this.element, 10);
3806                         this.callChain();
3807                 }
3808         },
3809
3810         /*
3811         Property: set
3812                 Immediately sets the value with no transition.
3813
3814         Arguments:
3815                 to - the point to jump to
3816
3817         Example:
3818                 >var myFx = new Fx.Style('myElement', 'opacity').set(0); //will make it immediately transparent
3819         */
3820
3821         set: function(to){
3822                 this.now = to;
3823                 this.increase();
3824                 return this;
3825         },
3826
3827         setNow: function(){
3828                 this.now = this.compute(this.from, this.to);
3829         },
3830
3831         compute: function(from, to){
3832                 return (to - from) * this.delta + from;
3833         },
3834
3835         /*
3836         Property: start
3837                 Executes an effect from one position to the other.
3838
3839         Arguments:
3840                 from - integer: staring value
3841                 to - integer: the ending value
3842
3843         Examples:
3844                 >var myFx = new Fx.Style('myElement', 'opacity').start(0,1); //display a transition from transparent to opaque.
3845         */
3846
3847         start: function(from, to){
3848                 if (!this.options.wait) this.stop();
3849                 else if (this.timer) return this;
3850                 this.from = from;
3851                 this.to = to;
3852                 this.change = this.to - this.from;
3853                 this.time = $time();
3854                 this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this);
3855                 this.fireEvent('onStart', this.element);
3856                 return this;
3857         },
3858
3859         /*
3860         Property: stop
3861                 Stops the transition.
3862         */
3863
3864         stop: function(end){
3865                 if (!this.timer) return this;
3866                 this.timer = $clear(this.timer);
3867                 if (!end) this.fireEvent('onCancel', this.element);
3868                 return this;
3869         }/*compatibility*/,
3870         
3871         custom: function(from, to){
3872                 return this.start(from, to);
3873         },
3874
3875         clearTimer: function(end){
3876                 return this.stop(end);
3877         }
3878
3879         /*end compatibility*/
3880
3881 });
3882
3883 Fx.Base.implement(new Chain, new Events, new Options);
3884
3885 /*
3886 Script: Fx.CSS.js
3887         Css parsing class for effects. Required by <Fx.Style>, <Fx.Styles>, <Fx.Elements>. No documentation needed, as its used internally.
3888
3889 License:
3890         MIT-style license.
3891 */
3892
3893 Fx.CSS = {
3894
3895         select: function(property, to){
3896                 if (property.test(/color/i)) return this.Color;
3897                 var type = $type(to);
3898                 if ((type == 'array') || (type == 'string' && to.contains(' '))) return this.Multi;
3899                 return this.Single;
3900         },
3901
3902         parse: function(el, property, fromTo){
3903                 if (!fromTo.push) fromTo = [fromTo];
3904                 var from = fromTo[0], to = fromTo[1];
3905                 if (!$chk(to)){
3906                         to = from;
3907                         from = el.getStyle(property);
3908                 }
3909                 var css = this.select(property, to);
3910                 return {'from': css.parse(from), 'to': css.parse(to), 'css': css};
3911         }
3912
3913 };
3914
3915 Fx.CSS.Single = {
3916
3917         parse: function(value){
3918                 return parseFloat(value);
3919         },
3920
3921         getNow: function(from, to, fx){
3922                 return fx.compute(from, to);
3923         },
3924
3925         getValue: function(value, unit, property){
3926                 if (unit == 'px' && property != 'opacity') value = Math.round(value);
3927                 return value + unit;
3928         }
3929
3930 };
3931
3932 Fx.CSS.Multi = {
3933
3934         parse: function(value){
3935                 return value.push ? value : value.split(' ').map(function(v){
3936                         return parseFloat(v);
3937                 });
3938         },
3939
3940         getNow: function(from, to, fx){
3941                 var now = [];
3942                 for (var i = 0; i < from.length; i++) now[i] = fx.compute(from[i], to[i]);
3943                 return now;
3944         },
3945
3946         getValue: function(value, unit, property){
3947                 if (unit == 'px' && property != 'opacity') value = value.map(Math.round);
3948                 return value.join(unit + ' ') + unit;
3949         }
3950
3951 };
3952
3953 Fx.CSS.Color = {
3954
3955         parse: function(value){
3956                 return value.push ? value : value.hexToRgb(true);
3957         },
3958
3959         getNow: function(from, to, fx){
3960                 var now = [];
3961                 for (var i = 0; i < from.length; i++) now[i] = Math.round(fx.compute(from[i], to[i]));
3962                 return now;
3963         },
3964
3965         getValue: function(value){
3966                 return 'rgb(' + value.join(',') + ')';
3967         }
3968
3969 };
3970
3971 /*
3972 Script: Fx.Style.js
3973         Contains <Fx.Style>
3974
3975 License:
3976         MIT-style license.
3977 */
3978
3979 /*
3980 Class: Fx.Style
3981         The Style effect, used to transition any css property from one value to another. Includes colors.
3982         Colors must be in hex format.
3983         Inherits methods, properties, options and events from <Fx.Base>.
3984
3985 Arguments:
3986         el - the $(element) to apply the style transition to
3987         property - the property to transition
3988         options - the Fx.Base options (see: <Fx.Base>)
3989
3990 Example:
3991         >var marginChange = new Fx.Style('myElement', 'margin-top', {duration:500});
3992         >marginChange.start(10, 100);
3993 */
3994
3995 Fx.Style = Fx.Base.extend({
3996
3997         initialize: function(el, property, options){
3998                 this.element = $(el);
3999                 this.property = property;
4000                 this.parent(options);
4001         },
4002
4003         /*
4004         Property: hide
4005                 Same as <Fx.Base.set> (0); hides the element immediately without transition.
4006         */
4007
4008         hide: function(){
4009                 return this.set(0);
4010         },
4011
4012         setNow: function(){
4013                 this.now = this.css.getNow(this.from, this.to, this);
4014         },
4015
4016         /*
4017         Property: set
4018                 Sets the element's css property (specified at instantiation) to the specified value immediately.
4019
4020         Example:
4021                 (start code)
4022                 var marginChange = new Fx.Style('myElement', 'margin-top', {duration:500});
4023                 marginChange.set(10); //margin-top is set to 10px immediately
4024                 (end)
4025         */
4026
4027         set: function(to){
4028                 this.css = Fx.CSS.select(this.property, to);
4029                 return this.parent(this.css.parse(to));
4030         },
4031
4032         /*
4033         Property: start
4034                 Displays the transition to the value/values passed in
4035
4036         Arguments:
4037                 from - (integer; optional) the starting position for the transition
4038                 to - (integer) the ending position for the transition
4039
4040         Note:
4041                 If you provide only one argument, the transition will use the current css value for its starting value.
4042
4043         Example:
4044                 (start code)
4045                 var marginChange = new Fx.Style('myElement', 'margin-top', {duration:500});
4046                 marginChange.start(10); //tries to read current margin top value and goes from current to 10
4047                 (end)
4048         */
4049
4050         start: function(from, to){
4051                 if (this.timer && this.options.wait) return this;
4052                 var parsed = Fx.CSS.parse(this.element, this.property, [from, to]);
4053                 this.css = parsed.css;
4054                 return this.parent(parsed.from, parsed.to);
4055         },
4056
4057         increase: function(){
4058                 this.element.setStyle(this.property, this.css.getValue(this.now, this.options.unit, this.property));
4059         }
4060
4061 });
4062
4063 /*
4064 Class: Element
4065         Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
4066 */
4067
4068 Element.extend({
4069
4070         /*
4071         Property: effect
4072                 Applies an <Fx.Style> to the Element; This a shortcut for <Fx.Style>.
4073
4074         Arguments:
4075                 property - (string) the css property to alter
4076                 options - (object; optional) key/value set of options (see <Fx.Style>)
4077
4078         Example:
4079                 >var myEffect = $('myElement').effect('height', {duration: 1000, transition: Fx.Transitions.linear});
4080                 >myEffect.start(10, 100);
4081                 >//OR
4082                 >$('myElement').effect('height', {duration: 1000, transition: Fx.Transitions.linear}).start(10,100);
4083         */
4084
4085         effect: function(property, options){
4086                 return new Fx.Style(this, property, options);
4087         }
4088
4089 });
4090
4091 /*
4092 Script: Fx.Styles.js
4093         Contains <Fx.Styles>
4094
4095 License:
4096         MIT-style license.
4097 */
4098
4099 /*
4100 Class: Fx.Styles
4101         Allows you to animate multiple css properties at once;
4102         Colors must be in hex format.
4103         Inherits methods, properties, options and events from <Fx.Base>.
4104
4105 Arguments:
4106         el - the $(element) to apply the styles transition to
4107         options - the fx options (see: <Fx.Base>)
4108
4109 Example:
4110         (start code)
4111         var myEffects = new Fx.Styles('myElement', {duration: 1000, transition: Fx.Transitions.linear});
4112
4113         //height from 10 to 100 and width from 900 to 300
4114         myEffects.start({
4115                 'height': [10, 100],
4116                 'width': [900, 300]
4117         });
4118
4119         //or height from current height to 100 and width from current width to 300
4120         myEffects.start({
4121                 'height': 100,
4122                 'width': 300
4123         });
4124         (end)
4125 */
4126
4127 Fx.Styles = Fx.Base.extend({
4128
4129         initialize: function(el, options){
4130                 this.element = $(el);
4131                 this.parent(options);
4132         },
4133
4134         setNow: function(){
4135                 for (var p in this.from) this.now[p] = this.css[p].getNow(this.from[p], this.to[p], this);
4136         },
4137
4138         set: function(to){
4139                 var parsed = {};
4140                 this.css = {};
4141                 for (var p in to){
4142                         this.css[p] = Fx.CSS.select(p, to[p]);
4143                         parsed[p] = this.css[p].parse(to[p]);
4144                 }
4145                 return this.parent(parsed);
4146         },
4147
4148         /*
4149         Property: start
4150                 Executes a transition for any number of css properties in tandem.
4151
4152         Arguments:
4153                 obj - an object containing keys that specify css properties to alter and values that specify either the from/to values (as an array) or just the end value (an integer).
4154
4155         Example:
4156                 see <Fx.Styles>
4157         */
4158
4159         start: function(obj){
4160                 if (this.timer && this.options.wait) return this;
4161                 this.now = {};
4162                 this.css = {};
4163                 var from = {}, to = {};
4164                 for (var p in obj){
4165                         var parsed = Fx.CSS.parse(this.element, p, obj[p]);
4166                         from[p] = parsed.from;
4167                         to[p] = parsed.to;
4168                         this.css[p] = parsed.css;
4169                 }
4170                 return this.parent(from, to);
4171         },
4172
4173         increase: function(){
4174                 for (var p in this.now) this.element.setStyle(p, this.css[p].getValue(this.now[p], this.options.unit, p));
4175         }
4176
4177 });
4178
4179 /*
4180 Class: Element
4181         Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
4182 */
4183
4184 Element.extend({
4185
4186         /*
4187         Property: effects
4188                 Applies an <Fx.Styles> to the Element; This a shortcut for <Fx.Styles>.
4189
4190         Example:
4191                 >var myEffects = $(myElement).effects({duration: 1000, transition: Fx.Transitions.Sine.easeInOut});
4192                 >myEffects.start({'height': [10, 100], 'width': [900, 300]});
4193         */
4194
4195         effects: function(options){
4196                 return new Fx.Styles(this, options);
4197         }
4198
4199 });
4200
4201 /*
4202 Script: Fx.Elements.js
4203         Contains <Fx.Elements>
4204
4205 License:
4206         MIT-style license.
4207 */
4208
4209 /*
4210 Class: Fx.Elements
4211         Fx.Elements allows you to apply any number of styles transitions to a selection of elements. Includes colors (must be in hex format).
4212         Inherits methods, properties, options and events from <Fx.Base>.
4213
4214 Arguments:
4215         elements - a collection of elements the effects will be applied to.
4216         options - same as <Fx.Base> options.
4217 */
4218
4219 Fx.Elements = Fx.Base.extend({
4220
4221         initialize: function(elements, options){
4222                 this.elements = $$(elements);
4223                 this.parent(options);
4224         },
4225
4226         setNow: function(){
4227                 for (var i in this.from){
4228                         var iFrom = this.from[i], iTo = this.to[i], iCss = this.css[i], iNow = this.now[i] = {};
4229                         for (var p in iFrom) iNow[p] = iCss[p].getNow(iFrom[p], iTo[p], this);
4230                 }
4231         },
4232
4233         set: function(to){
4234                 var parsed = {};
4235                 this.css = {};
4236                 for (var i in to){
4237                         var iTo = to[i], iCss = this.css[i] = {}, iParsed = parsed[i] = {};
4238                         for (var p in iTo){
4239                                 iCss[p] = Fx.CSS.select(p, iTo[p]);
4240                                 iParsed[p] = iCss[p].parse(iTo[p]);
4241                         }
4242                 }
4243                 return this.parent(parsed);
4244         },
4245
4246         /*
4247         Property: start
4248                 Applies the passed in style transitions to each object named (see example). Each item in the collection is refered to as a numerical string ("1" for instance). The first item is "0", the second "1", etc.
4249
4250         Example:
4251                 (start code)
4252                 var myElementsEffects = new Fx.Elements($$('a'));
4253                 myElementsEffects.start({
4254                         '0': { //let's change the first element's opacity and width
4255                                 'opacity': [0,1],
4256                                 'width': [100,200]
4257                         },
4258                         '4': { //and the fifth one's opacity
4259                                 'opacity': [0.2, 0.5]
4260                         }
4261                 });
4262                 (end)
4263         */
4264
4265         start: function(obj){
4266                 if (this.timer && this.options.wait) return this;
4267                 this.now = {};
4268                 this.css = {};
4269                 var from = {}, to = {};
4270                 for (var i in obj){
4271                         var iProps = obj[i], iFrom = from[i] = {}, iTo = to[i] = {}, iCss = this.css[i] = {};
4272                         for (var p in iProps){
4273                                 var parsed = Fx.CSS.parse(this.elements[i], p, iProps[p]);
4274                                 iFrom[p] = parsed.from;
4275                                 iTo[p] = parsed.to;
4276                                 iCss[p] = parsed.css;
4277                         }
4278                 }
4279                 return this.parent(from, to);
4280         },
4281
4282         increase: function(){
4283                 for (var i in this.now){
4284                         var iNow = this.now[i], iCss = this.css[i];
4285                         for (var p in iNow) this.elements[i].setStyle(p, iCss[p].getValue(iNow[p], this.options.unit, p));
4286                 }
4287         }
4288
4289 });
4290
4291 /*
4292 Script: Fx.Scroll.js
4293         Contains <Fx.Scroll>
4294
4295 License:
4296         MIT-style license.
4297 */
4298
4299 /*
4300 Class: Fx.Scroll
4301         Scroll any element with an overflow, including the window element.
4302         Inherits methods, properties, options and events from <Fx.Base>.
4303
4304 Note:
4305         Fx.Scroll requires an XHTML doctype.
4306
4307 Arguments:
4308         element - the element to scroll
4309         options - optional, see Options below.
4310
4311 Options:
4312         all the Fx.Base options and events, plus:
4313         offset - the distance for the scrollTo point/element. an Object with x/y properties.
4314         overflown - an array of nested scrolling containers, see <Element.getPosition>
4315 */
4316
4317 Fx.Scroll = Fx.Base.extend({
4318
4319         options: {
4320                 overflown: [],
4321                 offset: {'x': 0, 'y': 0},
4322                 wheelStops: true
4323         },
4324
4325         initialize: function(element, options){
4326                 this.now = [];
4327                 this.element = $(element);
4328                 this.bound = {'stop': this.stop.bind(this, false)};
4329                 this.parent(options);
4330                 if (this.options.wheelStops){
4331                         this.addEvent('onStart', function(){
4332                                 document.addEvent('mousewheel', this.bound.stop);
4333                         }.bind(this));
4334                         this.addEvent('onComplete', function(){
4335                                 document.removeEvent('mousewheel', this.bound.stop);
4336                         }.bind(this));
4337                 }
4338         },
4339
4340         setNow: function(){
4341                 for (var i = 0; i < 2; i++) this.now[i] = this.compute(this.from[i], this.to[i]);
4342         },
4343
4344         /*
4345         Property: scrollTo
4346                 Scrolls the chosen element to the x/y coordinates.
4347
4348         Arguments:
4349                 x - the x coordinate to scroll the element to
4350                 y - the y coordinate to scroll the element to
4351         */
4352
4353         scrollTo: function(x, y){
4354                 if (this.timer && this.options.wait) return this;
4355                 var el = this.element.getSize();
4356                 var values = {'x': x, 'y': y};
4357                 for (var z in el.size){
4358                         var max = el.scrollSize[z] - el.size[z];
4359                         if ($chk(values[z])) values[z] = ($type(values[z]) == 'number') ? values[z].limit(0, max) : max;
4360                         else values[z] = el.scroll[z];
4361                         values[z] += this.options.offset[z];
4362                 }
4363                 return this.start([el.scroll.x, el.scroll.y], [values.x, values.y]);
4364         },
4365
4366         /*
4367         Property: toTop
4368                 Scrolls the chosen element to its maximum top.
4369         */
4370
4371         toTop: function(){
4372                 return this.scrollTo(false, 0);
4373         },
4374
4375         /*
4376         Property: toBottom
4377                 Scrolls the chosen element to its maximum bottom.
4378         */
4379
4380         toBottom: function(){
4381                 return this.scrollTo(false, 'full');
4382         },
4383
4384         /*
4385         Property: toLeft
4386                 Scrolls the chosen element to its maximum left.
4387         */
4388
4389         toLeft: function(){
4390                 return this.scrollTo(0, false);
4391         },
4392
4393         /*
4394         Property: toRight
4395                 Scrolls the chosen element to its maximum right.
4396         */
4397
4398         toRight: function(){
4399                 return this.scrollTo('full', false);
4400         },
4401
4402         /*
4403         Property: toElement
4404                 Scrolls the specified element to the position the passed in element is found.
4405
4406         Arguments:
4407                 el - the $(element) to scroll the window to
4408         */
4409
4410         toElement: function(el){
4411                 var parent = this.element.getPosition(this.options.overflown);
4412                 var target = $(el).getPosition(this.options.overflown);
4413                 return this.scrollTo(target.x - parent.x, target.y - parent.y);
4414         },
4415
4416         increase: function(){
4417                 this.element.scrollTo(this.now[0], this.now[1]);
4418         }
4419
4420 });
4421
4422 /*
4423 Script: Fx.Slide.js
4424         Contains <Fx.Slide>
4425
4426 License:
4427         MIT-style license.
4428 */
4429
4430 /*
4431 Class: Fx.Slide
4432         The slide effect; slides an element in horizontally or vertically, the contents will fold inside.
4433         Inherits methods, properties, options and events from <Fx.Base>.
4434         
4435 Note:
4436         Fx.Slide requires an XHTML doctype.
4437
4438 Options:
4439         mode - set it to vertical or horizontal. Defaults to vertical.
4440         options - all the <Fx.Base> options
4441
4442 Example:
4443         (start code)
4444         var mySlider = new Fx.Slide('myElement', {duration: 500});
4445         mySlider.toggle() //toggle the slider up and down.
4446         (end)
4447 */
4448
4449 Fx.Slide = Fx.Base.extend({
4450
4451         options: {
4452                 mode: 'vertical'
4453         },
4454
4455         initialize: function(el, options){
4456                 this.element = $(el);
4457                 this.wrapper = new Element('div', {'styles': $extend(this.element.getStyles('margin'), {'overflow': 'hidden'})}).injectAfter(this.element).adopt(this.element);
4458                 this.element.setStyle('margin', 0);
4459                 this.setOptions(options);
4460                 this.now = [];
4461                 this.parent(this.options);
4462                 this.open = true;
4463                 this.addEvent('onComplete', function(){
4464                         this.open = (this.now[0] === 0);
4465                 });
4466                 if (window.webkit419) this.addEvent('onComplete', function(){
4467                         if (this.open) this.element.remove().inject(this.wrapper);
4468                 });
4469         },
4470
4471         setNow: function(){
4472                 for (var i = 0; i < 2; i++) this.now[i] = this.compute(this.from[i], this.to[i]);
4473         },
4474
4475         vertical: function(){
4476                 this.margin = 'margin-top';
4477                 this.layout = 'height';
4478                 this.offset = this.element.offsetHeight;
4479         },
4480
4481         horizontal: function(){
4482                 this.margin = 'margin-left';
4483                 this.layout = 'width';
4484                 this.offset = this.element.offsetWidth;
4485         },
4486
4487         /*
4488         Property: slideIn
4489                 Slides the elements in view horizontally or vertically.
4490
4491         Arguments:
4492                 mode - (optional, string) 'horizontal' or 'vertical'; defaults to options.mode.
4493         */
4494
4495         slideIn: function(mode){
4496                 this[mode || this.options.mode]();
4497                 return this.start([this.element.getStyle(this.margin).toInt(), this.wrapper.getStyle(this.layout).toInt()], [0, this.offset]);
4498         },
4499
4500         /*
4501         Property: slideOut
4502                 Sides the elements out of view horizontally or vertically.
4503
4504         Arguments:
4505                 mode - (optional, string) 'horizontal' or 'vertical'; defaults to options.mode.
4506         */
4507
4508         slideOut: function(mode){
4509                 this[mode || this.options.mode]();
4510                 return this.start([this.element.getStyle(this.margin).toInt(), this.wrapper.getStyle(this.layout).toInt()], [-this.offset, 0]);
4511         },
4512
4513         /*
4514         Property: hide
4515                 Hides the element without a transition.
4516
4517         Arguments:
4518                 mode - (optional, string) 'horizontal' or 'vertical'; defaults to options.mode.
4519         */
4520
4521         hide: function(mode){
4522                 this[mode || this.options.mode]();
4523                 this.open = false;
4524                 return this.set([-this.offset, 0]);
4525         },
4526
4527         /*
4528         Property: show
4529                 Shows the element without a transition.
4530
4531         Arguments:
4532                 mode - (optional, string) 'horizontal' or 'vertical'; defaults to options.mode.
4533         */
4534
4535         show: function(mode){
4536                 this[mode || this.options.mode]();
4537                 this.open = true;
4538                 return this.set([0, this.offset]);
4539         },
4540
4541         /*
4542         Property: toggle
4543                 Slides in or Out the element, depending on its state
4544
4545         Arguments:
4546                 mode - (optional, string) 'horizontal' or 'vertical'; defaults to options.mode.
4547
4548         */
4549
4550         toggle: function(mode){
4551                 if (this.wrapper.offsetHeight == 0 || this.wrapper.offsetWidth == 0) return this.slideIn(mode);
4552                 return this.slideOut(mode);
4553         },
4554
4555         increase: function(){
4556                 this.element.setStyle(this.margin, this.now[0] + this.options.unit);
4557                 this.wrapper.setStyle(this.layout, this.now[1] + this.options.unit);
4558         }
4559
4560 });
4561
4562 /*
4563 Script: Fx.Transitions.js
4564         Effects transitions, to be used with all the effects.
4565
4566 License:
4567         MIT-style license.
4568
4569 Credits:
4570         Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified & optimized to be used with mootools.
4571 */
4572
4573 /*
4574 Class: Fx.Transitions
4575         A collection of tweening transitions for use with the <Fx.Base> classes.
4576
4577 Example:
4578         >//Elastic.easeOut with default values:
4579         >new Fx.Style('margin', {transition: Fx.Transitions.Elastic.easeOut});
4580         >//Elastic.easeOut with user-defined value for elasticity.
4581         > var myTransition = new Fx.Transition(Fx.Transitions.Elastic, 3);
4582         >new Fx.Style('margin', {transition: myTransition.easeOut});
4583
4584 See also:
4585         http://www.robertpenner.com/easing/
4586 */
4587
4588 Fx.Transition = function(transition, params){
4589         params = params || [];
4590         if ($type(params) != 'array') params = [params];
4591         return $extend(transition, {
4592                 easeIn: function(pos){
4593                         return transition(pos, params);
4594                 },
4595                 easeOut: function(pos){
4596                         return 1 - transition(1 - pos, params);
4597                 },
4598                 easeInOut: function(pos){
4599                         return (pos <= 0.5) ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2;
4600                 }
4601         });
4602 };
4603
4604 Fx.Transitions = new Abstract({
4605
4606         /*
4607         Property: linear
4608                 displays a linear transition.
4609
4610         Graph:
4611                 (see Linear.png)
4612         */
4613
4614         linear: function(p){
4615                 return p;
4616         }
4617
4618 });
4619
4620 Fx.Transitions.extend = function(transitions){
4621         for (var transition in transitions){
4622                 Fx.Transitions[transition] = new Fx.Transition(transitions[transition]);
4623                 /*compatibility*/
4624                 Fx.Transitions.compat(transition);
4625                 /*end compatibility*/
4626         }
4627 };
4628
4629 /*compatibility*/
4630
4631 Fx.Transitions.compat = function(transition){
4632         ['In', 'Out', 'InOut'].each(function(easeType){
4633                 Fx.Transitions[transition.toLowerCase() + easeType] = Fx.Transitions[transition]['ease' + easeType];
4634         });
4635 };
4636
4637 /*end compatibility*/
4638
4639 Fx.Transitions.extend({
4640
4641         /*
4642         Property: Quad
4643                 displays a quadratic transition. Must be used as Quad.easeIn or Quad.easeOut or Quad.easeInOut
4644
4645         Graph:
4646                 (see Quad.png)
4647         */
4648
4649         //auto generated
4650
4651         /*
4652         Property: Cubic
4653                 displays a cubicular transition. Must be used as Cubic.easeIn or Cubic.easeOut or Cubic.easeInOut
4654
4655         Graph:
4656                 (see Cubic.png)
4657         */
4658
4659         //auto generated
4660
4661         /*
4662         Property: Quart
4663                 displays a quartetic transition. Must be used as Quart.easeIn or Quart.easeOut or Quart.easeInOut
4664
4665         Graph:
4666                 (see Quart.png)
4667         */
4668
4669         //auto generated
4670
4671         /*
4672         Property: Quint
4673                 displays a quintic transition. Must be used as Quint.easeIn or Quint.easeOut or Quint.easeInOut
4674
4675         Graph:
4676                 (see Quint.png)
4677         */
4678
4679         //auto generated
4680
4681         /*
4682         Property: Pow
4683                 Used to generate Quad, Cubic, Quart and Quint.
4684                 By default is p^6.
4685
4686         Graph:
4687                 (see Pow.png)
4688         */
4689
4690         Pow: function(p, x){
4691                 return Math.pow(p, x[0] || 6);
4692         },
4693
4694         /*
4695         Property: Expo
4696                 displays a exponential transition. Must be used as Expo.easeIn or Expo.easeOut or Expo.easeInOut
4697
4698         Graph:
4699                 (see Expo.png)
4700         */
4701
4702         Expo: function(p){
4703                 return Math.pow(2, 8 * (p - 1));
4704         },
4705
4706         /*
4707         Property: Circ
4708                 displays a circular transition. Must be used as Circ.easeIn or Circ.easeOut or Circ.easeInOut
4709
4710         Graph:
4711                 (see Circ.png)
4712         */
4713
4714         Circ: function(p){
4715                 return 1 - Math.sin(Math.acos(p));
4716         },
4717
4718
4719         /*
4720         Property: Sine
4721                 displays a sineousidal transition. Must be used as Sine.easeIn or Sine.easeOut or Sine.easeInOut
4722
4723         Graph:
4724                 (see Sine.png)
4725         */
4726
4727         Sine: function(p){
4728                 return 1 - Math.sin((1 - p) * Math.PI / 2);
4729         },
4730
4731         /*
4732         Property: Back
4733                 makes the transition go back, then all forth. Must be used as Back.easeIn or Back.easeOut or Back.easeInOut
4734
4735         Graph:
4736                 (see Back.png)
4737         */
4738
4739         Back: function(p, x){
4740                 x = x[0] || 1.618;
4741                 return Math.pow(p, 2) * ((x + 1) * p - x);
4742         },
4743
4744         /*
4745         Property: Bounce
4746                 makes the transition bouncy. Must be used as Bounce.easeIn or Bounce.easeOut or Bounce.easeInOut
4747
4748         Graph:
4749                 (see Bounce.png)
4750         */
4751
4752         Bounce: function(p){
4753                 var value;
4754                 for (var a = 0, b = 1; 1; a += b, b /= 2){
4755                         if (p >= (7 - 4 * a) / 11){
4756                                 value = - Math.pow((11 - 6 * a - 11 * p) / 4, 2) + b * b;
4757                                 break;
4758                         }
4759                 }
4760                 return value;
4761         },
4762
4763         /*
4764         Property: Elastic
4765                 Elastic curve. Must be used as Elastic.easeIn or Elastic.easeOut or Elastic.easeInOut
4766
4767         Graph:
4768                 (see Elastic.png)
4769         */
4770
4771         Elastic: function(p, x){
4772                 return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3);
4773         }
4774
4775 });
4776
4777 ['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){
4778         Fx.Transitions[transition] = new Fx.Transition(function(p){
4779                 return Math.pow(p, [i + 2]);
4780         });
4781         
4782         /*compatibility*/
4783         Fx.Transitions.compat(transition);
4784         /*end compatibility*/
4785 });
4786
4787 /*
4788 Script: Drag.Base.js
4789         Contains <Drag.Base>, <Element.makeResizable>
4790
4791 License:
4792         MIT-style license.
4793 */
4794
4795 var Drag = {};
4796
4797 /*
4798 Class: Drag.Base
4799         Modify two css properties of an element based on the position of the mouse.
4800         
4801 Note:
4802         Drag.Base requires an XHTML doctype.
4803
4804 Arguments:
4805         el - the $(element) to apply the transformations to.
4806         options - optional. The options object.
4807
4808 Options:
4809         handle - the $(element) to act as the handle for the draggable element. defaults to the $(element) itself.
4810         modifiers - an object. see Modifiers Below.
4811         limit - an object, see Limit below.
4812         grid - optional, distance in px for snap-to-grid dragging
4813         snap - optional, the distance you have to drag before the element starts to respond to the drag. defaults to false
4814
4815         modifiers:
4816                 x - string, the style you want to modify when the mouse moves in an horizontal direction. defaults to 'left'
4817                 y - string, the style you want to modify when the mouse moves in a vertical direction. defaults to 'top'
4818
4819         limit:
4820                 x - array with start and end limit relative to modifiers.x
4821                 y - array with start and end limit relative to modifiers.y
4822                 
4823 Events:
4824         onStart - optional, function to execute when the user starts to drag (on mousedown);
4825         onComplete - optional, function to execute when the user completes the drag.
4826         onDrag - optional, function to execute at every step of the drag
4827 */
4828
4829 Drag.Base = new Class({
4830
4831         options: {
4832                 handle: false,
4833                 unit: 'px',
4834                 onStart: Class.empty,
4835                 onBeforeStart: Class.empty,
4836                 onComplete: Class.empty,
4837                 onSnap: Class.empty,
4838                 onDrag: Class.empty,
4839                 limit: false,
4840                 modifiers: {x: 'left', y: 'top'},
4841                 grid: false,
4842                 snap: 6
4843         },
4844
4845         initialize: function(el, options){
4846                 this.setOptions(options);
4847                 this.element = $(el);
4848                 this.handle = $(this.options.handle) || this.element;
4849                 this.mouse = {'now': {}, 'pos': {}};
4850                 this.value = {'start': {}, 'now': {}};
4851                 this.bound = {
4852                         'start': this.start.bindWithEvent(this),
4853                         'check': this.check.bindWithEvent(this),
4854                         'drag': this.drag.bindWithEvent(this),
4855                         'stop': this.stop.bind(this)
4856                 };
4857                 this.attach();
4858                 if (this.options.initialize) this.options.initialize.call(this);
4859         },
4860
4861         attach: function(){
4862                 this.handle.addEvent('mousedown', this.bound.start);
4863                 return this;
4864         },
4865
4866         detach: function(){
4867                 this.handle.removeEvent('mousedown', this.bound.start);
4868                 return this;
4869         },
4870
4871         start: function(event){
4872                 this.fireEvent('onBeforeStart', this.element);
4873                 this.mouse.start = event.page;
4874                 var limit = this.options.limit;
4875                 this.limit = {'x': [], 'y': []};
4876                 for (var z in this.options.modifiers){
4877                         if (!this.options.modifiers[z]) continue;
4878                         this.value.now[z] = this.element.getStyle(this.options.modifiers[z]).toInt();
4879                         this.mouse.pos[z] = event.page[z] - this.value.now[z];
4880                         if (limit && limit[z]){
4881                                 for (var i = 0; i < 2; i++){
4882                                         if ($chk(limit[z][i])) this.limit[z][i] = ($type(limit[z][i]) == 'function') ? limit[z][i]() : limit[z][i];
4883                                 }
4884                         }
4885                 }
4886                 if ($type(this.options.grid) == 'number') this.options.grid = {'x': this.options.grid, 'y': this.options.grid};
4887                 document.addListener('mousemove', this.bound.check);
4888                 document.addListener('mouseup', this.bound.stop);
4889                 this.fireEvent('onStart', this.element);
4890                 event.stop();
4891         },
4892
4893         check: function(event){
4894                 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)));
4895                 if (distance > this.options.snap){
4896                         document.removeListener('mousemove', this.bound.check);
4897                         document.addListener('mousemove', this.bound.drag);
4898                         this.drag(event);
4899                         this.fireEvent('onSnap', this.element);
4900                 }
4901                 event.stop();
4902         },
4903
4904         drag: function(event){
4905                 this.out = false;
4906                 this.mouse.now = event.page;
4907                 for (var z in this.options.modifiers){
4908                         if (!this.options.modifiers[z]) continue;
4909                         this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z];
4910                         if (this.limit[z]){
4911                                 if ($chk(this.limit[z][1]) && (this.value.now[z] > this.limit[z][1])){
4912                                         this.value.now[z] = this.limit[z][1];
4913                                         this.out = true;
4914                                 } else if ($chk(this.limit[z][0]) && (this.value.now[z] < this.limit[z][0])){
4915                                         this.value.now[z] = this.limit[z][0];
4916                                         this.out = true;
4917                                 }
4918                         }
4919                         if (this.options.grid[z]) this.value.now[z] -= (this.value.now[z] % this.options.grid[z]);
4920                         this.element.setStyle(this.options.modifiers[z], this.value.now[z] + this.options.unit);
4921                 }
4922                 this.fireEvent('onDrag', this.element);
4923                 event.stop();
4924         },
4925
4926         stop: function(){
4927                 document.removeListener('mousemove', this.bound.check);
4928                 document.removeListener('mousemove', this.bound.drag);
4929                 document.removeListener('mouseup', this.bound.stop);
4930                 this.fireEvent('onComplete', this.element);
4931         }
4932
4933 });
4934
4935 Drag.Base.implement(new Events, new Options);
4936
4937 /*
4938 Class: Element
4939         Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
4940 */
4941
4942 Element.extend({
4943
4944         /*
4945         Property: makeResizable
4946                 Makes an element resizable (by dragging) with the supplied options.
4947
4948         Arguments:
4949                 options - see <Drag.Base> for acceptable options.
4950         */
4951
4952         makeResizable: function(options){
4953                 return new Drag.Base(this, $merge({modifiers: {x: 'width', y: 'height'}}, options));
4954         }
4955
4956 });
4957
4958 /*
4959 Script: Drag.Move.js
4960         Contains <Drag.Move>, <Element.makeDraggable>
4961
4962 License:
4963         MIT-style license.
4964 */
4965
4966 /*
4967 Class: Drag.Move
4968         Extends <Drag.Base>, has additional functionality for dragging an element, support snapping and droppables.
4969         Drag.move supports either position absolute or relative. If no position is found, absolute will be set.
4970         Inherits methods, properties, options and events from <Drag.Base>.
4971
4972 Note:
4973         Drag.Move requires an XHTML doctype.
4974
4975 Arguments:
4976         el - the $(element) to apply the drag to.
4977         options - optional. see Options below.
4978
4979 Options:
4980         all the drag.Base options, plus:
4981         container - an element, will fill automatically limiting options based on the $(element) size and position. defaults to false (no limiting)
4982         droppables - an array of elements you can drop your draggable to.
4983         overflown - an array of nested scrolling containers, see Element::getPosition
4984 */
4985
4986 Drag.Move = Drag.Base.extend({
4987
4988         options: {
4989                 droppables: [],
4990                 container: false,
4991                 overflown: []
4992         },
4993
4994         initialize: function(el, options){
4995                 this.setOptions(options);
4996                 this.element = $(el);
4997                 this.droppables = $$(this.options.droppables);
4998                 this.container = $(this.options.container);
4999                 this.position = {'element': this.element.getStyle('position'), 'container': false};
5000                 if (this.container) this.position.container = this.container.getStyle('position');
5001                 if (!['relative', 'absolute', 'fixed'].contains(this.position.element)) this.position.element = 'absolute';
5002                 var top = this.element.getStyle('top').toInt();
5003                 var left = this.element.getStyle('left').toInt();
5004                 if (this.position.element == 'absolute' && !['relative', 'absolute', 'fixed'].contains(this.position.container)){
5005                         top = $chk(top) ? top : this.element.getTop(this.options.overflown);
5006                         left = $chk(left) ? left : this.element.getLeft(this.options.overflown);
5007                 } else {
5008                         top = $chk(top) ? top : 0;
5009                         left = $chk(left) ? left : 0;
5010                 }
5011                 this.element.setStyles({'top': top, 'left': left, 'position': this.position.element});
5012                 this.parent(this.element);
5013         },
5014
5015         start: function(event){
5016                 this.overed = null;
5017                 if (this.container){
5018                         var cont = this.container.getCoordinates();
5019                         var el = this.element.getCoordinates();
5020                         if (this.position.element == 'absolute' && !['relative', 'absolute', 'fixed'].contains(this.position.container)){
5021                                 this.options.limit = {
5022                                         'x': [cont.left, cont.right - el.width],
5023                                         'y': [cont.top, cont.bottom - el.height]
5024                                 };
5025                         } else {
5026                                 this.options.limit = {
5027                                         'y': [0, cont.height - el.height],
5028                                         'x': [0, cont.width - el.width]
5029                                 };
5030                         }
5031                 }
5032                 this.parent(event);
5033         },
5034
5035         drag: function(event){
5036                 this.parent(event);
5037                 var overed = this.out ? false : this.droppables.filter(this.checkAgainst, this).getLast();
5038                 if (this.overed != overed){
5039                         if (this.overed) this.overed.fireEvent('leave', [this.element, this]);
5040                         this.overed = overed ? overed.fireEvent('over', [this.element, this]) : null;
5041                 }
5042                 return this;
5043         },
5044
5045         checkAgainst: function(el){
5046                 el = el.getCoordinates(this.options.overflown);
5047                 var now = this.mouse.now;
5048                 return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top);
5049         },
5050
5051         stop: function(){
5052                 if (this.overed && !this.out) this.overed.fireEvent('drop', [this.element, this]);
5053                 else this.element.fireEvent('emptydrop', this);
5054                 this.parent();
5055                 return this;
5056         }
5057
5058 });
5059
5060 /*
5061 Class: Element
5062         Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
5063 */
5064
5065 Element.extend({
5066
5067         /*
5068         Property: makeDraggable
5069                 Makes an element draggable with the supplied options.
5070
5071         Arguments:
5072                 options - see <Drag.Move> and <Drag.Base> for acceptable options.
5073         */
5074
5075         makeDraggable: function(options){
5076                 return new Drag.Move(this, options);
5077         }
5078
5079 });
5080
5081 /*
5082 Script: XHR.js
5083         Contains the basic XMLHttpRequest Class Wrapper.
5084
5085 License:
5086         MIT-style license.
5087 */
5088
5089 /*
5090 Class: XHR
5091         Basic XMLHttpRequest Wrapper.
5092
5093 Arguments:
5094         options - an object with options names as keys. See options below.
5095
5096 Options:
5097         method - 'post' or 'get' - the protocol for the request; optional, defaults to 'post'.
5098         async - boolean: asynchronous option; true uses asynchronous requests. Defaults to true.
5099         encoding - the encoding, defaults to utf-8.
5100         autoCancel - cancels the already running request if another one is sent. defaults to false.
5101         headers - accepts an object, that will be set to request headers.
5102         
5103 Events:
5104         onRequest - function to execute when the XHR request is fired.
5105         onSuccess - function to execute when the XHR request completes.
5106         onStateChange - function to execute when the state of the XMLHttpRequest changes.
5107         onFailure - function to execute when the state of the XMLHttpRequest changes.
5108
5109 Properties:
5110         running - true if the request is running.
5111         response - object, text and xml as keys. You can access this property in the onSuccess event.
5112
5113 Example:
5114         >var myXHR = new XHR({method: 'get'}).send('http://site.com/requestHandler.php', 'name=john&lastname=dorian');
5115 */
5116
5117 var XHR = new Class({
5118
5119         options: {
5120                 method: 'post',
5121                 async: true,
5122                 onRequest: Class.empty,
5123                 onSuccess: Class.empty,
5124                 onFailure: Class.empty,
5125                 urlEncoded: true,
5126                 encoding: 'utf-8',
5127                 autoCancel: false,
5128                 headers: {}
5129         },
5130
5131         setTransport: function(){
5132                 this.transport = (window.XMLHttpRequest) ? new XMLHttpRequest() : (window.ie ? new ActiveXObject('Microsoft.XMLHTTP') : false);
5133                 return this;
5134         },
5135
5136         initialize: function(options){
5137                 this.setTransport().setOptions(options);
5138                 this.options.isSuccess = this.options.isSuccess || this.isSuccess;
5139                 this.headers = {};
5140                 if (this.options.urlEncoded && this.options.method == 'post'){
5141                         var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
5142                         this.setHeader('Content-type', 'application/x-www-form-urlencoded' + encoding);
5143                 }
5144                 if (this.options.initialize) this.options.initialize.call(this);
5145         },
5146
5147         onStateChange: function(){
5148                 if (this.transport.readyState != 4 || !this.running) return;
5149                 this.running = false;
5150                 var status = 0;
5151                 try {status = this.transport.status;} catch(e){};
5152                 if (this.options.isSuccess.call(this, status)) this.onSuccess();
5153                 else this.onFailure();
5154                 this.transport.onreadystatechange = Class.empty;
5155         },
5156
5157         isSuccess: function(status){
5158                 return ((status >= 200) && (status < 300));
5159         },
5160
5161         onSuccess: function(){
5162                 this.response = {
5163                         'text': this.transport.responseText,
5164                         'xml': this.transport.responseXML
5165                 };
5166                 this.fireEvent('onSuccess', [this.response.text, this.response.xml]);
5167                 this.callChain();
5168         },
5169
5170         onFailure: function(){
5171                 this.fireEvent('onFailure', this.transport);
5172         },
5173
5174         /*
5175         Property: setHeader
5176                 Add/modify an header for the request. It will not override headers from the options.
5177
5178         Example:
5179                 >var myXhr = new XHR(url, {method: 'get', headers: {'X-Request': 'JSON'}});
5180                 >myXhr.setHeader('Last-Modified','Sat, 1 Jan 2005 05:00:00 GMT');
5181         */
5182
5183         setHeader: function(name, value){
5184                 this.headers[name] = value;
5185                 return this;
5186         },
5187
5188         /*
5189         Property: send
5190                 Opens the XHR connection and sends the data. Data has to be null or a string.
5191
5192         Example:
5193                 >var myXhr = new XHR({method: 'post'});
5194                 >myXhr.send(url, querystring);
5195                 >
5196                 >var syncXhr = new XHR({async: false, method: 'post'});
5197                 >syncXhr.send(url, null);
5198                 >
5199         */
5200
5201         send: function(url, data){
5202                 if (this.options.autoCancel) this.cancel();
5203                 else if (this.running) return this;
5204                 this.running = true;
5205                 if (data && this.options.method == 'get'){
5206                         url = url + (url.contains('?') ? '&' : '?') + data;
5207                         data = null;
5208                 }
5209                 this.transport.open(this.options.method.toUpperCase(), url, this.options.async);
5210                 this.transport.onreadystatechange = this.onStateChange.bind(this);
5211                 if ((this.options.method == 'post') && this.transport.overrideMimeType) this.setHeader('Connection', 'close');
5212                 $extend(this.headers, this.options.headers);
5213                 for (var type in this.headers) try {this.transport.setRequestHeader(type, this.headers[type]);} catch(e){};
5214                 this.fireEvent('onRequest');
5215                 this.transport.send($pick(data, null));
5216                 return this;
5217         },
5218
5219         /*
5220         Property: cancel
5221                 Cancels the running request. No effect if the request is not running.
5222
5223         Example:
5224                 >var myXhr = new XHR({method: 'get'}).send(url);
5225                 >myXhr.cancel();
5226         */
5227
5228         cancel: function(){
5229                 if (!this.running) return this;
5230                 this.running = false;
5231                 this.transport.abort();
5232                 this.transport.onreadystatechange = Class.empty;
5233                 this.setTransport();
5234                 this.fireEvent('onCancel');
5235                 return this;
5236         }
5237
5238 });
5239
5240 XHR.implement(new Chain, new Events, new Options);
5241
5242 /*
5243 Script: Ajax.js
5244         Contains the <Ajax> class. Also contains methods to generate querystings from forms and Objects.
5245
5246 Credits:
5247         Loosely based on the version from prototype.js <http://prototype.conio.net>
5248
5249 License:
5250         MIT-style license.
5251 */
5252
5253 /*
5254 Class: Ajax
5255         An Ajax class, For all your asynchronous needs.
5256         Inherits methods, properties, options and events from <XHR>.
5257
5258 Arguments:
5259         url - the url pointing to the server-side script.
5260         options - optional, an object containing options.
5261
5262 Options:
5263         data - you can write parameters here. Can be a querystring, an object or a Form element.
5264         update - $(element) to insert the response text of the XHR into, upon completion of the request.
5265         evalScripts - boolean; default is false. Execute scripts in the response text onComplete. When the response is javascript the whole response is evaluated.
5266         evalResponse - boolean; default is false. Force global evalulation of the whole response, no matter what content-type it is.
5267         
5268 Events:
5269         onComplete - function to execute when the ajax request completes.
5270
5271 Example:
5272         >var myAjax = new Ajax(url, {method: 'get'}).request();
5273 */
5274
5275 var Ajax = XHR.extend({
5276
5277         options: {
5278                 data: null,
5279                 update: null,
5280                 onComplete: Class.empty,
5281                 evalScripts: false,
5282                 evalResponse: false
5283         },
5284
5285         initialize: function(url, options){
5286                 this.addEvent('onSuccess', this.onComplete);
5287                 this.setOptions(options);
5288                 /*compatibility*/
5289                 this.options.data = this.options.data || this.options.postBody;
5290                 /*end compatibility*/
5291                 if (!['post', 'get'].contains(this.options.method)){
5292                         this._method = '_method=' + this.options.method;
5293                         this.options.method = 'post';
5294                 }
5295                 this.parent();
5296                 this.setHeader('X-Requested-With', 'XMLHttpRequest');
5297                 this.setHeader('Accept', 'text/javascript, text/html, application/xml, text/xml, */*');
5298                 this.url = url;
5299         },
5300
5301         onComplete: function(){
5302                 if (this.options.update) $(this.options.update).empty().setHTML(this.response.text);
5303                 if (this.options.evalScripts || this.options.evalResponse) this.evalScripts();
5304                 this.fireEvent('onComplete', [this.response.text, this.response.xml], 20);
5305         },
5306
5307         /*
5308         Property: request
5309                 Executes the ajax request.
5310
5311         Example:
5312                 >var myAjax = new Ajax(url, {method: 'get'});
5313                 >myAjax.request();
5314
5315                 OR
5316
5317                 >new Ajax(url, {method: 'get'}).request();
5318         */
5319
5320         request: function(data){
5321                 data = data || this.options.data;
5322                 switch($type(data)){
5323                         case 'element': data = $(data).toQueryString(); break;
5324                         case 'object': data = Object.toQueryString(data);
5325                 }
5326                 if (this._method) data = (data) ? [this._method, data].join('&') : this._method;
5327                 return this.send(this.url, data);
5328         },
5329
5330         /*
5331         Property: evalScripts
5332                 Executes scripts in the response text
5333         */
5334
5335         evalScripts: function(){
5336                 var script, scripts;
5337                 if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) scripts = this.response.text;
5338                 else {
5339                         scripts = [];
5340                         var regexp = /<script[^>]*>([\s\S]*?)<\/script>/gi;
5341                         while ((script = regexp.exec(this.response.text))) scripts.push(script[1]);
5342                         scripts = scripts.join('\n');
5343                 }
5344                 if (scripts) (window.execScript) ? window.execScript(scripts) : window.setTimeout(scripts, 0);
5345         },
5346
5347         /*
5348         Property: getHeader
5349                 Returns the given response header or null
5350         */
5351
5352         getHeader: function(name){
5353                 try {return this.transport.getResponseHeader(name);} catch(e){};
5354                 return null;
5355         }
5356
5357 });
5358
5359 /* Section: Object related Functions */
5360
5361 /*
5362 Function: Object.toQueryString
5363         Generates a querystring from key/pair values in an object
5364
5365 Arguments:
5366         source - the object to generate the querystring from.
5367
5368 Returns:
5369         the query string.
5370
5371 Example:
5372         >Object.toQueryString({apple: "red", lemon: "yellow"}); //returns "apple=red&lemon=yellow"
5373 */
5374
5375 Object.toQueryString = function(source){
5376         var queryString = [];
5377         for (var property in source) queryString.push(encodeURIComponent(property) + '=' + encodeURIComponent(source[property]));
5378         return queryString.join('&');
5379 };
5380
5381 /*
5382 Class: Element
5383         Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
5384 */
5385
5386 Element.extend({
5387
5388         /*
5389         Property: send
5390                 Sends a form with an ajax post request
5391
5392         Arguments:
5393                 options - option collection for ajax request. See <Ajax> for the options list.
5394
5395         Returns:
5396                 The Ajax Class Instance
5397
5398         Example:
5399                 (start code)
5400                 <form id="myForm" action="submit.php">
5401                 <input name="email" value="bob@bob.com">
5402                 <input name="zipCode" value="90210">
5403                 </form>
5404                 <script>
5405                 $('myForm').send()
5406                 </script>
5407                 (end)
5408         */
5409
5410         send: function(options){
5411                 return new Ajax(this.getProperty('action'), $merge({data: this.toQueryString()}, options, {method: 'post'})).request();
5412         }
5413
5414 });
5415
5416 /*
5417 Script: Cookie.js
5418         A cookie reader/creator
5419
5420 Credits:
5421         based on the functions by Peter-Paul Koch (http://quirksmode.org)
5422 */
5423
5424 /*
5425 Class: Cookie
5426         Class for creating, getting, and removing cookies.
5427 */
5428
5429 var Cookie = new Abstract({
5430
5431         options: {
5432                 domain: false,
5433                 path: false,
5434                 duration: false,
5435                 secure: false
5436         },
5437
5438         /*
5439         Property: set
5440                 Sets a cookie in the browser.
5441
5442         Arguments:
5443                 key - the key (name) for the cookie
5444                 value - the value to set, cannot contain semicolons
5445                 options - an object representing the Cookie options. See Options below. Default values are stored in Cookie.options.
5446
5447         Options:
5448                 domain - the domain the Cookie belongs to. If you want to share the cookie with pages located on a different domain, you have to set this value. Defaults to the current domain.
5449                 path - the path the Cookie belongs to. If you want to share the cookie with pages located in a different path, you have to set this value, for example to "/" to share the cookie with all pages on the domain. Defaults to the current path.
5450                 duration - the duration of the Cookie before it expires, in days.
5451                                         If set to false or 0, the cookie will be a session cookie that expires when the browser is closed. This is default.
5452                 secure - Stored cookie information can be accessed only from a secure environment.
5453
5454         Returns:
5455                 An object with the options, the key and the value. You can give it as first parameter to Cookie.remove.
5456
5457         Example:
5458                 >Cookie.set('username', 'Harald'); // session cookie (duration is false), or ...
5459                 >Cookie.set('username', 'JackBauer', {duration: 1}); // save this for 1 day
5460
5461         */
5462
5463         set: function(key, value, options){
5464                 options = $merge(this.options, options);
5465                 value = encodeURIComponent(value);
5466                 if (options.domain) value += '; domain=' + options.domain;
5467                 if (options.path) value += '; path=' + options.path;
5468                 if (options.duration){
5469                         var date = new Date();
5470                         date.setTime(date.getTime() + options.duration * 24 * 60 * 60 * 1000);
5471                         value += '; expires=' + date.toGMTString();
5472                 }
5473                 if (options.secure) value += '; secure';
5474                 document.cookie = key + '=' + value;
5475                 return $extend(options, {'key': key, 'value': value});
5476         },
5477
5478         /*
5479         Property: get
5480                 Gets the value of a cookie.
5481
5482         Arguments:
5483                 key - the name of the cookie you wish to retrieve.
5484
5485         Returns:
5486                 The cookie string value, or false if not found.
5487
5488         Example:
5489                 >Cookie.get("username") //returns JackBauer
5490         */
5491
5492         get: function(key){
5493                 var value = document.cookie.match('(?:^|;)\\s*' + key.escapeRegExp() + '=([^;]*)');
5494                 return value ? decodeURIComponent(value[1]) : false;
5495         },
5496
5497         /*
5498         Property: remove
5499                 Removes a cookie from the browser.
5500
5501         Arguments:
5502                 cookie - the name of the cookie to remove or a previous cookie (for domains)
5503                 options - optional. you can also pass the domain and path here. Same as options in <Cookie.set>
5504
5505         Examples:
5506                 >Cookie.remove('username') //bye-bye JackBauer, cya in 24 hours
5507                 >
5508                 >var myCookie = Cookie.set('username', 'Aaron', {domain: 'mootools.net'}); // Cookie.set returns an object with all values need to remove the cookie
5509                 >Cookie.remove(myCookie);
5510         */
5511
5512         remove: function(cookie, options){
5513                 if ($type(cookie) == 'object') this.set(cookie.key, '', $merge(cookie, {duration: -1}));
5514                 else this.set(cookie, '', $merge(options, {duration: -1}));
5515         }
5516
5517 });
5518
5519 /*
5520 Script: Json.js
5521         Simple Json parser and Stringyfier, See: <http://www.json.org/>
5522
5523 License:
5524         MIT-style license.
5525 */
5526
5527 /*
5528 Class: Json
5529         Simple Json parser and Stringyfier, See: <http://www.json.org/>
5530 */
5531
5532 var Json = {
5533
5534         /*
5535         Property: toString
5536                 Converts an object to a string, to be passed in server-side scripts as a parameter. Although its not normal usage for this class, this method can also be used to convert functions and arrays to strings.
5537
5538         Arguments:
5539                 obj - the object to convert to string
5540
5541         Returns:
5542                 A json string
5543
5544         Example:
5545                 (start code)
5546                 Json.toString({apple: 'red', lemon: 'yellow'}); '{"apple":"red","lemon":"yellow"}'
5547                 (end)
5548         */
5549
5550         toString: function(obj){
5551                 switch($type(obj)){
5552                         case 'string':
5553                                 return '"' + obj.replace(/(["\\])/g, '\\$1') + '"';
5554                         case 'array':
5555                                 return '[' + obj.map(Json.toString).join(',') + ']';
5556                         case 'object':
5557                                 var string = [];
5558                                 for (var property in obj) string.push(Json.toString(property) + ':' + Json.toString(obj[property]));
5559                                 return '{' + string.join(',') + '}';
5560                         case 'number':
5561                                 if (isFinite(obj)) break;
5562                         case false:
5563                                 return 'null';
5564                 }
5565                 return String(obj);
5566         },
5567
5568         /*
5569         Property: evaluate
5570                 converts a json string to an javascript Object.
5571
5572         Arguments:
5573                 str - the string to evaluate. if its not a string, it returns false.
5574                 secure - optionally, performs syntax check on json string. Defaults to false.
5575
5576         Credits:
5577                 Json test regexp is by Douglas Crockford <http://crockford.org>.
5578
5579         Example:
5580                 >var myObject = Json.evaluate('{"apple":"red","lemon":"yellow"}');
5581                 >//myObject will become {apple: 'red', lemon: 'yellow'}
5582         */
5583
5584         evaluate: function(str, secure){
5585                 return (($type(str) != 'string') || (secure && !str.test(/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/))) ? null : eval('(' + str + ')');
5586         }
5587
5588 };
5589
5590 /*
5591 Script: Json.Remote.js
5592         Contains <Json.Remote>.
5593
5594 License:
5595         MIT-style license.
5596 */
5597
5598 /*
5599 Class: Json.Remote
5600         Wrapped XHR with automated sending and receiving of Javascript Objects in Json Format.
5601         Inherits methods, properties, options and events from <XHR>.
5602
5603 Arguments:
5604         url - the url you want to send your object to.
5605         options - see <XHR> options
5606
5607 Example:
5608         this code will send user information based on name/last name
5609         (start code)
5610         var jSonRequest = new Json.Remote("http://site.com/tellMeAge.php", {onComplete: function(person){
5611                 alert(person.age); //is 25 years
5612                 alert(person.height); //is 170 cm
5613                 alert(person.weight); //is 120 kg
5614         }}).send({'name': 'John', 'lastName': 'Doe'});
5615         (end)
5616 */
5617
5618 Json.Remote = XHR.extend({
5619
5620         initialize: function(url, options){
5621                 this.url = url;
5622                 this.addEvent('onSuccess', this.onComplete);
5623                 this.parent(options);
5624                 this.setHeader('X-Request', 'JSON');
5625         },
5626
5627         send: function(obj){
5628                 return this.parent(this.url, 'json=' + Json.toString(obj));
5629         },
5630
5631         onComplete: function(){
5632                 this.fireEvent('onComplete', [Json.evaluate(this.response.text, this.options.secure)]);
5633         }
5634
5635 });
5636
5637 /*
5638 Script: Assets.js
5639         provides dynamic loading for images, css and javascript files.
5640
5641 License:
5642         MIT-style license.
5643 */
5644
5645 var Asset = new Abstract({
5646
5647         /*
5648         Property: javascript
5649                 Injects a javascript file in the page.
5650
5651         Arguments:
5652                 source - the path of the javascript file
5653                 properties - some additional attributes you might want to add to the script element
5654
5655         Example:
5656                 > new Asset.javascript('/scripts/myScript.js', {id: 'myScript'});
5657         */
5658
5659         javascript: function(source, properties){
5660                 properties = $merge({
5661                         'onload': Class.empty
5662                 }, properties);
5663                 var script = new Element('script', {'src': source}).addEvents({
5664                         'load': properties.onload,
5665                         'readystatechange': function(){
5666                                 if (this.readyState == 'complete') this.fireEvent('load');
5667                         }
5668                 });
5669                 delete properties.onload;
5670                 return script.setProperties(properties).inject(document.head);
5671         },
5672
5673         /*
5674         Property: css
5675                 Injects a css file in the page.
5676
5677         Arguments:
5678                 source - the path of the css file
5679                 properties - some additional attributes you might want to add to the link element
5680
5681         Example:
5682                 > new Asset.css('/css/myStyle.css', {id: 'myStyle', title: 'myStyle'});
5683         */
5684
5685         css: function(source, properties){
5686                 return new Element('link', $merge({
5687                         'rel': 'stylesheet', 'media': 'screen', 'type': 'text/css', 'href': source
5688                 }, properties)).inject(document.head);
5689         },
5690
5691         /*
5692         Property: image
5693                 Preloads an image and returns the img element. does not inject it to the page.
5694
5695         Arguments:
5696                 source - the path of the image file
5697                 properties - some additional attributes you might want to add to the img element
5698
5699         Example:
5700                 > new Asset.image('/images/myImage.png', {id: 'myImage', title: 'myImage', onload: myFunction});
5701
5702         Returns:
5703                 the img element. you can inject it anywhere you want with <Element.injectInside>/<Element.injectAfter>/<Element.injectBefore>
5704         */
5705
5706         image: function(source, properties){
5707                 properties = $merge({
5708                         'onload': Class.empty,
5709                         'onabort': Class.empty,
5710                         'onerror': Class.empty
5711                 }, properties);
5712                 var image = new Image();
5713                 image.src = source;
5714                 var element = new Element('img', {'src': source});
5715                 ['load', 'abort', 'error'].each(function(type){
5716                         var event = properties['on' + type];
5717                         delete properties['on' + type];
5718                         element.addEvent(type, function(){
5719                                 this.removeEvent(type, arguments.callee);
5720                                 event.call(this);
5721                         });
5722                 });
5723                 if (image.width && image.height) element.fireEvent('load', element, 1);
5724                 return element.setProperties(properties);
5725         },
5726
5727         /*
5728         Property: images
5729                 Preloads an array of images (as strings) and returns an array of img elements. does not inject them to the page.
5730
5731         Arguments:
5732                 sources - array, the paths of the image files
5733                 options - object, see below
5734
5735         Options:
5736                 onComplete - a function to execute when all image files are loaded in the browser's cache
5737                 onProgress - a function to execute when one image file is loaded in the browser's cache
5738
5739         Example:
5740                 (start code)
5741                 new Asset.images(['/images/myImage.png', '/images/myImage2.gif'], {
5742                         onComplete: function(){
5743                                 alert('all images loaded!');
5744                         }
5745                 });
5746                 (end)
5747
5748         Returns:
5749                 the img elements as $$. you can inject them anywhere you want with <Element.injectInside>/<Element.injectAfter>/<Element.injectBefore>
5750         */
5751
5752         images: function(sources, options){
5753                 options = $merge({
5754                         onComplete: Class.empty,
5755                         onProgress: Class.empty
5756                 }, options);
5757                 if (!sources.push) sources = [sources];
5758                 var images = [];
5759                 var counter = 0;
5760                 sources.each(function(source){
5761                         var img = new Asset.image(source, {
5762                                 'onload': function(){
5763                                         options.onProgress.call(this, counter);
5764                                         counter++;
5765                                         if (counter == sources.length) options.onComplete();
5766                                 }
5767                         });
5768                         images.push(img);
5769                 });
5770                 return new Elements(images);
5771         }
5772
5773 });
5774
5775 /*\r
5776 Script: Hash.js\r
5777         Contains the class Hash.\r
5778 \r
5779 License:\r
5780         MIT-style license.\r
5781 */\r
5782 \r
5783 /*\r
5784 Class: Hash\r
5785         It wraps an object that it uses internally as a map. The user must use set(), get(), and remove() to add/change, retrieve and remove values, it must not access the internal object directly. null/undefined values are allowed.\r
5786 \r
5787 Note:\r
5788         Each hash instance has the length property.\r
5789 \r
5790 Arguments:\r
5791         obj - an object to convert into a Hash instance.\r
5792 \r
5793 Example:\r
5794         (start code)\r
5795         var hash = new Hash({a: 'hi', b: 'world', c: 'howdy'});\r
5796         hash.remove('b'); // b is removed.\r
5797         hash.set('c', 'hello');\r
5798         hash.get('c'); // returns 'hello'\r
5799         hash.length // returns 2 (a and c)\r
5800         (end)\r
5801 */\r
5802 \r
5803 var Hash = new Class({\r
5804 \r
5805         length: 0,\r
5806 \r
5807         initialize: function(object){\r
5808                 this.obj = object || {};\r
5809                 this.setLength();\r
5810         },\r
5811 \r
5812         /*\r
5813         Property: get\r
5814                 Retrieves a value from the hash.\r
5815 \r
5816         Arguments:\r
5817                 key - The key\r
5818 \r
5819         Returns:\r
5820                 The value\r
5821         */\r
5822 \r
5823         get: function(key){\r
5824                 return (this.hasKey(key)) ? this.obj[key] : null;\r
5825         },\r
5826 \r
5827         /*\r
5828         Property: hasKey\r
5829                 Check the presence of a specified key-value pair in the hash.\r
5830 \r
5831         Arguments:\r
5832                 key - The key\r
5833 \r
5834         Returns:\r
5835                 True if the Hash contains a value for the specified key, otherwise false\r
5836         */\r
5837 \r
5838         hasKey: function(key){\r
5839                 return (key in this.obj);\r
5840         },\r
5841 \r
5842         /*\r
5843         Property: set\r
5844                 Adds a key-value pair to the hash or replaces a previous value associated with the key.\r
5845 \r
5846         Arguments:\r
5847                 key - The key\r
5848                 value - The value\r
5849         */\r
5850 \r
5851         set: function(key, value){\r
5852                 if (!this.hasKey(key)) this.length++;\r
5853                 this.obj[key] = value;\r
5854                 return this;\r
5855         },\r
5856 \r
5857         setLength: function(){\r
5858                 this.length = 0;\r
5859                 for (var p in this.obj) this.length++;\r
5860                 return this;\r
5861         },\r
5862 \r
5863         /*\r
5864         Property: remove\r
5865                 Removes a key-value pair from the hash.\r
5866 \r
5867         Arguments:\r
5868                 key - The key\r
5869         */\r
5870 \r
5871         remove: function(key){\r
5872                 if (this.hasKey(key)){\r
5873                         delete this.obj[key];\r
5874                         this.length--;\r
5875                 }\r
5876                 return this;\r
5877         },\r
5878 \r
5879         /*\r
5880         Property: each\r
5881                 Calls a function for each key-value pair. The first argument passed to the function will be the value, the second one will be the key, like $each.\r
5882 \r
5883         Arguments:\r
5884                 fn - The function to call for each key-value pair\r
5885                 bind - Optional, the object that will be referred to as "this" in the function\r
5886         */\r
5887 \r
5888         each: function(fn, bind){\r
5889                 $each(this.obj, fn, bind);\r
5890         },\r
5891 \r
5892         /*\r
5893         Property: extend\r
5894                 Extends the current hash with an object containing key-value pairs. Values for duplicate keys will be replaced by the new ones.\r
5895 \r
5896         Arguments:\r
5897                 obj - An object containing key-value pairs\r
5898         */\r
5899 \r
5900         extend: function(obj){\r
5901                 $extend(this.obj, obj);\r
5902                 return this.setLength();\r
5903         },\r
5904 \r
5905         /*\r
5906         Property: merge\r
5907                 Merges the current hash with multiple objects.\r
5908         */\r
5909 \r
5910         merge: function(){\r
5911                 this.obj = $merge.apply(null, [this.obj].extend(arguments));\r
5912                 return this.setLength();\r
5913         },\r
5914 \r
5915         /*\r
5916         Property: empty\r
5917                 Empties all hash values properties and values.\r
5918         */\r
5919 \r
5920         empty: function(){\r
5921                 this.obj = {};\r
5922                 this.length = 0;\r
5923                 return this;\r
5924         },\r
5925 \r
5926         /*\r
5927         Property: keys\r
5928                 Returns an array containing all the keys, in the same order as the values returned by <Hash.values>.\r
5929 \r
5930         Returns:\r
5931                 An array containing all the keys of the hash\r
5932         */\r
5933 \r
5934         keys: function(){\r
5935                 var keys = [];\r
5936                 for (var property in this.obj) keys.push(property);\r
5937                 return keys;\r
5938         },\r
5939 \r
5940         /*\r
5941         Property: values\r
5942                 Returns an array containing all the values, in the same order as the keys returned by <Hash.keys>.\r
5943 \r
5944         Returns:\r
5945                 An array containing all the values of the hash\r
5946         */\r
5947 \r
5948         values: function(){\r
5949                 var values = [];\r
5950                 for (var property in this.obj) values.push(this.obj[property]);\r
5951                 return values;\r
5952         }\r
5953 \r
5954 });\r
5955 \r
5956 /* Section: Utility Functions */\r
5957 \r
5958 /*\r
5959 Function: $H\r
5960         Shortcut to create a Hash from an Object.\r
5961 */\r
5962 \r
5963 function $H(obj){\r
5964         return new Hash(obj);\r
5965 };
5966
5967 /*\r
5968 Script: Hash.Cookie.js\r
5969         Stores and loads an Hash as a cookie using Json format.\r
5970 */\r
5971 \r
5972 /*\r
5973 Class: Hash.Cookie\r
5974         Inherits all the methods from <Hash>, additional methods are save and load.\r
5975         Hash json string has a limit of 4kb (4096byte), so be careful with your Hash size.\r
5976         Creating a new instance automatically loads the data from the Cookie into the Hash.\r
5977         If the Hash is emptied, the cookie is also removed.\r
5978 \r
5979 Arguments:\r
5980         name - the key (name) for the cookie\r
5981         options - options are identical to <Cookie> and are simply passed along to it.\r
5982                 In addition, it has the autoSave option, to save the cookie at every operation. defaults to true.\r
5983 \r
5984 Example:\r
5985         (start code)\r
5986         var fruits = new Hash.Cookie('myCookieName', {duration: 3600});\r
5987         fruits.extend({\r
5988                 'lemon': 'yellow',\r
5989                 'apple': 'red'\r
5990         });\r
5991         fruits.set('melon', 'green');\r
5992         fruits.get('lemon'); // yellow\r
5993 \r
5994         // ... on another page ... values load automatically\r
5995 \r
5996         var fruits = new Hash.Cookie('myCookieName', {duration: 365});\r
5997         fruits.get('melon'); // green\r
5998 \r
5999         fruits.erase(); // delete cookie\r
6000         (end)\r
6001 */\r
6002 \r
6003 Hash.Cookie = Hash.extend({\r
6004 \r
6005         initialize: function(name, options){\r
6006                 this.name = name;\r
6007                 this.options = $extend({'autoSave': true}, options || {});\r
6008                 this.load();\r
6009         },\r
6010 \r
6011         /*\r
6012         Property: save\r
6013                 Saves the Hash to the cookie. If the hash is empty, removes the cookie.\r
6014 \r
6015         Returns:\r
6016                 Returns false when the JSON string cookie is too long (4kb), otherwise true.\r
6017 \r
6018         Example:\r
6019                 (start code)\r
6020                 var login = new Hash.Cookie('userstatus', {autoSave: false});\r
6021 \r
6022                 login.extend({\r
6023                         'username': 'John',\r
6024                         'credentials': [4, 7, 9]\r
6025                 });\r
6026                 login.set('last_message', 'User logged in!');\r
6027 \r
6028                 login.save(); // finally save the Hash\r
6029                 (end)\r
6030         */\r
6031 \r
6032         save: function(){\r
6033                 if (this.length == 0){\r
6034                         Cookie.remove(this.name, this.options);\r
6035                         return true;\r
6036                 }\r
6037                 var str = Json.toString(this.obj);\r
6038                 if (str.length > 4096) return false; //cookie would be truncated!\r
6039                 Cookie.set(this.name, str, this.options);\r
6040                 return true;\r
6041         },\r
6042         \r
6043         /*\r
6044         Property: load\r
6045                 Loads the cookie and assigns it to the Hash.\r
6046         */\r
6047 \r
6048         load: function(){\r
6049                 this.obj = Json.evaluate(Cookie.get(this.name), true) || {};\r
6050                 this.setLength();\r
6051         }\r
6052 \r
6053 });\r
6054 \r
6055 Hash.Cookie.Methods = {};\r
6056 ['extend', 'set', 'merge', 'empty', 'remove'].each(function(method){\r
6057         Hash.Cookie.Methods[method] = function(){\r
6058                 Hash.prototype[method].apply(this, arguments);\r
6059                 if (this.options.autoSave) this.save();\r
6060                 return this;\r
6061         };\r
6062 });\r
6063 Hash.Cookie.implement(Hash.Cookie.Methods);
6064
6065 /*
6066 Script: Color.js
6067         Contains the Color class.
6068
6069 License:
6070         MIT-style license.
6071 */
6072
6073 /*
6074 Class: Color
6075         Creates a new Color Object, which is an array with some color specific methods.
6076 Arguments:
6077         color - the hex, the RGB array or the HSB array of the color to create. For HSB colors, you need to specify the second argument.
6078         type - a string representing the type of the color to create. needs to be specified if you intend to create the color with HSB values, or an array of HEX values. Can be 'rgb', 'hsb' or 'hex'.
6079
6080 Example:
6081         (start code)
6082         var black = new Color('#000');
6083         var purple = new Color([255,0,255]);
6084         // mix black with white and purple, each time at 10% of the new color
6085         var darkpurple = black.mix('#fff', purple, 10);
6086         $('myDiv').setStyle('background-color', darkpurple);
6087         (end)
6088 */
6089
6090 var Color = new Class({
6091
6092         initialize: function(color, type){
6093                 type = type || (color.push ? 'rgb' : 'hex');
6094                 var rgb, hsb;
6095                 switch(type){
6096                         case 'rgb':
6097                                 rgb = color;
6098                                 hsb = rgb.rgbToHsb();
6099                                 break;
6100                         case 'hsb':
6101                                 rgb = color.hsbToRgb();
6102                                 hsb = color;
6103                                 break;
6104                         default:
6105                                 rgb = color.hexToRgb(true);
6106                                 hsb = rgb.rgbToHsb();
6107                 }
6108                 rgb.hsb = hsb;
6109                 rgb.hex = rgb.rgbToHex();
6110                 return $extend(rgb, Color.prototype);
6111         },
6112
6113         /*
6114         Property: mix
6115                 Mixes two or more colors with the Color.
6116                 
6117         Arguments:
6118                 color - a color to mix. you can use as arguments how many colors as you want to mix with the original one.
6119                 alpha - if you use a number as the last argument, it will be threated as the amount of the color to mix.
6120         */
6121
6122         mix: function(){
6123                 var colors = $A(arguments);
6124                 var alpha = ($type(colors[colors.length - 1]) == 'number') ? colors.pop() : 50;
6125                 var rgb = this.copy();
6126                 colors.each(function(color){
6127                         color = new Color(color);
6128                         for (var i = 0; i < 3; i++) rgb[i] = Math.round((rgb[i] / 100 * (100 - alpha)) + (color[i] / 100 * alpha));
6129                 });
6130                 return new Color(rgb, 'rgb');
6131         },
6132
6133         /*
6134         Property: invert
6135                 Inverts the Color.
6136         */
6137
6138         invert: function(){
6139                 return new Color(this.map(function(value){
6140                         return 255 - value;
6141                 }));
6142         },
6143
6144         /*
6145         Property: setHue
6146                 Modifies the hue of the Color, and returns a new one.
6147         
6148         Arguments:
6149                 value - the hue to set
6150         */
6151
6152         setHue: function(value){
6153                 return new Color([value, this.hsb[1], this.hsb[2]], 'hsb');
6154         },
6155
6156         /*
6157         Property: setSaturation
6158                 Changes the saturation of the Color, and returns a new one.
6159         
6160         Arguments:
6161                 percent - the percentage of the saturation to set
6162         */
6163
6164         setSaturation: function(percent){
6165                 return new Color([this.hsb[0], percent, this.hsb[2]], 'hsb');
6166         },
6167
6168         /*
6169         Property: setBrightness
6170                 Changes the brightness of the Color, and returns a new one.
6171         
6172         Arguments:
6173                 percent - the percentage of the brightness to set
6174         */
6175
6176         setBrightness: function(percent){
6177                 return new Color([this.hsb[0], this.hsb[1], percent], 'hsb');
6178         }
6179
6180 });
6181
6182 /* Section: Utility Functions */
6183
6184 /*
6185 Function: $RGB
6186         Shortcut to create a new color, based on red, green, blue values.
6187
6188 Arguments:
6189         r - (integer) red value (0-255)
6190         g - (integer) green value (0-255)
6191         b - (integer) blue value (0-255)
6192
6193 */
6194
6195 function $RGB(r, g, b){
6196         return new Color([r, g, b], 'rgb');
6197 };
6198
6199 /*
6200 Function: $HSB
6201         Shortcut to create a new color, based on hue, saturation, brightness values.
6202
6203 Arguments:
6204         h - (integer) hue value (0-100)
6205         s - (integer) saturation value (0-100)
6206         b - (integer) brightness value (0-100)
6207 */
6208
6209 function $HSB(h, s, b){
6210         return new Color([h, s, b], 'hsb');
6211 };
6212
6213 /*
6214 Class: Array
6215         A collection of The Array Object prototype methods.
6216 */
6217
6218 Array.extend({
6219         
6220         /*
6221         Property: rgbToHsb
6222                 Converts a RGB array to an HSB array.
6223
6224         Returns:
6225                 the HSB array.
6226         */
6227
6228         rgbToHsb: function(){
6229                 var red = this[0], green = this[1], blue = this[2];
6230                 var hue, saturation, brightness;
6231                 var max = Math.max(red, green, blue), min = Math.min(red, green, blue);
6232                 var delta = max - min;
6233                 brightness = max / 255;
6234                 saturation = (max != 0) ? delta / max : 0;
6235                 if (saturation == 0){
6236                         hue = 0;
6237                 } else {
6238                         var rr = (max - red) / delta;
6239                         var gr = (max - green) / delta;
6240                         var br = (max - blue) / delta;
6241                         if (red == max) hue = br - gr;
6242                         else if (green == max) hue = 2 + rr - br;
6243                         else hue = 4 + gr - rr;
6244                         hue /= 6;
6245                         if (hue < 0) hue++;
6246                 }
6247                 return [Math.round(hue * 360), Math.round(saturation * 100), Math.round(brightness * 100)];
6248         },
6249
6250         /*
6251         Property: hsbToRgb
6252                 Converts an HSB array to an RGB array.
6253
6254         Returns:
6255                 the RGB array.
6256         */
6257
6258         hsbToRgb: function(){
6259                 var br = Math.round(this[2] / 100 * 255);
6260                 if (this[1] == 0){
6261                         return [br, br, br];
6262                 } else {
6263                         var hue = this[0] % 360;
6264                         var f = hue % 60;
6265                         var p = Math.round((this[2] * (100 - this[1])) / 10000 * 255);
6266                         var q = Math.round((this[2] * (6000 - this[1] * f)) / 600000 * 255);
6267                         var t = Math.round((this[2] * (6000 - this[1] * (60 - f))) / 600000 * 255);
6268                         switch(Math.floor(hue / 60)){
6269                                 case 0: return [br, t, p];
6270                                 case 1: return [q, br, p];
6271                                 case 2: return [p, br, t];
6272                                 case 3: return [p, q, br];
6273                                 case 4: return [t, p, br];
6274                                 case 5: return [br, p, q];
6275                         }
6276                 }
6277                 return false;
6278         }
6279
6280 });
6281
6282 /*
6283 Script: Scroller.js
6284         Contains the <Scroller>.
6285
6286 License:
6287         MIT-style license.
6288 */
6289
6290 /*
6291 Class: Scroller
6292         The Scroller is a class to scroll any element with an overflow (including the window) when the mouse cursor reaches certain buondaries of that element.
6293         You must call its start method to start listening to mouse movements.
6294
6295 Note:
6296         The Scroller requires an XHTML doctype.
6297
6298 Arguments:
6299         element - required, the element to scroll.
6300         options - optional, see options below, and <Fx.Base> options.
6301
6302 Options:
6303         area - integer, the necessary boundaries to make the element scroll.
6304         velocity - integer, velocity ratio, the modifier for the window scrolling speed.
6305
6306 Events:
6307         onChange - optionally, when the mouse reaches some boundaries, you can choose to alter some other values, instead of the scrolling offsets.
6308                 Automatically passes as parameters x and y values.
6309 */
6310
6311 var Scroller = new Class({
6312
6313         options: {
6314                 area: 20,
6315                 velocity: 1,
6316                 onChange: function(x, y){
6317                         this.element.scrollTo(x, y);
6318                 }
6319         },
6320
6321         initialize: function(element, options){
6322                 this.setOptions(options);
6323                 this.element = $(element);
6324                 this.mousemover = ([window, document].contains(element)) ? $(document.body) : this.element;
6325         },
6326
6327         /*
6328         Property: start
6329                 The scroller starts listening to mouse movements.
6330         */
6331
6332         start: function(){
6333                 this.coord = this.getCoords.bindWithEvent(this);
6334                 this.mousemover.addListener('mousemove', this.coord);
6335         },
6336
6337         /*
6338         Property: stop
6339                 The scroller stops listening to mouse movements.
6340         */
6341
6342         stop: function(){
6343                 this.mousemover.removeListener('mousemove', this.coord);
6344                 this.timer = $clear(this.timer);
6345         },
6346
6347         getCoords: function(event){
6348                 this.page = (this.element == window) ? event.client : event.page;
6349                 if (!this.timer) this.timer = this.scroll.periodical(50, this);
6350         },
6351
6352         scroll: function(){
6353                 var el = this.element.getSize();
6354                 var pos = this.element.getPosition();
6355
6356                 var change = {'x': 0, 'y': 0};
6357                 for (var z in this.page){
6358                         if (this.page[z] < (this.options.area + pos[z]) && el.scroll[z] != 0)
6359                                 change[z] = (this.page[z] - this.options.area - pos[z]) * this.options.velocity;
6360                         else if (this.page[z] + this.options.area > (el.size[z] + pos[z]) && el.scroll[z] + el.size[z] != el.scrollSize[z])
6361                                 change[z] = (this.page[z] - el.size[z] + this.options.area - pos[z]) * this.options.velocity;
6362                 }
6363                 if (change.y || change.x) this.fireEvent('onChange', [el.scroll.x + change.x, el.scroll.y + change.y]);
6364         }
6365
6366 });
6367
6368 Scroller.implement(new Events, new Options);
6369
6370 /*
6371 Script: Slider.js
6372         Contains <Slider>
6373
6374 License:
6375         MIT-style license.
6376 */
6377
6378 /*
6379 Class: Slider
6380         Creates a slider with two elements: a knob and a container. Returns the values.
6381         
6382 Note:
6383         The Slider requires an XHTML doctype.
6384
6385 Arguments:
6386         element - the knob container
6387         knob - the handle
6388         options - see Options below
6389
6390 Options:
6391         steps - the number of steps for your slider.
6392         mode - either 'horizontal' or 'vertical'. defaults to horizontal.
6393         offset - relative offset for knob position. default to 0.
6394         
6395 Events:
6396         onChange - a function to fire when the value changes.
6397         onComplete - a function to fire when you're done dragging.
6398         onTick - optionally, you can alter the onTick behavior, for example displaying an effect of the knob moving to the desired position.
6399                 Passes as parameter the new position.
6400 */
6401
6402 var Slider = new Class({
6403
6404         options: {
6405                 onChange: Class.empty,
6406                 onComplete: Class.empty,
6407                 onTick: function(pos){
6408                         this.knob.setStyle(this.p, pos);
6409                 },
6410                 mode: 'horizontal',
6411                 steps: 100,
6412                 offset: 0
6413         },
6414
6415         initialize: function(el, knob, options){
6416                 this.element = $(el);
6417                 this.knob = $(knob);
6418                 this.setOptions(options);
6419                 this.previousChange = -1;
6420                 this.previousEnd = -1;
6421                 this.step = -1;
6422                 this.element.addEvent('mousedown', this.clickedElement.bindWithEvent(this));
6423                 var mod, offset;
6424                 switch(this.options.mode){
6425                         case 'horizontal':
6426                                 this.z = 'x';
6427                                 this.p = 'left';
6428                                 mod = {'x': 'left', 'y': false};
6429                                 offset = 'offsetWidth';
6430                                 break;
6431                         case 'vertical':
6432                                 this.z = 'y';
6433                                 this.p = 'top';
6434                                 mod = {'x': false, 'y': 'top'};
6435                                 offset = 'offsetHeight';
6436                 }
6437                 this.max = this.element[offset] - this.knob[offset] + (this.options.offset * 2);
6438                 this.half = this.knob[offset]/2;
6439                 this.getPos = this.element['get' + this.p.capitalize()].bind(this.element);
6440                 this.knob.setStyle('position', 'relative').setStyle(this.p, - this.options.offset);
6441                 var lim = {};
6442                 lim[this.z] = [- this.options.offset, this.max - this.options.offset];
6443                 this.drag = new Drag.Base(this.knob, {
6444                         limit: lim,
6445                         modifiers: mod,
6446                         snap: 0,
6447                         onStart: function(){
6448                                 this.draggedKnob();
6449                         }.bind(this),
6450                         onDrag: function(){
6451                                 this.draggedKnob();
6452                         }.bind(this),
6453                         onComplete: function(){
6454                                 this.draggedKnob();
6455                                 this.end();
6456                         }.bind(this)
6457                 });
6458                 if (this.options.initialize) this.options.initialize.call(this);
6459         },
6460
6461         /*
6462         Property: set
6463                 The slider will get the step you pass.
6464
6465         Arguments:
6466                 step - one integer
6467         */
6468
6469         set: function(step){
6470                 this.step = step.limit(0, this.options.steps);
6471                 this.checkStep();
6472                 this.end();
6473                 this.fireEvent('onTick', this.toPosition(this.step));
6474                 return this;
6475         },
6476
6477         clickedElement: function(event){
6478                 var position = event.page[this.z] - this.getPos() - this.half;
6479                 position = position.limit(-this.options.offset, this.max -this.options.offset);
6480                 this.step = this.toStep(position);
6481                 this.checkStep();
6482                 this.end();
6483                 this.fireEvent('onTick', position);
6484         },
6485
6486         draggedKnob: function(){
6487                 this.step = this.toStep(this.drag.value.now[this.z]);
6488                 this.checkStep();
6489         },
6490
6491         checkStep: function(){
6492                 if (this.previousChange != this.step){
6493                         this.previousChange = this.step;
6494                         this.fireEvent('onChange', this.step);
6495                 }
6496         },
6497
6498         end: function(){
6499                 if (this.previousEnd !== this.step){
6500                         this.previousEnd = this.step;
6501                         this.fireEvent('onComplete', this.step + '');
6502                 }
6503         },
6504
6505         toStep: function(position){
6506                 return Math.round((position + this.options.offset) / this.max * this.options.steps);
6507         },
6508
6509         toPosition: function(step){
6510                 return this.max * step / this.options.steps;
6511         }
6512
6513 });
6514
6515 Slider.implement(new Events);
6516 Slider.implement(new Options);
6517
6518 /*
6519 Script: SmoothScroll.js
6520         Contains <SmoothScroll>
6521
6522 License:
6523         MIT-style license.
6524 */
6525
6526 /*
6527 Class: SmoothScroll
6528         Auto targets all the anchors in a page and display a smooth scrolling effect upon clicking them.
6529         Inherits methods, properties, options and events from <Fx.Scroll>.
6530
6531 Note:
6532         SmoothScroll requires an XHTML doctype.
6533
6534 Arguments:
6535         options - the Fx.Scroll options (see: <Fx.Scroll>) plus links, a collection of elements you want your smoothscroll on. Defaults to document.links.
6536
6537 Example:
6538         >new SmoothScroll();
6539 */
6540
6541 var SmoothScroll = Fx.Scroll.extend({
6542
6543         initialize: function(options){
6544                 this.parent(window, options);
6545                 this.links = (this.options.links) ? $$(this.options.links) : $$(document.links);
6546                 var location = window.location.href.match(/^[^#]*/)[0] + '#';
6547                 this.links.each(function(link){
6548                         if (link.href.indexOf(location) != 0) return;
6549                         var anchor = link.href.substr(location.length);
6550                         if (anchor && $(anchor)) this.useLink(link, anchor);
6551                 }, this);
6552                 if (!window.webkit419) this.addEvent('onComplete', function(){
6553                         window.location.hash = this.anchor;
6554                 });
6555         },
6556
6557         useLink: function(link, anchor){
6558                 link.addEvent('click', function(event){
6559                         this.anchor = anchor;
6560                         this.toElement(anchor);
6561                         event.stop();
6562                 }.bindWithEvent(this));
6563         }
6564
6565 });
6566
6567 /*
6568 Script: Sortables.js
6569         Contains <Sortables> Class.
6570
6571 License:
6572         MIT-style license.
6573 */
6574
6575 /*
6576 Class: Sortables
6577         Creates an interface for <Drag.Base> and drop, resorting of a list.
6578
6579 Note:
6580         The Sortables require an XHTML doctype.
6581
6582 Arguments:
6583         list - required, the list that will become sortable.
6584         options - an Object, see options below.
6585
6586 Options:
6587         handles - a collection of elements to be used for drag handles. defaults to the elements.
6588         
6589 Events:
6590         onStart - function executed when the item starts dragging
6591         onComplete - function executed when the item ends dragging
6592 */
6593
6594 var Sortables = new Class({
6595
6596         options: {
6597                 handles: false,
6598                 onStart: Class.empty,
6599                 onComplete: Class.empty,
6600                 ghost: true,
6601                 snap: 3,
6602                 onDragStart: function(element, ghost){
6603                         ghost.setStyle('opacity', 0.7);
6604                         element.setStyle('opacity', 0.7);
6605                 },
6606                 onDragComplete: function(element, ghost){
6607                         element.setStyle('opacity', 1);
6608                         ghost.remove();
6609                         this.trash.remove();
6610                 }
6611         },
6612
6613         initialize: function(list, options){
6614                 this.setOptions(options);
6615                 this.list = $(list);
6616                 this.elements = this.list.getChildren();
6617                 this.handles = (this.options.handles) ? $$(this.options.handles) : this.elements;
6618                 this.bound = {
6619                         'start': [],
6620                         'moveGhost': this.moveGhost.bindWithEvent(this)
6621                 };
6622                 for (var i = 0, l = this.handles.length; i < l; i++){
6623                         this.bound.start[i] = this.start.bindWithEvent(this, this.elements[i]);
6624                 }
6625                 this.attach();
6626                 if (this.options.initialize) this.options.initialize.call(this);
6627                 this.bound.move = this.move.bindWithEvent(this);
6628                 this.bound.end = this.end.bind(this);
6629         },
6630
6631         attach: function(){
6632                 this.handles.each(function(handle, i){
6633                         handle.addEvent('mousedown', this.bound.start[i]);
6634                 }, this);
6635         },
6636
6637         detach: function(){
6638                 this.handles.each(function(handle, i){
6639                         handle.removeEvent('mousedown', this.bound.start[i]);
6640                 }, this);
6641         },
6642
6643         start: function(event, el){
6644                 this.active = el;
6645                 this.coordinates = this.list.getCoordinates();
6646                 if (this.options.ghost){
6647                         var position = el.getPosition();
6648                         this.offset = event.page.y - position.y;
6649                         this.trash = new Element('div').inject(document.body);
6650                         this.ghost = el.clone().inject(this.trash).setStyles({
6651                                 'position': 'absolute',
6652                                 'left': position.x,
6653                                 'top': event.page.y - this.offset
6654                         });
6655                         document.addListener('mousemove', this.bound.moveGhost);
6656                         this.fireEvent('onDragStart', [el, this.ghost]);
6657                 }
6658                 document.addListener('mousemove', this.bound.move);
6659                 document.addListener('mouseup', this.bound.end);
6660                 this.fireEvent('onStart', el);
6661                 event.stop();
6662         },
6663
6664         moveGhost: function(event){
6665                 var value = event.page.y - this.offset;
6666                 value = value.limit(this.coordinates.top, this.coordinates.bottom - this.ghost.offsetHeight);
6667                 this.ghost.setStyle('top', value);
6668                 event.stop();
6669         },
6670
6671         move: function(event){
6672                 var now = event.page.y;
6673                 this.previous = this.previous || now;
6674                 var up = ((this.previous - now) > 0);
6675                 var prev = this.active.getPrevious();
6676                 var next = this.active.getNext();
6677                 if (prev && up && now < prev.getCoordinates().bottom) this.active.injectBefore(prev);
6678                 if (next && !up && now > next.getCoordinates().top) this.active.injectAfter(next);
6679                 this.previous = now;
6680         },
6681
6682         serialize: function(converter){
6683                 return this.list.getChildren().map(converter || function(el){
6684                         return this.elements.indexOf(el);
6685                 }, this);
6686         },
6687
6688         end: function(){
6689                 this.previous = null;
6690                 document.removeListener('mousemove', this.bound.move);
6691                 document.removeListener('mouseup', this.bound.end);
6692                 if (this.options.ghost){
6693                         document.removeListener('mousemove', this.bound.moveGhost);
6694                         this.fireEvent('onDragComplete', [this.active, this.ghost]);
6695                 }
6696                 this.fireEvent('onComplete', this.active);
6697         }
6698
6699 });
6700
6701 Sortables.implement(new Events, new Options);
6702
6703 /*
6704 Script: Tips.js
6705         Tooltips, BubbleTips, whatever they are, they will appear on mouseover
6706
6707 License:
6708         MIT-style license.
6709
6710 Credits:
6711         The idea behind Tips.js is based on Bubble Tooltips (<http://web-graphics.com/mtarchive/001717.php>) by Alessandro Fulcitiniti <http://web-graphics.com>
6712 */
6713
6714 /*
6715 Class: Tips
6716         Display a tip on any element with a title and/or href.
6717
6718 Note:
6719         Tips requires an XHTML doctype.
6720
6721 Arguments:
6722         elements - a collection of elements to apply the tooltips to on mouseover.
6723         options - an object. See options Below.
6724
6725 Options:
6726         maxTitleChars - the maximum number of characters to display in the title of the tip. defaults to 30.
6727         showDelay - the delay the onShow method is called. (defaults to 100 ms)
6728         hideDelay - the delay the onHide method is called. (defaults to 100 ms)
6729
6730         className - the prefix for your tooltip classNames. defaults to 'tool'.
6731
6732                 the whole tooltip will have as classname: tool-tip
6733
6734                 the title will have as classname: tool-title
6735
6736                 the text will have as classname: tool-text
6737
6738         offsets - the distance of your tooltip from the mouse. an Object with x/y properties.
6739         fixed - if set to true, the toolTip will not follow the mouse.
6740         
6741 Events:
6742         onShow - optionally you can alter the default onShow behaviour with this option (like displaying a fade in effect);
6743         onHide - optionally you can alter the default onHide behaviour with this option (like displaying a fade out effect);
6744
6745 Example:
6746         (start code)
6747         <img src="/images/i.png" title="The body of the tooltip is stored in the title" class="toolTipImg"/>
6748         <script>
6749                 var myTips = new Tips($$('.toolTipImg'), {
6750                         maxTitleChars: 50       //I like my captions a little long
6751                 });
6752         </script>
6753         (end)
6754
6755 Note:
6756         The title of the element will always be used as the tooltip body. If you put :: on your title, the text before :: will become the tooltip title.
6757 */
6758
6759 var Tips = new Class({
6760
6761         options: {
6762                 onShow: function(tip){
6763                         tip.setStyle('visibility', 'visible');
6764                 },
6765                 onHide: function(tip){
6766                         tip.setStyle('visibility', 'hidden');
6767                 },
6768                 maxTitleChars: 30,
6769                 showDelay: 100,
6770                 hideDelay: 100,
6771                 className: 'tool',
6772                 offsets: {'x': 16, 'y': 16},
6773                 fixed: false
6774         },
6775
6776         initialize: function(elements, options){
6777                 this.setOptions(options);
6778                 this.toolTip = new Element('div', {
6779                         'class': this.options.className + '-tip',
6780                         'styles': {
6781                                 'position': 'absolute',
6782                                 'top': '0',
6783                                 'left': '0',
6784                                 'visibility': 'hidden'
6785                         }
6786                 }).inject(document.body);
6787                 this.wrapper = new Element('div').inject(this.toolTip);
6788                 $$(elements).each(this.build, this);
6789                 if (this.options.initialize) this.options.initialize.call(this);
6790         },
6791
6792         build: function(el){
6793                 el.$tmp.myTitle = (el.href && el.getTag() == 'a') ? el.href.replace('http://', '') : (el.rel || false);
6794                 if (el.title){
6795                         var dual = el.title.split('::');
6796                         if (dual.length > 1){
6797                                 el.$tmp.myTitle = dual[0].trim();
6798                                 el.$tmp.myText = dual[1].trim();
6799                         } else {
6800                                 el.$tmp.myText = el.title;
6801                         }
6802                         el.removeAttribute('title');
6803                 } else {
6804                         el.$tmp.myText = false;
6805                 }
6806                 if (el.$tmp.myTitle && el.$tmp.myTitle.length > this.options.maxTitleChars) el.$tmp.myTitle = el.$tmp.myTitle.substr(0, this.options.maxTitleChars - 1) + "&hellip;";
6807                 el.addEvent('mouseenter', function(event){
6808                         this.start(el);
6809                         if (!this.options.fixed) this.locate(event);
6810                         else this.position(el);
6811                 }.bind(this));
6812                 if (!this.options.fixed) el.addEvent('mousemove', this.locate.bindWithEvent(this));
6813                 var end = this.end.bind(this);
6814                 el.addEvent('mouseleave', end);
6815                 el.addEvent('trash', end);
6816         },
6817
6818         start: function(el){
6819                 this.wrapper.empty();
6820                 if (el.$tmp.myTitle){
6821                         this.title = new Element('span').inject(new Element('div', {'class': this.options.className + '-title'}).inject(this.wrapper)).setHTML(el.$tmp.myTitle);
6822                 }
6823                 if (el.$tmp.myText){
6824                         this.text = new Element('span').inject(new Element('div', {'class': this.options.className + '-text'}).inject(this.wrapper)).setHTML(el.$tmp.myText);
6825                 }
6826                 $clear(this.timer);
6827                 this.timer = this.show.delay(this.options.showDelay, this);
6828         },
6829
6830         end: function(event){
6831                 $clear(this.timer);
6832                 this.timer = this.hide.delay(this.options.hideDelay, this);
6833         },
6834
6835         position: function(element){
6836                 var pos = element.getPosition();
6837                 this.toolTip.setStyles({
6838                         'left': pos.x + this.options.offsets.x,
6839                         'top': pos.y + this.options.offsets.y
6840                 });
6841         },
6842
6843         locate: function(event){
6844                 var win = {'x': window.getWidth(), 'y': window.getHeight()};
6845                 var scroll = {'x': window.getScrollLeft(), 'y': window.getScrollTop()};
6846                 var tip = {'x': this.toolTip.offsetWidth, 'y': this.toolTip.offsetHeight};
6847                 var prop = {'x': 'left', 'y': 'top'};
6848                 for (var z in prop){
6849                         var pos = event.page[z] + this.options.offsets[z];
6850                         if ((pos + tip[z] - scroll[z]) > win[z]) pos = event.page[z] - this.options.offsets[z] - tip[z];
6851                         this.toolTip.setStyle(prop[z], pos);
6852                 };
6853         },
6854
6855         show: function(){
6856                 if (this.options.timeout) this.timer = this.hide.delay(this.options.timeout, this);
6857                 this.fireEvent('onShow', [this.toolTip]);
6858         },
6859
6860         hide: function(){
6861                 this.fireEvent('onHide', [this.toolTip]);
6862         }
6863
6864 });
6865
6866 Tips.implement(new Events, new Options);
6867
6868 /*
6869 Script: Group.js
6870         For Grouping Classes or Elements Events. The Event added to the Group will fire when all of the events of the items of the group are fired.
6871
6872 License:
6873         MIT-style license.
6874 */
6875
6876 /*
6877 Class: Group
6878         An "Utility" Class.
6879
6880 Arguments:
6881         List of Class instances
6882
6883 Example:
6884         (start code)
6885         xhr1 = new Ajax('data.js', {evalScript: true});
6886         xhr2 = new Ajax('abstraction.js', {evalScript: true});
6887         xhr3 = new Ajax('template.js', {evalScript: true});
6888
6889         var group = new Group(xhr1, xhr2, xhr3);
6890         group.addEvent('onComplete', function(){
6891                 alert('All Scripts loaded');
6892         });
6893
6894         xhr1.request();
6895         xhr2.request();
6896         xhr3.request();
6897         (end)
6898
6899 */
6900
6901 var Group = new Class({
6902
6903         initialize: function(){
6904                 this.instances = $A(arguments);
6905                 this.events = {};
6906                 this.checker = {};
6907         },
6908
6909         /*
6910         Property: addEvent
6911                 adds an event to the stack of events of the Class instances.
6912
6913         Arguments:
6914                 type - string; the event name (e.g. 'onComplete')
6915                 fn - function to execute when all instances fired this event
6916         */
6917
6918         addEvent: function(type, fn){
6919                 this.checker[type] = this.checker[type] || {};
6920                 this.events[type] = this.events[type] || [];
6921                 if (this.events[type].contains(fn)) return false;
6922                 else this.events[type].push(fn);
6923                 this.instances.each(function(instance, i){
6924                         instance.addEvent(type, this.check.bind(this, [type, instance, i]));
6925                 }, this);
6926                 return this;
6927         },
6928
6929         check: function(type, instance, i){
6930                 this.checker[type][i] = true;
6931                 var every = this.instances.every(function(current, j){
6932                         return this.checker[type][j] || false;
6933                 }, this);
6934                 if (!every) return;
6935                 this.checker[type] = {};
6936                 this.events[type].each(function(event){
6937                         event.call(this, this.instances, instance);
6938                 }, this);
6939         }
6940
6941 });
6942
6943 /*\r
6944 Script: Accordion.js\r
6945         Contains <Accordion>\r
6946 \r
6947 License:\r
6948         MIT-style license.\r
6949 */\r
6950 \r
6951 /*\r
6952 Class: Accordion\r
6953         The Accordion class creates a group of elements that are toggled when their handles are clicked. When one elements toggles in, the others toggles back.\r
6954         Inherits methods, properties, options and events from <Fx.Elements>.\r
6955         \r
6956 Note:\r
6957         The Accordion requires an XHTML doctype.\r
6958 \r
6959 Arguments:\r
6960         togglers - required, a collection of elements, the elements handlers that will be clickable.\r
6961         elements - required, a collection of elements the transitions will be applied to.\r
6962         options - optional, see options below, and <Fx.Base> options and events.\r
6963 \r
6964 Options:\r
6965         show - integer, the Index of the element to show at start.\r
6966         display - integer, the Index of the element to show at start (with a transition). defaults to 0.\r
6967         fixedHeight - integer, if you want the elements to have a fixed height. defaults to false.\r
6968         fixedWidth - integer, if you want the elements to have a fixed width. defaults to false.\r
6969         height - boolean, will add a height transition to the accordion if true. defaults to true.\r
6970         opacity - boolean, will add an opacity transition to the accordion if true. defaults to true.\r
6971         width - boolean, will add a width transition to the accordion if true. defaults to false, css mastery is required to make this work!\r
6972         alwaysHide - boolean, will allow to hide all elements if true, instead of always keeping one element shown. defaults to false.\r
6973         \r
6974 Events:\r
6975         onActive - function to execute when an element starts to show\r
6976         onBackground - function to execute when an element starts to hide\r
6977 */\r
6978 \r
6979 var Accordion = Fx.Elements.extend({\r
6980 \r
6981         options: {\r
6982                 onActive: Class.empty,\r
6983                 onBackground: Class.empty,\r
6984                 display: 0,\r
6985                 show: false,\r
6986                 height: true,\r
6987                 width: false,\r
6988                 opacity: true,\r
6989                 fixedHeight: false,\r
6990                 fixedWidth: false,\r
6991                 wait: false,\r
6992                 alwaysHide: false\r
6993         },\r
6994 \r
6995         initialize: function(){\r
6996                 var options, togglers, elements, container;\r
6997                 $each(arguments, function(argument, i){\r
6998                         switch($type(argument)){\r
6999                                 case 'object': options = argument; break;\r
7000                                 case 'element': container = $(argument); break;\r
7001                                 default:\r
7002                                         var temp = $$(argument);\r
7003                                         if (!togglers) togglers = temp;\r
7004                                         else elements = temp;\r
7005                         }\r
7006                 });\r
7007                 this.togglers = togglers || [];\r
7008                 this.elements = elements || [];\r
7009                 this.container = $(container);\r
7010                 this.setOptions(options);\r
7011                 this.previous = -1;\r
7012                 if (this.options.alwaysHide) this.options.wait = true;\r
7013                 if ($chk(this.options.show)){\r
7014                         this.options.display = false;\r
7015                         this.previous = this.options.show;\r
7016                 }\r
7017                 if (this.options.start){\r
7018                         this.options.display = false;\r
7019                         this.options.show = false;\r
7020                 }\r
7021                 this.effects = {};\r
7022                 if (this.options.opacity) this.effects.opacity = 'fullOpacity';\r
7023                 if (this.options.width) this.effects.width = this.options.fixedWidth ? 'fullWidth' : 'offsetWidth';\r
7024                 if (this.options.height) this.effects.height = this.options.fixedHeight ? 'fullHeight' : 'scrollHeight';\r
7025                 for (var i = 0, l = this.togglers.length; i < l; i++) this.addSection(this.togglers[i], this.elements[i]);\r
7026                 this.elements.each(function(el, i){\r
7027                         if (this.options.show === i){\r
7028                                 this.fireEvent('onActive', [this.togglers[i], el]);\r
7029                         } else {\r
7030                                 for (var fx in this.effects) el.setStyle(fx, 0);\r
7031                         }\r
7032                 }, this);\r
7033                 this.parent(this.elements);\r
7034                 if ($chk(this.options.display)) this.display(this.options.display);\r
7035         },\r
7036 \r
7037         /*\r
7038         Property: addSection\r
7039                 Dynamically adds a new section into the accordion at the specified position.\r
7040 \r
7041         Arguments:\r
7042                 toggler - (dom element) the element that toggles the accordion section open.\r
7043                 element - (dom element) the element that stretches open when the toggler is clicked.\r
7044                 pos - (integer) the index where these objects are to be inserted within the accordion.\r
7045         */\r
7046 \r
7047         addSection: function(toggler, element, pos){\r
7048                 toggler = $(toggler);\r
7049                 element = $(element);\r
7050                 var test = this.togglers.contains(toggler);\r
7051                 var len = this.togglers.length;\r
7052                 this.togglers.include(toggler);\r
7053                 this.elements.include(element);\r
7054                 if (len && (!test || pos)){\r
7055                         pos = $pick(pos, len - 1);\r
7056                         toggler.injectBefore(this.togglers[pos]);\r
7057                         element.injectAfter(toggler);\r
7058                 } else if (this.container && !test){\r
7059                         toggler.inject(this.container);\r
7060                         element.inject(this.container);\r
7061                 }\r
7062                 var idx = this.togglers.indexOf(toggler);\r
7063                 toggler.addEvent('click', this.display.bind(this, idx));\r
7064                 if (this.options.height) element.setStyles({'padding-top': 0, 'border-top': 'none', 'padding-bottom': 0, 'border-bottom': 'none'});\r
7065                 if (this.options.width) element.setStyles({'padding-left': 0, 'border-left': 'none', 'padding-right': 0, 'border-right': 'none'});\r
7066                 element.fullOpacity = 1;\r
7067                 if (this.options.fixedWidth) element.fullWidth = this.options.fixedWidth;\r
7068                 if (this.options.fixedHeight) element.fullHeight = this.options.fixedHeight;\r
7069                 element.setStyle('overflow', 'hidden');\r
7070                 if (!test){\r
7071                         for (var fx in this.effects) element.setStyle(fx, 0);\r
7072                 }\r
7073                 return this;\r
7074         },\r
7075 \r
7076         /*\r
7077         Property: display\r
7078                 Shows a specific section and hides all others. Useful when triggering an accordion from outside.\r
7079 \r
7080         Arguments:\r
7081                 index - integer, the index of the item to show, or the actual element to show.\r
7082         */\r
7083 \r
7084         display: function(index){\r
7085                 index = ($type(index) == 'element') ? this.elements.indexOf(index) : index;\r
7086                 if ((this.timer && this.options.wait) || (index === this.previous && !this.options.alwaysHide)) return this;\r
7087                 this.previous = index;\r
7088                 var obj = {};\r
7089                 this.elements.each(function(el, i){\r
7090                         obj[i] = {};\r
7091                         var hide = (i != index) || (this.options.alwaysHide && (el.offsetHeight > 0));\r
7092                         this.fireEvent(hide ? 'onBackground' : 'onActive', [this.togglers[i], el]);\r
7093                         for (var fx in this.effects) obj[i][fx] = hide ? 0 : el[this.effects[fx]];\r
7094                 }, this);\r
7095                 return this.start(obj);\r
7096         },\r
7097 \r
7098         showThisHideOpen: function(index){return this.display(index);}\r
7099 \r
7100 });\r
7101 \r
7102 Fx.Accordion = Accordion;