initial commit
[emacs-init.git] / nxhtml / nxhtml / doc / js / smoothgallery / scripts / mootools.uncompressed.js
1 /*
2 Script: Moo.js
3         My Object Oriented javascript.
4
5 Author:
6         Valerio Proietti, <http://mad4milk.net>
7
8 License:
9         MIT-style license.
10
11 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 based on 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 /*
18 Class: Class
19         The base class object of the <http://mootools.net> framework.
20
21 Arguments:
22         properties - the collection of properties that apply to the class. Creates a new class, its initialize method will fire upon class instantiation.
23
24 Example:
25         (start code)
26         var Cat = new Class({
27                 initialize: function(name){
28                         this.name = name;
29                 }
30         });
31         var myCat = new Cat('Micia');
32         alert myCat.name; //alerts 'Micia'
33         (end)
34 */
35
36 var Class = function(properties){
37         var klass = function(){
38                 if (this.initialize && arguments[0] != 'noinit') return this.initialize.apply(this, arguments);
39                 else return this;
40         };
41         for (var property in this) klass[property] = this[property];
42         klass.prototype = properties;
43         return klass;
44 };
45
46 /*
47 Property: empty
48         Returns an empty function
49 */
50
51 Class.empty = function(){};
52
53 Class.prototype = {
54
55         /*
56         Property: extend
57                 Returns the copy of the Class extended with the passed in properties.
58
59         Arguments:
60                 properties - the properties to add to the base class in this new Class.
61
62         Example:
63                 (start code)
64                 var Animal = new Class({
65                         initialize: function(age){
66                                 this.age = age;
67                         }
68                 });
69                 var Cat = Animal.extend({
70                         initialize: function(name, age){
71                                 this.parent(age); //will call the previous initialize;
72                                 this.name = name;
73                         }
74                 });
75                 var myCat = new Cat('Micia', 20);
76                 alert myCat.name; //alerts 'Micia'
77                 alert myCat.age; //alerts 20
78                 (end)
79         */
80
81         extend: function(properties){
82                 var pr0t0typ3 = new this('noinit');
83
84                 var parentize = function(previous, current){
85                         if (!previous.apply || !current.apply) return false;
86                         return function(){
87                                 this.parent = previous;
88                                 return current.apply(this, arguments);
89                         };
90                 };
91
92                 for (var property in properties){
93                         var previous = pr0t0typ3[property];
94                         var current = properties[property];
95                         if (previous && previous != current) current = parentize(previous, current) || current;
96                         pr0t0typ3[property] = current;
97                 }
98                 return new Class(pr0t0typ3);
99         },
100
101         /*
102         Property: implement
103                 Implements the passed in properties to the base Class prototypes, altering the base class, unlike <Class.extend>.
104
105         Arguments:
106                 properties - the properties to add to the base class.
107
108         Example:
109                 (start code)
110                 var Animal = new Class({
111                         initialize: function(age){
112                                 this.age = age;
113                         }
114                 });
115                 Animal.implement({
116                         setName: function(name){
117                                 this.name = name
118                         }
119                 });
120                 var myAnimal = new Animal(20);
121                 myAnimal.setName('Micia');
122                 alert(myAnimal.name); //alerts 'Micia'
123                 (end)
124         */
125
126         implement: function(properties){
127                 for (var property in properties) this.prototype[property] = properties[property];
128         }
129
130 };
131
132 /* Section: Object related Functions */
133
134 /*
135 Function: Object.extend
136         Copies all the properties from the second passed object to the first passed Object.
137         If you do myWhatever.extend = Object.extend the first parameter will become myWhatever, and your extend function will only need one parameter.
138
139 Example:
140         (start code)
141         var firstOb = {
142                 'name': 'John',
143                 'lastName': 'Doe'
144         };
145         var secondOb = {
146                 'age': '20',
147                 'sex': 'male',
148                 'lastName': 'Dorian'
149         };
150         Object.extend(firstOb, secondOb);
151         //firstOb will become: 
152         {
153                 'name': 'John',
154                 'lastName': 'Dorian',
155                 'age': '20',
156                 'sex': 'male'
157         };
158         (end)
159
160 Returns:
161         The first object, extended.
162 */
163
164 Object.extend = function(){
165         var args = arguments;
166         args = (args[1]) ? [args[0], args[1]] : [this, args[0]];
167         for (var property in args[1]) args[0][property] = args[1][property];
168         return args[0];
169 };
170
171 /*
172 Function: Object.Native
173         Will add a .extend method to the objects passed as a parameter, equivalent to <Class.implement>
174
175 Arguments:
176         a number of classes/native javascript objects
177
178 */
179
180 Object.Native = function(){
181         for (var i = 0; i < arguments.length; i++) arguments[i].extend = Class.prototype.implement;
182 };
183
184 new Object.Native(Function, Array, String, Number, Class);
185
186 /*
187 Script: Utility.js
188         Contains Utility functions
189
190 Author:
191         Valerio Proietti, <http://mad4milk.net>
192
193 License:
194         MIT-style license.
195 */
196
197 //htmlelement mapping
198
199 if (typeof HTMLElement == 'undefined'){
200         var HTMLElement = Class.empty;
201         HTMLElement.prototype = {};
202 }
203
204 /*
205 Function: $type
206         Returns the type of object that matches the element passed in.
207
208 Arguments:
209         obj - the object to inspect.
210
211 Example:
212         >var myString = 'hello';
213         >$type(myString); //returns "string"
214
215 Returns:
216         'element' - if obj is a DOM element node
217         'textnode' - if obj is a DOM text node
218         'whitespace' - if obj is a DOM whitespace node
219         'array' - if obj is an array
220         'object' - if obj is an object
221         'string' - if obj is a string
222         'number' - if obj is a number
223         'boolean' - if obj is a boolean
224         'function' - if obj is a function
225         false - (boolean) if the object is not defined or none of the above.
226 */
227
228 function $type(obj){
229         if (obj === null || obj === undefined) return false;
230         var type = typeof obj;
231         if (type == 'object'){
232                 if (obj instanceof HTMLElement) return 'element';
233                 if (obj instanceof Array) return 'array';
234                 if (obj.nodeName){
235                         switch (obj.nodeType){
236                                 case 1: return 'element';
237                                 case 3: return obj.nodeValue.test('\\S') ? 'textnode' : 'whitespace';
238                         }
239                 }
240         }
241         return type;
242 };
243
244 /*
245 Function: $chk
246         Returns true if the passed in value/object exists or is 0, otherwise returns false.
247         Useful to accept zeroes.
248 */
249
250 function $chk(obj){
251         return !!(obj || obj === 0);
252 };
253
254 /*
255 Function: $pick
256         Returns the first object if defined, otherwise returns the second.
257 */
258
259 function $pick(obj, picked){
260         return ($type(obj)) ? obj : picked;
261 };
262
263 /*
264 Function: $random
265         Returns a random integer number between the two passed in values.
266
267 Arguments:
268         min - integer, the minimum value (inclusive).
269         max - integer, the maximum value (inclusive).
270
271 Returns:
272         a random integer between min and max.
273 */
274
275 function $random(min, max){
276         return Math.floor(Math.random() * (max - min + 1) + min);
277 };
278
279 /*
280 Function: $clear
281         clears a timeout or an Interval.
282
283 Returns:
284         null
285
286 Arguments:
287         timer - the setInterval or setTimeout to clear.
288
289 Example:
290         >var myTimer = myFunction.delay(5000); //wait 5 seconds and execute my function.
291         >myTimer = $clear(myTimer); //nevermind
292
293 See also:
294         <Function.delay>, <Function.periodical>
295 */
296
297 function $clear(timer){
298         clearTimeout(timer);
299         clearInterval(timer);
300         return null;
301 };
302
303 /* Section: Browser Detection */
304
305 /*
306 Properties:
307         window.ie - will be set to true if the current browser is internet explorer (any).
308         window.ie6 - will be set to true if the current browser is internet explorer 6.
309         window.ie7 - will be set to true if the current browser is internet explorer 7.
310         window.khtml - will be set to true if the current browser is Safari/Konqueror.
311         window.gecko - will be set to true if the current browser is Mozilla/Gecko.
312 */
313
314 if (window.ActiveXObject) window.ie = window[window.XMLHttpRequest ? 'ie7' : 'ie6'] = true;
315 else if (document.childNodes && !document.all && !navigator.taintEnabled) window.khtml = true;
316 else if (document.getBoxObjectFor != null) window.gecko = true;
317
318 /*
319 Script: Array.js
320         Contains Array prototypes and the function <$A>;
321
322 Author:
323         Valerio Proietti, <http://mad4milk.net>
324
325 License:
326         MIT-style license.
327 */
328
329 /*
330 Class: Array
331         A collection of The Array Object prototype methods.
332 */
333
334 //emulated methods
335
336 /*
337 Property: forEach
338         Iterates through an array; This method is only available for browsers without native *forEach* support.
339         For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:forEach>
340 */
341
342 Array.prototype.forEach = Array.prototype.forEach || function(fn, bind){
343         for (var i = 0; i < this.length; i++) fn.call(bind, this[i], i, this);
344 };
345
346 /*
347 Property: map
348         This method is provided only for browsers without native *map* support.
349         For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:map>
350 */
351
352 Array.prototype.map = Array.prototype.map || function(fn, bind){
353         var results = [];
354         for (var i = 0; i < this.length; i++) results[i] = fn.call(bind, this[i], i, this);
355         return results;
356 };
357
358 /*
359 Property: every
360         This method is provided only for browsers without native *every* support.
361         For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every>
362 */
363
364 Array.prototype.every = Array.prototype.every || function(fn, bind){
365         for (var i = 0; i < this.length; i++){
366                 if (!fn.call(bind, this[i], i, this)) return false;
367         }
368         return true;
369 };
370
371 /*
372 Property: some
373         This method is provided only for browsers without native *some* support.
374         For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some>
375 */
376
377 Array.prototype.some = Array.prototype.some || function(fn, bind){
378         for (var i = 0; i < this.length; i++){
379                 if (fn.call(bind, this[i], i, this)) return true;
380         }
381         return false;
382 };
383
384 /*
385 Property: indexOf
386         This method is provided only for browsers without native *indexOf* support.
387         For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf>
388 */
389
390 Array.prototype.indexOf = Array.prototype.indexOf || function(item, from){
391         from = from || 0;
392         if (from < 0) from = Math.max(0, this.length + from);
393         while (from < this.length){
394                 if(this[from] === item) return from;
395                 from++;
396         }
397         return -1;
398 };
399
400 //custom methods
401
402 Array.extend({
403
404         /*
405         Property: each
406                 Same as <Array.forEach>.
407
408         Arguments:
409                 fn - the function to execute with each item in the array
410                 bind - optional, the object that the "this" of the function will refer to.
411
412         Example:
413                 >var Animals = ['Cat', 'Dog', 'Coala'];
414                 >Animals.forEach(function(animal){
415                 >       document.write(animal)
416                 >});
417         */
418
419         each: Array.prototype.forEach,
420
421         /*
422         Property: copy
423                 Copy the array and returns it.
424
425         Returns:
426                 an Array
427
428         Example:
429                 >var letters = ["a","b","c"];
430                 >var copy = ["a","b","c"].copy();
431         */
432
433         copy: function(){
434                 var newArray = [];
435                 for (var i = 0; i < this.length; i++) newArray[i] = this[i];
436                 return newArray;
437         },
438
439         /*
440         Property: remove
441                 Removes all occurrences of an item from the array.
442
443         Arguments:
444                 item - the item to remove
445
446         Returns:
447                 the Array with all occurrences of the item removed.
448
449         Example:
450                 >["1","2","3","2"].remove("2") // ["1","3"];
451         */
452
453         remove: function(item){
454                 var i = 0;
455                 while (i < this.length){
456                         if (this[i] == item) this.splice(i, 1);
457                         else i++;
458                 }
459                 return this;
460         },
461
462         /*
463         Property: test
464                 Tests an array for the presence of an item.
465
466         Arguments:
467                 item - the item to search for in the array.
468                 from - 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.
469
470         Returns:
471                 true - the item was found
472                 false - it wasn't
473
474         Example:
475                 >["a","b","c"].test("a"); // true
476                 >["a","b","c"].test("d"); // false
477         */
478
479         test: function(item, from){
480                 return this.indexOf(item, from) != -1;
481         },
482
483         /*
484         Property: extend
485                 Extends an array with another
486
487         Arguments:
488                 newArray - the array to extend ours with
489
490         Example:
491                 >var Animals = ['Cat', 'Dog', 'Coala'];
492                 >Animals.extend(['Lizard']);
493                 >//Animals is now: ['Cat', 'Dog', 'Coala', 'Lizard'];
494         */
495
496         extend: function(newArray){
497                 for (var i = 0; i < newArray.length; i++) this.push(newArray[i]);
498                 return this;
499         },
500
501         /*
502         Property: associate
503                 Creates an object with key-value pairs based on the array of keywords passed in
504                 and the current content of the array.
505
506         Arguments:
507                 keys - the array of keywords.
508
509         Example:
510                 (start code)
511                 var Animals = ['Cat', 'Dog', 'Coala', 'Lizard'];
512                 var Speech = ['Miao', 'Bau', 'Fruuu', 'Mute'];
513                 var Speeches = Animals.associate(speech);
514                 //Speeches['Miao'] is now Cat.
515                 //Speeches['Bau'] is now Dog.
516                 //...
517                 (end)
518         */
519
520         associate: function(keys){
521                 var obj = {}, length = Math.min(this.length, keys.length);
522                 for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
523                 return obj;
524         }
525
526 });
527
528 /* Section: Utility Functions */
529
530 /*
531 Function: $A()
532         Same as <Array.copy>, but as function.
533         Useful to apply Array prototypes to iterable objects, as a collection of DOM elements or the arguments object.
534
535 Example:
536         (start code)
537         function myFunction(){
538                 $A(arguments).each(argument, function(){
539                         alert(argument);
540                 });
541         };
542         //the above will alert all the arguments passed to the function myFunction.
543         (end)
544 */
545
546 function $A(array){
547         return Array.prototype.copy.call(array);
548 };
549
550 /*
551 Function: $each
552         use to iterate through iterables that are not regular arrays, such as builtin getElementsByTagName calls, or arguments of a function.
553
554 Arguments:
555         iterable - an iterable element.
556         function - function to apply to the iterable.
557         bind - optional, the 'this' of the function will refer to this object.
558 */
559
560 function $each(iterable, fn, bind){
561         return Array.prototype.forEach.call(iterable, fn, bind);
562 };
563
564 /*
565 Script: String.js
566         Contains String prototypes and Number prototypes.
567
568 Author:
569         Valerio Proietti, <http://mad4milk.net>
570
571 License:
572         MIT-style license.
573 */
574
575 /*
576 Class: String
577         A collection of The String Object prototype methods.
578 */
579
580 String.extend({
581
582         /*
583         Property: test
584                 Tests a string with a regular expression.
585
586         Arguments:
587                 regex - the regular expression you want to match the string with
588                 params - optional, any parameters you want to pass to the regex ('g' has no effect)
589
590         Returns:
591                 true if a match for the regular expression is found in the string, false if not.
592                 See <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:RegExp:test>
593
594         Example:
595                 >"I like cookies".test("cookie"); // returns true
596                 >"I like cookies".test("COOKIE", "i") // ignore case, returns true
597                 >"I like cookies".test("cake"); // returns false
598         */
599
600         test: function(regex, params){
601                 return new RegExp(regex, params).test(this);
602         },
603
604         /*
605         Property: toInt
606                 parses a string to an integer.
607
608         Returns:
609                 either an int or "NaN" if the string is not a number.
610
611         Example:
612                 >var value = "10px".toInt(); // value is 10
613         */
614
615         toInt: function(){
616                 return parseInt(this);
617         },
618
619         toFloat: function(){
620                 return parseFloat(this);
621         },
622
623         /*
624         Property: camelCase
625                 Converts a hiphenated string to a camelcase string.
626
627         Example:
628                 >"I-like-cookies".camelCase(); //"ILikeCookies"
629
630         Returns:
631                 the camel cased string
632         */
633
634         camelCase: function(){
635                 return this.replace(/-\D/g, function(match){
636                         return match.charAt(1).toUpperCase();
637                 });
638         },
639
640         /*
641         Property: hyphenate
642                 Converts a camelCased string to a hyphen-ated string.
643
644         Example:
645                 >"ILikeCookies".hyphenate(); //"I-like-cookies"
646         */
647
648         hyphenate: function(){
649                 return this.replace(/\w[A-Z]/g, function(match){
650                         return (match.charAt(0)+'-'+match.charAt(1).toLowerCase());
651                 });
652         },
653
654         /*
655         Property: capitalize
656                 Converts the first letter in each word of a string to Uppercase.
657
658         Example:
659                 >"i like cookies".capitalize(); //"I Like Cookies"
660
661         Returns:
662                 the capitalized string
663         */
664
665         capitalize: function(){
666                 return this.toLowerCase().replace(/\b[a-z]/g, function(match){
667                         return match.toUpperCase();
668                 });
669         },
670
671         /*
672         Property: trim
673                 Trims the leading and trailing spaces off a string.
674
675         Example:
676                 >"    i like cookies     ".trim() //"i like cookies"
677
678         Returns:
679                 the trimmed string
680         */
681
682         trim: function(){
683                 return this.replace(/^\s+|\s+$/g, '');
684         },
685
686         /*
687         Property: clean
688                 trims (<String.trim>) a string AND removes all the double spaces in a string.
689
690         Returns:
691                 the cleaned string
692
693         Example:
694                 >" i      like     cookies      \n\n".clean() //"i like cookies"
695         */
696
697         clean: function(){
698                 return this.replace(/\s{2,}/g, ' ').trim();
699         },
700
701         /*
702         Property: rgbToHex
703                 Converts an RGB value to hexidecimal. The string must be in the format of "rgb(255, 255, 255)" or "rgba(255, 255, 255, 1)";
704
705         Arguments:
706                 array - boolean value, defaults to false. Use true if you want the array ['FF', '33', '00'] as output instead of #FF3300
707
708         Returns:
709                 hex string or array. returns transparent if the fourth value of rgba in input string is 0,
710
711         Example:
712                 >"rgb(17,34,51)".rgbToHex(); //"#112233"
713                 >"rgba(17,34,51,0)".rgbToHex(); //"transparent"
714                 >"rgb(17,34,51)".rgbToHex(true); //[11,22,33]
715         */
716
717         rgbToHex: function(array){
718                 var rgb = this.match(/\d{1,3}/g);
719                 return (rgb) ? rgb.rgbToHex(array) : false;
720         },
721
722         /*
723         Property: hexToRgb
724                 Converts a hexidecimal color value to RGB. Input string must be the hex color value (with or without the hash). Also accepts triplets ('333');
725
726         Arguments:
727                 array - boolean value, defaults to false. Use true if you want the array ['255', '255', '255'] as output instead of "rgb(255,255,255)";
728
729         Returns:
730                 rgb string or array.
731
732         Example:
733                 >"#112233".hexToRgb(); //"rgb(17,34,51)"
734                 >"#112233".hexToRgb(true); //[17,34,51]
735         */
736
737         hexToRgb: function(array){
738                 var hex = this.match('^#?(\\w{1,2})(\\w{1,2})(\\w{1,2})$');
739                 return (hex) ? hex.hexToRgb(array) : false;
740         }
741
742 });
743
744 Array.extend({
745         
746         rgbToHex: function(array){
747                 if (this.length < 3) return false;
748                 if (this[3] && this[3] == 0) return 'transparent';
749                 var hex = [];
750                 for (var i = 0; i < 3; i++){
751                         var bit = (this[i]-0).toString(16);
752                         hex.push(bit.length == 1 ? '0'+bit : bit);
753                 }
754                 return array ? hex : '#'+hex.join('');
755         },
756         
757         hexToRgb: function(array){
758                 if (this.length != 4) return false;
759                 var rgb = [];
760                 for (var i = 1; i < 4; i++){
761                         if (this[i].length == 1) this[i] += this[i];
762                         rgb.push(parseInt(this[i], 16));
763                 }
764                 return array ? rgb : 'rgb('+rgb.join(',')+')';
765         }
766
767 });
768
769 /*
770 Class: Number
771         contains the internal method toInt.
772 */
773
774 Number.extend({
775
776         /*
777         Property: toInt
778                 Returns this number; useful because toInt must work on both Strings and Numbers.
779         */
780
781         toInt: function(){
782                 return parseInt(this);
783         },
784
785         toFloat: function(){
786                 return parseFloat(this);
787         }
788
789 });
790
791 /* 
792 Script: Function.js
793         Contains Function prototypes and utility functions .
794
795 Author:
796         Valerio Proietti, <http://mad4milk.net>
797
798 License:
799         MIT-style license.
800
801 Credits:
802         - 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
803 */
804
805 /*
806 Class: Function
807         A collection of The Function Object prototype methods.
808 */
809
810 Function.extend({
811
812         create: function(options){
813                 var fn = this;
814                 options = Object.extend({
815                         'bind': fn,
816                         'event': false,
817                         'arguments': null,
818                         'delay': false,
819                         'periodical': false,
820                         'attempt': false
821                 }, options || {});
822                 if (options.arguments != null && typeof options.arguments != 'undefined' && !(options.arguments instanceof Array))
823                         options.arguments = [options.arguments];
824                 return function(event){
825                         var args = options.arguments || arguments;
826                         if (options.event){
827                                 event = (options.event === true) ? event || window.event : new options.event(event);
828                                 args = [event].concat(args);
829                         }
830                         var returns = function(){
831                                 return fn.apply(options.bind, args);
832                         };
833                         if (options.delay) return setTimeout(returns, options.delay);
834                         if (options.periodical) return setInterval(returns, options.periodical);
835                         if (options.attempt){
836                                 try {
837                                         var result = returns();
838                                 } catch(err){
839                                         result = err;
840                                 } finally {
841                                         return result;
842                                 }
843                         } else return returns();
844                 };
845         },
846
847         /*
848         Property: pass
849                 Shortcut to create closures with arguments and bind.
850
851         Returns:
852                 a function.
853
854         Arguments:
855                 args - the arguments passed. must be an array if arguments > 1
856                 bind - optional, the object that the "this" of the function will refer to.
857
858         Example:
859                 >myFunction.pass([arg1, arg2], myElement);
860         */
861
862         pass: function(args, bind){
863                 return this.create({'arguments': args, 'bind': bind});
864         },
865         
866         /*
867         Property: attempt
868                 Tries to execute the function, returns either the function results or the error.
869
870         Arguments:
871                 args - the arguments passed. must be an array if arguments > 1
872                 bind - optional, the object that the "this" of the function will refer to.
873
874         Example:
875                 >myFunction.attempt([arg1, arg2], myElement);
876         */
877
878         attempt: function(args, bind){
879                 return this.create({'arguments': args, 'bind': bind, 'attempt': true})();
880         },
881
882         /*
883         Property: bind
884                 method to easily create closures with "this" altered.
885
886         Arguments:
887                 bind - optional, the object that the "this" of the function will refer to.
888                 args - optional, the arguments passed. must be an array if arguments > 1
889
890         Returns:
891                 a function.
892
893         Example:
894                 >function myFunction(){
895                 >       this.setStyle('color', 'red');
896                 >       // note that 'this' here refers to myFunction, not an element
897                 >       // we'll need to bind this function to the element we want to alter
898                 >};
899                 >var myBoundFunction = myFunction.bind(myElement);
900                 >myBoundFunction(); // this will make the element myElement red.
901         */
902
903         bind: function(bind, args){
904                 return this.create({'bind': bind, 'arguments': args});
905         },
906
907         /*
908         Property: bindAsEventListener
909                 cross browser method to pass event firer
910
911         Arguments:
912                 bind - optional, the object that the "this" of the function will refer to.
913                 args - optional, the arguments passed. must be an array if arguments > 1
914
915         Returns:
916                 a function with the parameter bind as its "this" and as a pre-passed argument event or window.event, depending on the browser.
917
918         Example:
919                 >function myFunction(event){
920                 >       alert(event.clientx) //returns the coordinates of the mouse..
921                 >};
922                 >myElement.onclick = myFunction.bindAsEventListener(myElement);
923         */
924
925         bindAsEventListener: function(bind, args){
926                 return this.create({'bind': bind, 'event': true, 'arguments': args});
927         },
928
929         /*
930         Property: delay
931                 Delays the execution of a function by a specified duration.
932
933         Arguments:
934                 ms - the duration to wait in milliseconds
935                 bind - optional, the object that the "this" of the function will refer to.
936                 args - optional, the arguments passed. must be an array if arguments > 1
937
938         Example:
939                 >myFunction.delay(50, myElement) //wait 50 milliseconds, then call myFunction and bind myElement to it
940                 >(function(){alert('one second later...')}).delay(1000); //wait a second and alert
941         */
942
943         delay: function(ms, bind, args){
944                 return this.create({'delay': ms, 'bind': bind, 'arguments': args})();
945         },
946
947         /*
948         Property: periodical
949                 Executes a function in the specified intervals of time
950
951         Arguments:
952                 ms - the duration of the intervals between executions.
953                 bind - optional, the object that the "this" of the function will refer to.
954                 args - optional, the arguments passed. must be an array if arguments > 1
955         */
956
957         periodical: function(ms, bind, args){
958                 return this.create({'periodical': ms, 'bind': bind, 'arguments': args})();
959         }
960
961 });
962
963 /*
964 Script: Element.js
965         Contains useful Element prototypes, to be used with the dollar function <$>.
966
967 Author:
968         Valerio Proietti, <http://mad4milk.net>
969
970 License:
971         MIT-style license.
972
973 Credits:
974         - 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
975 */
976
977 /*
978 Class: Element
979         Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
980 */
981
982 var Element = new Class({
983
984         /*
985         Property: initialize
986                 Creates a new element of the type passed in.
987
988         Arguments:
989                 el - the tag name for the element you wish to create.
990
991         Example:
992                 >var div = new Element('div');
993         */
994
995         initialize: function(el){
996                 if ($type(el) == 'string') el = document.createElement(el);
997                 return $(el);
998         }
999
1000 });
1001
1002 /*
1003 Function: $()
1004         returns the element passed in with all the Element prototypes applied.
1005
1006 Arguments:
1007         el - a reference to an actual element or a string representing the id of an element
1008
1009 Example:
1010         >$('myElement') // gets a DOM element by id with all the Element prototypes applied.
1011         >var div = document.getElementById('myElement');
1012         >$(div) //returns an Element also with all the mootools extentions applied.
1013
1014         You'll use this when you aren't sure if a variable is an actual element or an id, as
1015         well as just shorthand for document.getElementById().
1016
1017 Returns:
1018         a DOM element or false (if no id was found).
1019
1020 Note:
1021         you need to call $ on an element only once to get all the prototypes.
1022         But its no harm to call it multiple times, as it will detect if it has been already extended.
1023 */
1024
1025 function $(el){
1026         if (!el) return false;
1027         if (el._element_extended_ || [window, document].test(el)) return el;
1028         if ($type(el) == 'string') el = document.getElementById(el);
1029         if ($type(el) != 'element') return false;
1030         if (['object', 'embed'].test(el.tagName.toLowerCase()) || el.extend) return el;
1031         el._element_extended_ = true;
1032         Garbage.collect(el);
1033         el.extend = Object.extend;
1034         if (!(el instanceof HTMLElement)) el.extend(Element.prototype);
1035         return el;
1036 };
1037
1038 //elements class
1039
1040 var Elements = new Class({});
1041
1042 new Object.Native(Elements);
1043
1044 document.getElementsBySelector = document.getElementsByTagName;
1045
1046 /*
1047 Function: $$()
1048         Selects, and extends DOM elements.
1049
1050 Arguments:
1051         HTMLCollection(document.getElementsByTagName, element.childNodes), an array of elements, a string.
1052
1053 Note:
1054         if you loaded <Dom.js>, $$ will also accept CSS Selectors.
1055
1056 Example:
1057         >$$('a') //an array of all anchor tags on the page
1058         >$$('a', 'b') //an array of all anchor and bold tags on the page
1059         >$$('#myElement') //array containing only the element with id = myElement. (only with <Dom.js>)
1060         >$$('#myElement a.myClass') //an array of all anchor tags with the class "myClass" within the DOM element with id "myElement" (only with <Dom.js>)
1061
1062 Returns:
1063         array - array of all the dom elements matched
1064 */
1065
1066 function $$(){
1067         if (!arguments) return false;
1068         if (arguments.length == 1){
1069                 if (!arguments[0]) return false;
1070                 if (arguments[0]._elements_extended_) return arguments[0];
1071         }
1072         var elements = [];
1073         $each(arguments, function(selector){
1074                 switch ($type(selector)){
1075                         case 'element': elements.push($(selector)); break;
1076                         case 'string': selector = document.getElementsBySelector(selector);
1077                         default:
1078                         if (selector.length){
1079                                 $each(selector, function(el){
1080                                         if ($(el)) elements.push(el);
1081                                 });
1082                         }
1083                 }
1084         });
1085         elements._elements_extended_ = true;
1086         return Object.extend(elements, new Elements);
1087 };
1088
1089 Elements.Multi = function(property){
1090         return function(){
1091                 var args = arguments;
1092                 var items = [];
1093                 var elements = true;
1094                 $each(this, function(el){
1095                         var returns = el[property].apply(el, args);
1096                         if ($type(returns) != 'element') elements = false;
1097                         items.push(returns);
1098                 });
1099                 if (elements) items = $$(items);
1100                 return items;
1101         };
1102 };
1103
1104 Element.extend = function(properties){
1105         for (var property in properties){
1106                 HTMLElement.prototype[property] = properties[property];
1107                 Element.prototype[property] = properties[property];
1108                 Elements.prototype[property] = Elements.Multi(property);
1109         }
1110 };
1111
1112 Element.extend({
1113
1114         inject: function(el, where){
1115                 el = $(el) || new Element(el);
1116                 switch (where){
1117                         case "before": $(el.parentNode).insertBefore(this, el); break;
1118                         case "after":
1119                                 if (!el.getNext()) $(el.parentNode).appendChild(this);
1120                                 else $(el.parentNode).insertBefore(this, el.getNext());
1121                                 break;
1122                         case "inside": el.appendChild(this);
1123                 }
1124                 return this;
1125         },
1126
1127         /*
1128         Property: injectBefore
1129                 Inserts the Element before the passed element.
1130
1131         Parameteres:
1132                 el - a string representing the element to be injected in (myElementId, or div), or an element reference.
1133                 If you pass div or another tag, the element will be created.
1134
1135         Example:
1136                 >html:
1137                 ><div id="myElement"></div>
1138                 ><div id="mySecondElement"></div>
1139                 >js:
1140                 >$('mySecondElement').injectBefore('myElement');
1141                 >resulting html:
1142                 ><div id="mySecondElement"></div>
1143                 ><div id="myElement"></div>
1144
1145         */
1146
1147         injectBefore: function(el){
1148                 return this.inject(el, 'before');
1149         },
1150
1151         /*
1152         Property: injectAfter
1153                 Same as <Element.injectBefore>, but inserts the element after.
1154         */
1155
1156         injectAfter: function(el){
1157                 return this.inject(el, 'after');
1158         },
1159
1160         /*
1161         Property: injectInside
1162                 Same as <Element.injectBefore>, but inserts the element inside.
1163         */
1164
1165         injectInside: function(el){
1166                 return this.inject(el, 'inside');
1167         },
1168
1169         /*
1170         Property: adopt
1171                 Inserts the passed element inside the Element. Works as <Element.injectInside> but in reverse.
1172
1173         Parameteres:
1174                 el - a string representing the element to be injected in (myElementId, or div), or an element reference.
1175                 If you pass div or another tag, the element will be created.
1176         */
1177
1178         adopt: function(el){
1179                 this.appendChild($(el) || new Element(el));
1180                 return this;
1181         },
1182
1183         /*
1184         Property: remove
1185                 Removes the Element from the DOM.
1186
1187         Example:
1188                 >$('myElement').remove() //bye bye
1189         */
1190
1191         remove: function(){
1192                 this.parentNode.removeChild(this);
1193                 return this;
1194         },
1195
1196         /*
1197         Property: clone
1198                 Clones the Element and returns the cloned one.
1199
1200         Returns: 
1201                 the cloned element
1202
1203         Example:
1204                 >var clone = $('myElement').clone().injectAfter('myElement');
1205                 >//clones the Element and append the clone after the Element.
1206         */
1207
1208         clone: function(contents){
1209                 var el = this.cloneNode(contents !== false);
1210                 return $(el);
1211         },
1212
1213         /*
1214         Property: replaceWith
1215                 Replaces the Element with an element passed.
1216
1217         Parameteres:
1218                 el - a string representing the element to be injected in (myElementId, or div), or an element reference.
1219                 If you pass div or another tag, the element will be created.
1220
1221         Returns:
1222                 the passed in element
1223
1224         Example:
1225                 >$('myOldElement').replaceWith($('myNewElement')); //$('myOldElement') is gone, and $('myNewElement') is in its place.
1226         */
1227
1228         replaceWith: function(el){
1229                 el = $(el) || new Element(el);
1230                 this.parentNode.replaceChild(el, this);
1231                 return el;
1232         },
1233
1234         /*
1235         Property: appendText
1236                 Appends text node to a DOM element.
1237
1238         Arguments:
1239                 text - the text to append.
1240
1241         Example:
1242                 ><div id="myElement">hey</div>
1243                 >$('myElement').appendText(' howdy'); //myElement innerHTML is now "hey howdy"
1244         */
1245
1246         appendText: function(text){
1247                 if (window.ie){
1248                         switch(this.getTag()){
1249                                 case 'style': this.styleSheet.cssText = text; return this;
1250                                 case 'script': this.setProperty('text', text); return this;
1251                         }
1252                 }
1253                 this.appendChild(document.createTextNode(text));
1254                 return this;
1255         },
1256
1257         /*
1258         Property: hasClass
1259                 Tests the Element to see if it has the passed in className.
1260
1261         Returns:
1262                 true - the Element has the class
1263                 false - it doesn't
1264          
1265         Arguments:
1266                 className - the class name to test.
1267          
1268         Example:
1269                 ><div id="myElement" class="testClass"></div>
1270                 >$('myElement').hasClass('testClass'); //returns true
1271         */
1272
1273         hasClass: function(className){
1274                 return this.className.test('(?:^|\\s+)' + className + '(?:\\s+|$)');
1275         },
1276
1277         /*
1278         Property: addClass
1279                 Adds the passed in class to the Element, if the element doesnt already have it.
1280
1281         Arguments:
1282                 className - the class name to add
1283
1284         Example: 
1285                 ><div id="myElement" class="testClass"></div>
1286                 >$('myElement').addClass('newClass'); //<div id="myElement" class="testClass newClass"></div>
1287         */
1288
1289         addClass: function(className){
1290                 if (!this.hasClass(className)) this.className = (this.className+' '+className).clean();
1291                 return this;
1292         },
1293
1294         /*
1295         Property: removeClass
1296                 works like <Element.addClass>, but removes the class from the element.
1297         */
1298
1299         removeClass: function(className){
1300                 if (this.hasClass(className)) this.className = this.className.replace(className, '').clean();
1301                 return this;
1302         },
1303
1304         /*
1305         Property: toggleClass
1306                 Adds or removes the passed in class name to the element, depending on if it's present or not.
1307
1308         Arguments:
1309                 className - the class to add or remove
1310
1311         Example:
1312                 ><div id="myElement" class="myClass"></div>
1313                 >$('myElement').toggleClass('myClass');
1314                 ><div id="myElement" class=""></div>
1315                 >$('myElement').toggleClass('myClass');
1316                 ><div id="myElement" class="myClass"></div>
1317         */
1318
1319         toggleClass: function(className){
1320                 return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
1321         },
1322
1323         /*
1324         Property: setStyle
1325                 Sets a css property to the Element.
1326
1327                 Arguments:
1328                         property - the property to set
1329                         value - the value to which to set it
1330
1331                 Example:
1332                         >$('myElement').setStyle('width', '300px'); //the width is now 300px
1333         */
1334
1335         setStyle: function(property, value){
1336                 if (property == 'opacity') this.setOpacity(parseFloat(value));
1337                 else this.style[property.camelCase()] = (value.push) ? value.rgbToHex() : value;
1338                 return this;
1339         },
1340
1341         /*
1342         Property: setStyles
1343                 Applies a collection of styles to the Element.
1344
1345         Arguments:
1346                 source - an object or string containing all the styles to apply
1347
1348         Examples:
1349                 >$('myElement').setStyles({
1350                 >       border: '1px solid #000',
1351                 >       width: '300px',
1352                 >       height: '400px'
1353                 >});
1354
1355                 OR
1356
1357                 >$('myElement').setStyle('border: 1px solid #000; width: 300px; height: 400px;');
1358         */
1359
1360         setStyles: function(source){
1361                 switch ($type(source)){
1362                         case 'object':
1363                                 for (var property in source) this.setStyle(property, source[property]);
1364                                 break;
1365                         case 'string':
1366                                 if (window.ie) this.cssText = source;
1367                                 else this.setAttribute('style', source);
1368                 }
1369                 return this;
1370         },
1371
1372         /*
1373         Property: setOpacity
1374                 Sets the opacity of the Element, and sets also visibility == "hidden" if opacity == 0, and visibility = "visible" if opacity == 1.
1375
1376         Arguments:
1377                 opacity - Accepts numbers from 0 to 1.
1378
1379         Example:
1380                 >$('myElement').setOpacity(0.5) //make it 50% transparent
1381         */
1382
1383         setOpacity: function(opacity){
1384                 if (opacity == 0){
1385                         if(this.style.visibility != "hidden") this.style.visibility = "hidden";
1386                 } else {
1387                         if(this.style.visibility != "visible") this.style.visibility = "visible";
1388                 }
1389                 if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1;
1390                 if (window.ie) this.style.filter = "alpha(opacity=" + opacity*100 + ")";
1391                 this.style.opacity = this.opacity = opacity;
1392                 return this;
1393         },
1394
1395         /*
1396         Property: getStyle
1397                 Returns the style of the Element given the property passed in.
1398
1399         Arguments:
1400                 property - the css style property you want to retrieve
1401
1402         Example:
1403                 >$('myElement').getStyle('width'); //returns "400px"
1404                 >//but you can also use
1405                 >$('myElement').getStyle('width').toInt(); //returns "400"
1406
1407         Returns:
1408                 the style as a string
1409         */
1410
1411         getStyle: function(property){
1412                 property = property.camelCase();
1413                 var style = this.style[property] || false;
1414                 if (!$chk(style)){
1415                         if (property == 'opacity') return $chk(this.opacity) ? this.opacity : 1;
1416                         if (['margin', 'padding'].test(property)){
1417                                 return [this.getStyle(property+'-top') || 0, this.getStyle(property+'-right') || 0,
1418                                                 this.getStyle(property+'-bottom') || 0, this.getStyle(property+'-left') || 0].join(' ');
1419                         }
1420                         if (document.defaultView) style = document.defaultView.getComputedStyle(this, null).getPropertyValue(property.hyphenate());
1421                         else if (this.currentStyle) style = this.currentStyle[property];
1422                 }
1423                 return (style && property.test('color', 'i') && style.test('rgb')) ? style.rgbToHex() : style;
1424         },
1425
1426         /*
1427         Property: addEvent
1428                 Attaches an event listener to a DOM element.
1429
1430         Arguments:
1431                 type - the event to monitor ('click', 'load', etc) without the prefix 'on'.
1432                 fn - the function to execute
1433
1434         Example:
1435                 >$('myElement').addEvent('click', function(){alert('clicked!')});
1436         */
1437
1438         addEvent: function(type, fn){
1439                 this.events = this.events || {};
1440                 this.events[type] = this.events[type] || {'keys': [], 'values': []};
1441                 if (!this.events[type].keys.test(fn)){
1442                         this.events[type].keys.push(fn);
1443                         if (this.addEventListener){
1444                                 this.addEventListener((type == 'mousewheel' && window.gecko) ? 'DOMMouseScroll' : type, fn, false);
1445                         } else {
1446                                 fn = fn.bind(this);
1447                                 this.attachEvent('on'+type, fn);
1448                                 this.events[type].values.push(fn);
1449                         }
1450                 }
1451                 return this;
1452         },
1453
1454         addEvents: function(source){
1455                 if (source){
1456                         for (var type in source) this.addEvent(type, source[type]);
1457                 }
1458                 return this;
1459         },
1460
1461         /*
1462         Property: removeEvent
1463                 Works as Element.addEvent, but instead removes the previously added event listener.
1464         */
1465
1466         removeEvent: function(type, fn){
1467                 if (this.events && this.events[type]){
1468                         var pos = this.events[type].keys.indexOf(fn);
1469                         if (pos == -1) return this;
1470                         var key = this.events[type].keys.splice(pos,1)[0];
1471                         if (this.removeEventListener){
1472                                 this.removeEventListener((type == 'mousewheel' && window.gecko) ? 'DOMMouseScroll' : type, key, false);
1473                         } else {
1474                                 this.detachEvent('on'+type, this.events[type].values.splice(pos,1)[0]);
1475                         }
1476                 }
1477                 return this;
1478         },
1479
1480         /*
1481         Property: removeEvents
1482                 removes all events of a certain type from an element. if no argument is passed in, removes all events.
1483         */
1484
1485         removeEvents: function(type){
1486                 if (this.events){
1487                         if (type){
1488                                 if (this.events[type]){
1489                                         this.events[type].keys.each(function(fn){
1490                                                 this.removeEvent(type, fn);
1491                                         }, this);
1492                                         this.events[type] = null;
1493                                 }
1494                         } else {
1495                                 for (var evType in this.events) this.removeEvents(evType);
1496                                 this.events = null;
1497                         }
1498                 }
1499                 return this;
1500         },
1501
1502         /*
1503         Property: fireEvent
1504                 executes all events of the specified type present in the element.
1505         */
1506
1507         fireEvent: function(type, args){
1508                 if (this.events && this.events[type]){
1509                         args = args || [];
1510                         if ($type(args) != 'array') args = [args];
1511                         this.events[type].keys.each(function(fn){
1512                                 fn.apply(this, args);
1513                         }, this);
1514                 }
1515         },
1516
1517         getBrother: function(what){
1518                 var el = this[what+'Sibling'];
1519                 while ($type(el) == 'whitespace') el = el[what+'Sibling'];
1520                 return $(el);
1521         },
1522
1523         /*
1524         Property: getPrevious
1525                 Returns the previousSibling of the Element, excluding text nodes.
1526
1527         Example:
1528                 >$('myElement').getPrevious(); //get the previous DOM element from myElement
1529
1530         Returns:
1531                 the sibling element or undefined if none found.
1532         */
1533
1534         getPrevious: function(){
1535                 return this.getBrother('previous');
1536         },
1537
1538         /*
1539         Property: getNext
1540                 Works as Element.getPrevious, but tries to find the nextSibling.
1541         */
1542
1543         getNext: function(){
1544                 return this.getBrother('next');
1545         },
1546
1547         /*
1548         Property: getFirst
1549                 Works as <Element.getPrevious>, but tries to find the firstChild.
1550         */
1551
1552         getFirst: function(){
1553                 var el = this.firstChild;
1554                 while ($type(el) == 'whitespace') el = el.nextSibling;
1555                 return $(el);
1556         },
1557
1558         /*
1559         Property: getLast
1560                 Works as <Element.getPrevious>, but tries to find the lastChild.
1561         */
1562
1563         getLast: function(){
1564                 var el = this.lastChild;
1565                 while ($type(el) == 'whitespace') el = el.previousSibling;
1566                 return $(el);
1567         },
1568         
1569         /*
1570         Property: getParent
1571                 returns the $(element.parentNode)
1572         */
1573
1574         getParent: function(){
1575                 return $(this.parentNode);
1576         },
1577         
1578         /*
1579         Property: getChildren
1580                 returns all the $(element.childNodes), excluding text nodes. Returns as <Elements>.
1581         */
1582
1583         getChildren: function(){
1584                 return $$(this.childNodes);
1585         },
1586
1587         /*
1588         Property: setProperty
1589                 Sets an attribute for the Element.
1590
1591         Arguments:
1592                 property - the property to assign the value passed in
1593                 value - the value to assign to the property passed in
1594
1595         Example:
1596                 >$('myImage').setProperty('src', 'whatever.gif'); //myImage now points to whatever.gif for its source
1597         */
1598
1599         setProperty: function(property, value){
1600                 switch (property){
1601                         case 'class': this.className = value; break;
1602                         case 'style': this.setStyles(value); break;
1603                         case 'name': if (window.ie6){
1604                                 var el = $(document.createElement('<'+this.getTag()+' name="'+value+'" />'));
1605                                 $each(this.attributes, function(attribute){
1606                                         if (attribute.name != 'name') el.setProperty(attribute.name, attribute.value);
1607                                 });
1608                                 if (this.parentNode) this.replaceWith(el);
1609                                 return el;
1610                         }
1611                         default: this.setAttribute(property, value);
1612                 }
1613                 return this;
1614         },
1615
1616         /*
1617         Property: setProperties
1618                 Sets numerous attributes for the Element.
1619
1620         Arguments:
1621                 source - an object with key/value pairs.
1622
1623         Example:
1624                 >$('myElement').setProperties({
1625                 >       src: 'whatever.gif',
1626                 >       alt: 'whatever dude'
1627                 >});
1628                 ><img src="whatever.gif" alt="whatever dude">
1629         */
1630
1631         setProperties: function(source){
1632                 for (var property in source) this.setProperty(property, source[property]);
1633                 return this;
1634         },
1635
1636         /*
1637         Property: setHTML
1638                 Sets the innerHTML of the Element.
1639
1640         Arguments:
1641                 html - the new innerHTML for the element.
1642
1643         Example:
1644                 >$('myElement').setHTML(newHTML) //the innerHTML of myElement is now = newHTML
1645         */
1646
1647         setHTML: function(html){
1648                 this.innerHTML = html;
1649                 return this;
1650         },
1651
1652         /*
1653         Property: getProperty
1654                 Gets the an attribute of the Element.
1655
1656         Arguments:
1657                 property - the attribute to retrieve
1658
1659         Example:
1660                 >$('myImage').getProperty('src') // returns whatever.gif
1661
1662         Returns:
1663                 the value, or an empty string
1664         */
1665
1666         getProperty: function(property){
1667                 return (property == 'class') ? this.className : this.getAttribute(property);
1668         },
1669
1670         /*
1671         Property: getTag
1672                 Returns the tagName of the element in lower case.
1673
1674         Example:
1675                 >$('myImage').getTag() // returns 'img'
1676
1677         Returns:
1678                 The tag name in lower case
1679         */
1680
1681         getTag: function(){
1682                 return this.tagName.toLowerCase();
1683         },
1684
1685         getOffsets: function(){
1686                 var el = this, offsetLeft = 0, offsetTop = 0;
1687                 do {
1688                         offsetLeft += el.offsetLeft || 0;
1689                         offsetTop += el.offsetTop || 0;
1690                         el = el.offsetParent;
1691                 } while (el);
1692                 return {'x': offsetLeft, 'y': offsetTop};
1693         },
1694
1695         /*
1696         Property: scrollTo
1697                 scrolls the element to the specified coordinated (if the element has an overflow)
1698
1699         Arguments:
1700                 x - the x coordinate
1701                 y - the y coordinate
1702
1703         Example:
1704                 >$('myElement').scrollTo(0, 100)
1705         */
1706
1707         scrollTo: function(x, y){
1708                 this.scrollLeft = x;
1709                 this.scrollTop = y;
1710         },
1711
1712         /*
1713         Property: getSize
1714                 return an Object representing the size/scroll values of the element.
1715
1716         Example:
1717                 (start code)
1718                 $('myElement').getSize();
1719                 (end)
1720
1721         Returns:
1722                 (start code)
1723                 {
1724                         'scroll': {'x': 100, 'y': 100},
1725                         'size': {'x': 200, 'y': 400},
1726                         'scrollSize': {'x': 300, 'y': 500}
1727                 }
1728                 (end)
1729         */
1730
1731         getSize: function(){
1732                 return {
1733                         'scroll': {'x': this.scrollLeft, 'y': this.scrollTop},
1734                         'size': {'x': this.offsetWidth, 'y': this.offsetHeight},
1735                         'scrollSize': {'x': this.scrollWidth, 'y': this.scrollHeight}
1736                 };
1737         },
1738
1739         /*
1740         Property: getTop
1741                 Returns the distance from the top of the window to the Element.
1742         */
1743
1744         getTop: function(){
1745                 return this.getOffsets().y;
1746         },
1747
1748         /*
1749         Property: getLeft
1750                 Returns the distance from the left of the window to the Element.
1751         */
1752
1753         getLeft: function(){
1754                 return this.getOffsets().x;
1755         },
1756
1757         /*
1758         Property: getPosition
1759                 Returns an object with width, height, left, right, top, and bottom, representing the values of the Element
1760
1761         Example:
1762                 (start code)
1763                 var myValues = $('myElement').getPosition();
1764                 (end)
1765
1766         Returns:
1767                 (start code)
1768                 {
1769                         width: 200,
1770                         height: 300,
1771                         left: 100,
1772                         top: 50,
1773                         right: 300,
1774                         bottom: 350
1775                 }
1776                 (end)
1777         */
1778
1779         getPosition: function(){
1780                 var offs = this.getOffsets();
1781                 var obj = {
1782                         'width': this.offsetWidth,
1783                         'height': this.offsetHeight,
1784                         'left': offs.x,
1785                         'top': offs.y
1786                 };
1787                 obj.right = obj.left + obj.width;
1788                 obj.bottom = obj.top + obj.height;
1789                 return obj;
1790         },
1791
1792         /*
1793         Property: getValue
1794                 Returns the value of the Element, if its tag is textarea, select or input. no multiple select support.
1795         */
1796
1797         getValue: function(){
1798                 switch (this.getTag()){
1799                         case 'select': if (this.selectedIndex != -1) return this.options[this.selectedIndex].value; break;
1800                         case 'input': if (!(this.checked && ['checkbox', 'radio'].test(this.type)) && !['hidden', 'text', 'password'].test(this.type)) break;
1801                         case 'textarea': return this.value;
1802                 }
1803                 return false;
1804         }
1805
1806 });
1807
1808 var Window = window;
1809
1810 window.addEvent = document.addEvent = Element.prototype.addEvent;
1811 window.removeEvent = document.removeEvent = Element.prototype.removeEvent;
1812
1813 var Garbage = {
1814
1815         elements: [],
1816
1817         collect: function(element){
1818                 Garbage.elements.push(element);
1819         },
1820
1821         trash: function(){
1822                 window.removeEvent('unload', Garbage.trash);
1823                 Garbage.elements.each(function(el){
1824                         el.removeEvents();
1825                         for (var p in Element.prototype) HTMLElement[p] = window[p] = document[p] = el[p] = null;
1826                         el.extend = null;
1827                 });
1828         }
1829
1830 };
1831
1832 window.addEvent('unload', Garbage.trash);
1833
1834 /*
1835 Script: Event.js
1836         Event class
1837
1838 Author:
1839         Valerio Proietti, <http://mad4milk.net>, Michael Jackson, <http://ajaxon.com/michael>
1840
1841 License:
1842         MIT-style license.
1843 */
1844
1845 /*
1846 Class: Event
1847         Cross browser methods to manage events.
1848
1849 Arguments:
1850         event - the event
1851
1852 Properties:
1853         shift - true if the user pressed the shift
1854         control - true if the user pressed the control 
1855         alt - true if the user pressed the alt
1856         meta - true if the user pressed the meta key
1857         code - the keycode of the key pressed
1858         page.x - the x position of the mouse, relative to the full window
1859         page.y - the y position of the mouse, relative to the full window
1860         client.x - the x position of the mouse, relative to the viewport
1861         client.y - the y position of the mouse, relative to the viewport
1862         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.
1863         target - the event target
1864         relatedTarget - the event related target
1865
1866 Example:
1867         (start code)
1868         $('myLink').onkeydown = function(event){
1869                 var event = new Event(event);
1870                 //event is now the Event class.
1871                 alert(event.key); //returns the lowercase letter pressed
1872                 alert(event.shift); //returns true if the key pressed is shift
1873                 if (event.key == 's' && event.control) alert('document saved');
1874         };
1875         (end)
1876 */
1877
1878 var Event = new Class({
1879
1880         initialize: function(event){
1881                 this.event = event || window.event;
1882                 this.type = this.event.type;
1883                 this.target = this.event.target || this.event.srcElement;
1884                 if (this.target.nodeType == 3) this.target = this.target.parentNode; // Safari
1885                 this.shift = this.event.shiftKey;
1886                 this.control = this.event.ctrlKey;
1887                 this.alt = this.event.altKey;
1888                 this.meta = this.event.metaKey;
1889                 if (['DOMMouseScroll', 'mousewheel'].test(this.type)){
1890                         this.wheel = this.event.wheelDelta ? (this.event.wheelDelta / (window.opera ? -120 : 120)) : -(this.event.detail || 0) / 3;
1891                 } else if (this.type.test('key')){
1892                         this.code = this.event.which || this.event.keyCode;
1893                         for (var name in Event.keys){
1894                                 if (Event.keys[name] == this.code) var special = name;
1895                         }
1896                         this.key = special || String.fromCharCode(this.code).toLowerCase();
1897
1898                 } else if (this.type.test('mouse') || this.type == 'click'){
1899                         this.page = {
1900                                 'x': this.event.pageX || this.event.clientX + document.documentElement.scrollLeft,
1901                                 'y': this.event.pageY || this.event.clientY + document.documentElement.scrollTop
1902                         };
1903                         this.client = {
1904                                 'x': this.event.pageX ? this.event.pageX - window.pageXOffset : this.event.clientX,
1905                                 'y': this.event.pageY ? this.event.pageY - window.pageYOffset : this.event.clientY
1906                         };
1907                         this.rightClick = (this.event.which == 3) || (this.event.button == 2);
1908                         switch (this.type){
1909                                 case 'mouseover': this.relatedTarget = this.event.relatedTarget || this.event.fromElement; break;
1910                                 case 'mouseout': this.relatedTarget = this.event.relatedTarget || this.event.toElement;
1911                         }
1912                 }
1913         },
1914
1915         /*
1916         Property: stop
1917                 cross browser method to stop an event
1918         */
1919
1920         stop: function() {
1921                 this.stopPropagation();
1922                 this.preventDefault();
1923                 return this;
1924         },
1925
1926         /*
1927         Property: stopPropagation
1928                 cross browser method to stop the propagation of an event
1929         */
1930
1931         stopPropagation: function(){
1932                 if (this.event.stopPropagation) this.event.stopPropagation();
1933                 else this.event.cancelBubble = true;
1934                 return this;
1935     },
1936
1937         /*
1938         Property: preventDefault
1939                 cross browser method to prevent the default action of the event
1940         */
1941
1942         preventDefault: function(){
1943                 if (this.event.preventDefault) this.event.preventDefault();
1944                 else this.event.returnValue = false;
1945                 return this;
1946         }
1947
1948 });
1949
1950 Event.keys = {
1951         'enter': 13,
1952         'up': 38,
1953         'down': 40,
1954         'left': 37,
1955         'right': 39,
1956         'esc': 27,
1957         'space': 32,
1958         'backspace': 8,
1959         'delete': 46
1960 };
1961
1962 Function.extend({
1963
1964         /*
1965         Property: bindWithEvent
1966                 automatically passes mootools Event Class.
1967
1968         Arguments:
1969                 bind - optional, the object that the "this" of the function will refer to.
1970
1971         Returns:
1972                 a function with the parameter bind as its "this" and as a pre-passed argument event or window.event, depending on the browser.
1973
1974         Example:
1975                 >function myFunction(event){
1976                 >       alert(event.clientx) //returns the coordinates of the mouse..
1977                 >};
1978                 >myElement.onclick = myFunction.bindWithEvent(myElement);
1979         */
1980
1981         bindWithEvent: function(bind, args){
1982                 return this.create({'bind': bind, 'arguments': args, 'event': Event});
1983         }
1984
1985 });
1986
1987
1988 /*
1989 Script: Common.js
1990         Contains common implementations for custom classes. In Mootools is implemented in <Ajax> and <Fx>.
1991
1992 Author:
1993         Valerio Proietti, <http://mad4milk.net>
1994
1995 License:
1996         MIT-style license.
1997 */
1998
1999 /*
2000 Class: Chain
2001         An "Utility" Class. Its methods can be implemented with <Class.implement> into any <Class>.
2002         Currently implemented in <Fx> and <Ajax>. In <Fx> for example, is used to execute a list of function, one after another, once the effect is completed.
2003         The functions will not be fired all togheter, but one every completion, to create custom complex animations.
2004
2005 Example:
2006         (start code)
2007         var myFx = new Fx.Style('element', 'opacity');
2008
2009         myFx.start(1,0).chain(function(){
2010                 myFx.start(0,1);
2011         }).chain(function(){
2012                 myFx.start(1,0);
2013         }).chain(function(){
2014                 myFx.start(0,1);
2015         });
2016         //the element will appear and disappear three times
2017         (end)
2018 */
2019
2020 var Chain = new Class({
2021
2022         /*
2023         Property: chain
2024                 adds a function to the Chain instance stack.
2025
2026         Arguments:
2027                 fn - the function to append.
2028         */
2029
2030         chain: function(fn){
2031                 this.chains = this.chains || [];
2032                 this.chains.push(fn);
2033                 return this;
2034         },
2035
2036         /*
2037         Property: callChain
2038                 Executes the first function of the Chain instance stack, then removes it. The first function will then become the second.
2039         */
2040
2041         callChain: function(){
2042                 if (this.chains && this.chains.length) this.chains.splice(0, 1)[0].delay(10, this);
2043         },
2044
2045         /*
2046         Property: clearChain
2047                 Clears the stack of a Chain instance.
2048         */
2049
2050         clearChain: function(){
2051                 this.chains = [];
2052         }
2053
2054 });
2055
2056 /*
2057 Class: Events
2058         An "Utility" Class. Its methods can be implemented with <Class.implement> into any <Class>.
2059         In <Fx> Class, for example, is used to give the possibility add any number of functions to the Effects events, like onComplete, onStart, onCancel
2060
2061 Example:
2062         (start code)
2063         var myFx = new Fx.Style('element', 'opacity').addEvent('onComplete', function(){
2064                 alert('the effect is completed');
2065         }).addEvent('onComplete', function(){
2066                 alert('I told you the effect is completed');
2067         });
2068
2069         myFx.start(0,1);
2070         //upon completion it will display the 2 alerts, in order.
2071         (end)
2072 */
2073
2074 var Events = new Class({
2075
2076         /*
2077         Property: addEvent
2078                 adds an event to the stack of events of the Class instance.
2079         */
2080
2081         addEvent: function(type, fn){
2082                 if (fn != Class.empty){
2083                         this.events = this.events || {};
2084                         this.events[type] = this.events[type] || [];
2085                         if (!this.events[type].test(fn)) this.events[type].push(fn);
2086                 }
2087                 return this;
2088         },
2089
2090         /*
2091         Property: fireEvent
2092                 fires all events of the specified type in the Class instance.
2093         */
2094
2095         fireEvent: function(type, args, delay){
2096                 if (this.events && this.events[type]){
2097                         this.events[type].each(function(fn){
2098                                 fn.create({'bind': this, 'delay': delay, 'arguments': args})();
2099                         }, this);
2100                 }
2101                 return this;
2102         },
2103
2104         /*
2105         Property: removeEvent
2106                 removes an event from the stack of events of the Class instance.
2107         */
2108
2109         removeEvent: function(type, fn){
2110                 if (this.events && this.events[type]) this.events[type].remove(fn);
2111                 return this;
2112         }
2113
2114 });
2115
2116 /*
2117 Class: Options
2118         An "Utility" Class. Its methods can be implemented with <Class.implement> into any <Class>.
2119         Used to automate the options settings, also adding Class <Events> when the option begins with on.
2120 */
2121
2122 var Options = new Class({
2123
2124         /*
2125         Property: setOptions
2126                 sets this.options
2127
2128         Arguments:
2129                 defaults - the default set of options
2130                 options - the user entered options. can be empty too.
2131
2132         Note:
2133                 if your Class has <Events> implemented, every option beginning with on, followed by a capital letter (onComplete) becomes an Class instance event.
2134         */
2135
2136         setOptions: function(defaults, options){
2137                 this.options = Object.extend(defaults, options);
2138                 if (this.addEvent){
2139                         for (var option in this.options){
2140                                 if (($type(this.options[option]) == 'function') && option.test('^on[A-Z]')) this.addEvent(option, this.options[option]);
2141                         }
2142                 }
2143                 return this;
2144         }
2145
2146 });
2147
2148 /*
2149 Script: Dom.js
2150         Css Query related function and <Element> extensions
2151
2152 Author:
2153         Valerio Proietti, <http://mad4milk.net>
2154
2155 License:
2156         MIT-style license.
2157 */
2158
2159 /* Section: Utility Functions */
2160
2161 /* 
2162 Function: $E 
2163         Selects a single (i.e. the first found) Element based on the selector passed in and an optional filter element.
2164
2165 Arguments:
2166         selector - the css selector to match
2167         filter - optional; a DOM element to limit the scope of the selector match; defaults to document.
2168
2169 Example:
2170         >$E('a', 'myElement') //find the first anchor tag inside the DOM element with id 'myElement'
2171
2172 Returns:
2173         a DOM element - the first element that matches the selector
2174 */
2175
2176 function $E(selector, filter){
2177         return ($(filter) || document).getElement(selector);
2178 };
2179
2180 /*
2181 Function: $ES
2182         Returns a collection of Elements that match the selector passed in limited to the scope of the optional filter.
2183         See Also: <Element.getElements> for an alternate syntax.
2184
2185 Returns:
2186         an array of dom elements that match the selector within the filter
2187
2188 Arguments:
2189         selector - css selector to match
2190         filter - optional; a DOM element to limit the scope of the selector match; defaults to document.
2191
2192 Examples:
2193         >$ES("a") //gets all the anchor tags; synonymous with $$("a")
2194         >$ES('a','myElement') //get all the anchor tags within $('myElement')
2195 */
2196
2197 function $ES(selector, filter){
2198         return ($(filter) || document).getElementsBySelector(selector);
2199 };
2200
2201 /*
2202 Class: Element
2203         Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
2204 */
2205
2206 Element.extend({
2207
2208         /*
2209         Property: getElements 
2210                 Gets all the elements within an element that match the given (single) selector.
2211
2212         Arguments:
2213                 selector - the css selector to match
2214
2215         Example:
2216                 >$('myElement').getElements('a'); // get all anchors within myElement
2217
2218         Credits:
2219                 Say thanks to Christophe Beyls <http://digitalia.be> for the new regular expression that rules getElements, a big step forward in terms of speed.
2220         */
2221
2222         getElements: function(selector){
2223                 var filters = [];
2224                 selector.clean().split(' ').each(function(sel, i){
2225                         var param = sel.match('^(\\w*|\\*)(?:#([\\w_-]+)|\\.([\\w_-]+))?(?:\\[["\']?(\\w+)["\']?(?:([\\*\\^\\$]?=)["\']?(\\w*)["\']?)?\\])?$');
2226                         //PARAM ARRAY: 0 = full string: 1 = tag; 2 = id; 3 = class; 4 = attribute; 5 = operator; 6 = value;
2227                         if (!param) return;
2228                         param[1] = param[1] || '*';
2229                         if (i == 0){
2230                                 if (param[2]){
2231                                         var el = this.getElementById(param[2]);
2232                                         if (!el || ((param[1] != '*') && (Element.prototype.getTag.call(el) != param[1]))) return;
2233                                         filters = [el];
2234                                 } else {
2235                                         filters = $A(this.getElementsByTagName(param[1]));
2236                                 }
2237                         } else {
2238                                 filters = Elements.prototype.filterByTagName.call(filters, param[1]);
2239                                 if (param[2]) filters = Elements.prototype.filterById.call(filters, param[2]);
2240                         }
2241                         if (param[3]) filters = Elements.prototype.filterByClassName.call(filters, param[3]);
2242                         if (param[4]) filters = Elements.prototype.filterByAttribute.call(filters, param[4], param[6], param[5]);
2243                 }, this);
2244                 return $$(filters);
2245         },
2246
2247         /*
2248         Property: getElementById
2249                 Targets an element with the specified id found inside the Element. Does not overwrite document.getElementById.
2250
2251         Arguments:
2252                 id - the id of the element to find.
2253         */
2254
2255         getElementById: function(id){
2256                 var el = document.getElementById(id);
2257                 if (!el) return false;
2258                 for (var parent = el.parentNode; parent != this; parent = parent.parentNode){
2259                         if (!parent) return false;
2260                 }
2261                 return el;
2262         },
2263
2264         /*
2265         Property: getElement
2266                 Same as <Element.getElements>, but returns only the first. Alternate syntax for <$E>, where filter is the Element.
2267         */
2268
2269         getElement: function(selector){
2270                 return this.getElementsBySelector(selector)[0];
2271         },
2272
2273         /*
2274         Property: getElementsBySelector
2275                 Same as <Element.getElements>, but allows for comma separated selectors, as in css. Alternate syntax for <$$>, where filter is the Element.
2276
2277         */
2278
2279         getElementsBySelector: function(selector){
2280                 var els = [];
2281                 selector.split(',').each(function(sel){
2282                         els.extend(this.getElements(sel));
2283                 }, this);
2284                 return $$(els);
2285         }
2286
2287 });
2288
2289 document.extend = Object.extend;
2290
2291 /* Section: document related functions */
2292
2293 document.extend({
2294         /*
2295         Function: document.getElementsByClassName 
2296                 Returns all the elements that match a specific class name. 
2297                 Here for compatibility purposes. can also be written: document.getElements('.className'), or $$('.className')
2298         */
2299
2300         getElementsByClassName: function(className){
2301                 return document.getElements('.'+className);
2302         },
2303         getElement: Element.prototype.getElement,
2304         getElements: Element.prototype.getElements,
2305         getElementsBySelector: Element.prototype.getElementsBySelector
2306
2307 });
2308
2309 /*
2310 Class: Elements
2311         Methods for dom queries arrays, as <$$>.
2312 */
2313
2314 Elements.extend({
2315
2316         //internal methods
2317
2318         filterById: function(id, tag){
2319                 var found = [];
2320                 this.each(function(el){
2321                         if (el.id == id) found.push(el);
2322                 });
2323                 return found;
2324         },
2325
2326         filterByClassName: function(className){
2327                 var found = [];
2328                 this.each(function(el){
2329                         if (Element.prototype.hasClass.call(el, className)) found.push(el);
2330                 });
2331                 return found;
2332         },
2333
2334         filterByTagName: function(tagName){
2335                 var found = [];
2336                 this.each(function(el){
2337                         found.extend(el.getElementsByTagName(tagName));
2338                 });
2339                 return found;
2340         },
2341
2342         filterByAttribute: function(name, value, operator){
2343                 var found = [];
2344                 this.each(function(el){
2345                         var att = el.getAttribute(name);
2346                         if (!att) return found;
2347                         if (!operator) return found.push(el);
2348
2349                         switch (operator){
2350                                 case '*=': if (att.test(value)) found.push(el); break;
2351                                 case '=': if (att == value) found.push(el); break;
2352                                 case '^=': if (att.test('^'+value)) found.push(el); break;
2353                                 case '$=': if (att.test(value+'$')) found.push(el);
2354                         }
2355                         return found;
2356                 });
2357                 return found;
2358         }
2359
2360 });
2361
2362 /*
2363 Script: Hash.js
2364         Contains the class Hash.
2365
2366 Author:
2367         Christophe Beyls <http://digitalia.be>
2368
2369 License:
2370         MIT-style license.
2371 */
2372
2373 /*
2374 Class: Hash
2375         It wraps an object that it uses internally as a map. The user must use put(), get(), and remove() to add/change, retrieve and remove values, it must not access the internal object directly. With this implementation, null values are not allowed.
2376
2377 Example:
2378         (start code)
2379         var hash = new Hash({a: 'hi', b: 'world', c: 'howdy'});
2380         hash.remove('b'); // b is removed.
2381         hash.set('c', 'hello');
2382         hash.get('c'); // returns 'hello'
2383         hash.length // returns 2 (a and b)
2384         (end)
2385 */
2386
2387 var Hash = new Class({
2388
2389         length: 0,
2390
2391         initialize: function(obj) {
2392                 this.obj = {};
2393                 for (var property in obj) {
2394                         this.obj[property] = obj[property];
2395                         this.length++;
2396                 }
2397         },
2398
2399         get: function(key) {
2400                 return this.obj[key];
2401         },
2402
2403         set: function(key, value) {
2404                 if (value == null) return false;
2405                 if (this.obj[key] == undefined) this.length++;
2406                 this.obj[key] = value;
2407                 return this;
2408         },
2409
2410         remove: function(key) {
2411                 if (this.obj[key] == undefined) return false;
2412                 var obj = {};
2413                 this.length--;
2414                 for (var property in this.obj){
2415                         if (property != key) obj[property] = this.obj[property];
2416                 }
2417                 this.obj = obj;
2418                 return this;
2419         },
2420
2421         each: function(fn, bind) {
2422                 for (var property in this.obj) fn.call(bind || this, property, this.obj[property]);
2423         },
2424         
2425         extend: function(obj){
2426                 this.initialize(Object.extend(this.obj, obj));
2427                 return this;
2428         },
2429
2430         empty: function() {
2431                 return (this.length == 0);
2432         },
2433
2434         keys: function() {
2435                 var keys = [];
2436                 for (var property in this.obj) keys.push(property);
2437                 return keys;
2438         },
2439
2440         values: function() {
2441                 var values = [];
2442                 for (var property in this.obj) values.push(this.obj[property]);
2443                 return values;
2444         }
2445
2446 });
2447
2448 /*
2449 Function: $H
2450         Shortcut to create an Hash from an Object.
2451 */
2452
2453 function $H(obj) {
2454         return new Hash(obj);
2455 };
2456
2457 /*
2458 Script: Color.js
2459         Contains the Color class.
2460
2461 Author:
2462         Michael Jackson <http://ajaxon.com/michael>
2463
2464 License:
2465         MIT-style license.
2466 */
2467
2468 /*
2469 Class: Color
2470         Creates a new Color Object, which is an array with some color specific methods.
2471
2472 Example:
2473         (start code)
2474         var black = new Color('#000');
2475         var purple = new Color([255,0,255]);
2476         // mix black with white and purple, each time at 10% of the new color
2477         var darkpurple = black.mix('#fff', purple, 10);
2478         $('myDiv').setStyle('background-color', darkpurple);
2479         (end)
2480 */
2481
2482 var Color = new Class({
2483
2484         initialize: function(color){
2485                 if (color.mix && color.invert) return color;
2486                 var rgb = (color.push) ? color : color.hexToRgb(true);
2487                 return Object.extend(rgb, Color.prototype);
2488         },
2489         
2490         mix: function(){
2491                 var colors = $A(arguments);
2492                 var alpha = 50;
2493                 if ($type(colors[colors.length-1]) == 'number') alpha = colors.pop();
2494                 var rgb = this.copy();
2495                 colors.each(function(color){
2496                         color = new Color(color);
2497                         for (var i = 0; i < 3; i++) rgb[i] = Math.round((rgb[i] / 100 * (100 - alpha)) + (color[i] / 100 * alpha));
2498                 });
2499                 return new Color(rgb);
2500         },
2501
2502         invert: function(){
2503                 var rgb = [];
2504                 for (var i = 0; i < 3; i++) rgb.push(255 - this[i]);
2505                 return new Color(rgb);
2506         }
2507
2508 });
2509
2510 function $C(color){
2511         return new Color(color);
2512 };
2513
2514 /*
2515 Script: Window.Base.js
2516         Contains Window.onDomReady and Window.disableImageCache
2517
2518 License:
2519         MIT-style license.
2520 */
2521
2522 /*
2523 Class: Window
2524         Cross browser methods to get the window size, onDomReady method.
2525 */
2526
2527 window.extend = Object.extend;
2528
2529 window.extend({
2530
2531         /*
2532         Function: window.disableImageCache
2533                 Disables background image chache for internex explorer, to prevent flickering. 
2534                 To be called if you have effects with background images, and they flicker.
2535
2536         Example:
2537                 Window.disableImageCache();
2538         */
2539
2540         disableImageCache: function(){
2541                 if (this.ie6) try {document.execCommand("BackgroundImageCache", false, true);} catch (e){};
2542         },
2543
2544         addEvent: function(type, fn){
2545                 if (type == 'domready'){
2546                         if (this.loaded) fn();
2547                         else if (!this.events || !this.events.domready){
2548                                 var domReady = function(){
2549                                         if (this.loaded) return;
2550                                         this.loaded = true;
2551                                         if (this.timer) this.timer = $clear(this.timer);
2552                                         Element.prototype.fireEvent.call(this, 'domready');
2553                                         this.events.domready = null;
2554                                 }.bind(this);
2555                                 if (document.readyState && this.khtml){ //safari and konqueror
2556                                         this.timer = function(){
2557                                                 if (['loaded','complete'].test(document.readyState)) domReady();
2558                                         }.periodical(50);
2559                                 }
2560                                 else if (document.readyState && this.ie){ //ie
2561                                         document.write("<script id=ie_ready defer src=javascript:void(0)><\/script>");
2562                                         $('ie_ready').onreadystatechange = function(){
2563                                                 if (this.readyState == 'complete') domReady();
2564                                         };
2565                                 } else { //others
2566                                         this.addEvent("load", domReady);
2567                                         document.addEvent("DOMContentLoaded", domReady);
2568                                 }
2569                         }
2570                 }
2571                 Element.prototype.addEvent.call(this, type, fn);
2572                 return this;
2573         },
2574
2575         /*
2576         Function: window.onDomReady
2577                 Executes the passed in function when the DOM is ready (when the document tree has loaded, not waiting for images).
2578                 Same as window.addEvent('domready', init);
2579
2580         Credits:
2581                 (c) Dean Edwards/Matthias Miller/John Resig, remastered for mootools. Later touched up by Christophe Beyls <http://digitalia.be>.
2582
2583         Arguments:
2584                 init - the function to execute when the DOM is ready
2585
2586         Example:
2587                 > window.addEvent('domready', function(){alert('the dom is ready')});
2588         */
2589
2590         onDomReady: function(init){
2591                 return this.addEvent('domready', init);
2592         }
2593
2594 });
2595
2596 /*
2597 Script: Window.Size.js
2598         Window cross-browser dimensions methods.
2599
2600 License:
2601         MIT-style license.
2602 */
2603
2604 /*
2605 Class: window
2606         Cross browser methods to get the window size, onDomReady method.
2607 */
2608
2609 window.extend({
2610
2611         /*
2612         Property: getWidth
2613                 Returns an integer representing the width of the browser.
2614         */
2615
2616         getWidth: function(){
2617                 if (this.khtml || this.opera) return this.innerWidth;
2618                 else return document.documentElement.clientWidth || document.body.clientWidth;
2619         },
2620
2621         /*
2622         Property: getHeight
2623                 Returns an integer representing the height of the browser.
2624         */
2625
2626         getHeight: function(){
2627                 if (this.khtml || this.opera) return this.innerHeight;
2628                 return document.documentElement.clientHeight || document.body.clientHeight;
2629         },
2630
2631         /*
2632         Property: getScrollHeight
2633                 Returns an integer representing the scrollHeight of the window.
2634
2635         See Also:
2636                 <http://developer.mozilla.org/en/docs/DOM:element.scrollHeight>
2637         */
2638
2639         getScrollHeight: function(){
2640                 return document.documentElement.scrollHeight;
2641         },
2642
2643         /*
2644         Property: getScrollWidth
2645                 Returns an integer representing the scrollWidth of the window.
2646
2647         See Also:
2648                 <http://developer.mozilla.org/en/docs/DOM:element.scrollWidth>
2649         */
2650
2651         getScrollWidth: function(){
2652                 return document.documentElement.scrollWidth;
2653         },
2654
2655         /*
2656         Property: getScrollTop
2657                 Returns an integer representing the scrollTop of the window (the number of pixels the window has scrolled from the top).
2658
2659         See Also:
2660                 <http://developer.mozilla.org/en/docs/DOM:element.scrollTop>
2661         */
2662
2663         getScrollTop: function(){
2664                 return this.pageYOffset || document.documentElement.scrollTop;
2665         },
2666
2667         /*
2668         Property: getScrollLeft
2669                 Returns an integer representing the scrollLeft of the window (the number of pixels the window has scrolled from the left).
2670
2671         See Also:
2672                 <http://developer.mozilla.org/en/docs/DOM:element.scrollLeft>
2673         */
2674
2675         getScrollLeft: function(){
2676                 return this.pageXOffset || document.documentElement.scrollLeft;
2677         },
2678
2679         /*
2680         Property: getSize
2681                 Same as <Element.getSize>
2682         */
2683
2684         getSize: function(){
2685                 return {
2686                         'scroll': {'x': this.getScrollLeft(), 'y': this.getScrollTop()},
2687                         'size': {'x': this.getWidth(), 'y': this.getHeight()},
2688                         'scrollSize': {'x': this.getScrollWidth(), 'y': this.getScrollHeight()}
2689                 };
2690         },
2691
2692         //ignore
2693         getOffsets: function(){return {'x': 0, 'y': 0}}
2694
2695 });
2696
2697 /*
2698 Script: Fx.Base.js
2699         Contains <Fx.Base> and two Transitions.
2700
2701 Author:
2702         Valerio Proietti, <http://mad4milk.net>
2703
2704 License:
2705         MIT-style license.
2706 */
2707
2708 var Fx = {};
2709
2710 /*
2711 Class: Fx.Base
2712         Base class for the Mootools Effects (Moo.Fx) library.
2713
2714 Options:
2715         onStart - the function to execute as the effect begins; nothing (<Class.empty>) by default.
2716         onComplete - the function to execute after the effect has processed; nothing (<Class.empty>) by default.
2717         transition - the equation to use for the effect see <Fx.Transitions>; default is <Fx.Transitions.sineInOut>
2718         duration - the duration of the effect in ms; 500 is the default.
2719         unit - the unit is 'px' by default (other values include things like 'em' for fonts or '%').
2720         wait - boolean: to wait or not to wait for a current transition to end before running another of the same instance. defaults to true.
2721         fps - the frames per second for the transition; default is 30
2722 */
2723
2724 Fx.Base = new Class({
2725
2726         getOptions: function(){
2727                 return {
2728                         onStart: Class.empty,
2729                         onComplete: Class.empty,
2730                         onCancel: Class.empty,
2731                         transition: Fx.Transitions.sineInOut,
2732                         duration: 500,
2733                         unit: 'px',
2734                         wait: true,
2735                         fps: 50
2736                 };
2737         },
2738
2739         initialize: function(options){
2740                 this.element = this.element || null;
2741                 this.setOptions(this.getOptions(), options);
2742                 if (this.options.initialize) this.options.initialize.call(this);
2743         },
2744
2745         step: function(){
2746                 var time = new Date().getTime();
2747                 if (time < this.time + this.options.duration){
2748                         this.cTime = time - this.time;
2749                         this.setNow();
2750                         this.increase();
2751                 } else {
2752                         this.stop(true);
2753                         this.now = this.to;
2754                         this.increase();
2755                         this.fireEvent('onComplete', this.element, 10);
2756                         this.callChain();
2757                 }
2758         },
2759
2760         /*
2761         Property: set
2762                 Immediately sets the value with no transition.
2763
2764         Arguments:
2765                 to - the point to jump to
2766
2767         Example:
2768                 >var myFx = new Fx.Style('myElement', 'opacity').set(0); //will make it immediately transparent
2769         */
2770
2771         set: function(to){
2772                 this.now = to;
2773                 this.increase();
2774                 return this;
2775         },
2776
2777         setNow: function(){
2778                 this.now = this.compute(this.from, this.to);
2779         },
2780
2781         compute: function(from, to){
2782                 return this.options.transition(this.cTime, from, (to - from), this.options.duration);
2783         },
2784
2785         /*
2786         Property: start
2787                 Executes an effect from one position to the other.
2788
2789         Arguments:
2790                 from - integer: staring value
2791                 to - integer: the ending value
2792
2793         Examples:
2794                 >var myFx = new Fx.Style('myElement', 'opacity').start(0,1); //display a transition from transparent to opaque.
2795         */
2796
2797         start: function(from, to){
2798                 if (!this.options.wait) this.stop();
2799                 else if (this.timer) return this;
2800                 this.from = from;
2801                 this.to = to;
2802                 this.time = new Date().getTime();
2803                 this.timer = this.step.periodical(Math.round(1000/this.options.fps), this);
2804                 this.fireEvent('onStart', this.element);
2805                 return this;
2806         },
2807
2808         /*
2809         Property: stop
2810                 Stops the transition.
2811         */
2812
2813         stop: function(end){
2814                 if (!this.timer) return this;
2815                 this.timer = $clear(this.timer);
2816                 if (!end) this.fireEvent('onCancel', this.element);
2817                 return this;
2818         },
2819
2820         //compat
2821         custom: function(from, to){return this.start(from, to)},
2822         clearTimer: function(end){return this.stop(end)}
2823
2824 });
2825
2826 Fx.Base.implement(new Chain);
2827 Fx.Base.implement(new Events);
2828 Fx.Base.implement(new Options);
2829
2830 /*
2831 Class: Fx.Transitions
2832         A collection of transition equations for use with the <Fx> Class.
2833
2834 See Also:
2835         <Fxtransitions.js> for a whole bunch of transitions.
2836
2837 Credits:
2838         Easing Equations, (c) 2003 Robert Penner (http://www.robertpenner.com/easing/), Open Source BSD License.
2839 */
2840
2841 Fx.Transitions = {
2842
2843         /* Property: linear */
2844         linear: function(t, b, c, d){
2845                 return c*t/d + b;
2846         },
2847
2848         /* Property: sineInOut */
2849         sineInOut: function(t, b, c, d){
2850                 return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
2851         }
2852
2853 };
2854
2855 /*
2856 Script: Fx.CSS.js
2857         Css parsing class for effects. Required by <Fx.Style>, <Fx.Styles>, <Fx.Elements>. No documentation needed, as its used internally.
2858
2859 Author:
2860         Christophe Beyls, <http://www.digitalia.be>,
2861         Valerio Proietti, <http://mad4milk.net>
2862
2863 License:
2864         MIT-style license.
2865 */
2866
2867 Fx.CSS = {
2868
2869         select: function(property, to){
2870                 if (property.test('color', 'i')) return this.Color;
2871                 if (to.test && to.test(' ')) return this.Multi;
2872                 return this.Single;
2873         },
2874
2875         parse: function(el, property, fromTo){
2876                 if (!fromTo.push) fromTo = [fromTo];
2877                 var from = fromTo[0], to = fromTo[1];
2878                 if (!to && to != 0){
2879                         to = from;
2880                         from = el.getStyle(property);
2881                 }
2882                 var css = this.select(property, to);
2883                 return {from: css.parse(from), to: css.parse(to), css: css};
2884         }
2885
2886 };
2887
2888 Fx.CSS.Single = {
2889
2890         parse: function(value){
2891                 return parseFloat(value);
2892         },
2893
2894         getNow: function(from, to, fx){
2895                 return fx.compute(from, to);
2896         },
2897
2898         getValue: function(value, unit){
2899                 return value+unit;
2900         }
2901
2902 };
2903
2904 Fx.CSS.Multi = {
2905
2906         parse: function(value){
2907                 return value.push ? value : value.split(' ').map(function(v){
2908                         return parseFloat(v);
2909                 });
2910         },
2911
2912         getNow: function(from, to, fx){
2913                 var now = [];
2914                 for (var i = 0; i < from.length; i++) now[i] = fx.compute(from[i], to[i]);
2915                 return now;
2916         },
2917
2918         getValue: function(value, unit){
2919                 return value.join(unit+' ')+unit;
2920         }
2921
2922 };
2923
2924 Fx.CSS.Color = {
2925
2926         parse: function(value){
2927                 return value.push ? value : value.hexToRgb(true);
2928         },
2929
2930         getNow: function(from, to, fx){
2931                 var now = [];
2932                 for (var i = 0; i < from.length; i++) now[i] = Math.round(fx.compute(from[i], to[i]));
2933                 return now;
2934         },
2935
2936         getValue: function(value){
2937                 return 'rgb('+value.join(',')+')';
2938         }
2939
2940 };
2941
2942 /*
2943 Script: Fx.Style.js
2944         Contains <Fx.Style>
2945
2946 Author:
2947         Valerio Proietti, <http://mad4milk.net>
2948
2949 License:
2950         MIT-style license.
2951 */
2952
2953 /*
2954 Class: Fx.Style
2955         The Style effect; Extends <Fx.Base>, inherits all its properties. Used to transition any css property from one value to another. Includes colors.
2956         Colors must be in hex format.
2957
2958 Arguments:
2959         el - the $(element) to apply the style transition to
2960         property - the property to transition
2961         options - the Fx.Base options (see: <Fx.Base>)
2962
2963 Example:
2964         >var marginChange = new Fx.Style('myElement', 'margin-top', {duration:500});
2965         >marginChange.start(10, 100);
2966 */
2967
2968 Fx.Style = Fx.Base.extend({
2969
2970         initialize: function(el, property, options){
2971                 this.element = $(el);
2972                 this.property = property;
2973                 this.parent(options);
2974         },
2975
2976         /*
2977         Property: hide
2978                 Same as <Fx.Base.set>(0)
2979         */
2980
2981         hide: function(){
2982                 return this.set(0);
2983         },
2984
2985         setNow: function(){
2986                 this.now = this.css.getNow(this.from, this.to, this);
2987         },
2988
2989         set: function(to){
2990                 this.css = Fx.CSS.select(this.property, to);
2991                 return this.parent(this.css.parse(to));
2992         },
2993
2994         /*
2995         Property: start
2996                 displays the transition to the value/values passed in
2997
2998         Example:
2999                 (start code)
3000                 var var marginChange = new Fx.Style('myElement', 'margin-top', {duration:500});
3001                 marginChange.start(10); //tries to read current margin top value and goes from current to 10
3002                 (end)
3003         */
3004
3005         start: function(from, to){
3006                 if (this.timer && this.options.wait) return this;
3007                 var parsed = Fx.CSS.parse(this.element, this.property, [from, to]);
3008                 this.css = parsed.css;
3009                 return this.parent(parsed.from, parsed.to);
3010         },
3011
3012         increase: function(){
3013                 this.element.setStyle(this.property, this.css.getValue(this.now, this.options.unit));
3014         }
3015
3016 });
3017
3018 /*
3019 Class: Element
3020         Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
3021 */
3022
3023 Element.extend({
3024
3025         /*
3026         Property: effect
3027                 Applies an <Fx.Style> to the Element; This a shortcut for <Fx.Style>.
3028
3029         Example:
3030                 >var myEffect = $('myElement').effect('height', {duration: 1000, transition: Fx.Transitions.linear});
3031                 >myEffect.start(10, 100);
3032         */
3033
3034         effect: function(property, options){
3035                 return new Fx.Style(this, property, options);
3036         }
3037
3038 });
3039
3040 /*
3041 Script: Fx.Styles.js
3042         Contains <Fx.Styles>
3043
3044 Author:
3045         Valerio Proietti, <http://mad4milk.net>
3046
3047 License:
3048         MIT-style license.
3049 */
3050
3051 /*
3052 Class: Fx.Styles
3053         Allows you to animate multiple css properties at once; Extends <Fx.Base>, inherits all its properties. Includes colors.
3054         Colors must be in hex format.
3055
3056 Arguments:
3057         el - the $(element) to apply the styles transition to
3058         options - the fx options (see: <Fx.Base>)
3059
3060 Example:
3061         (start code)
3062         var myEffects = new Fx.Styles('myElement', {duration: 1000, transition: Fx.Transitions.linear});
3063
3064         //height from 10 to 100 and width from 900 to 300
3065         myEffects.start({
3066                 'height': [10, 100],
3067                 'width': [900, 300]
3068         });
3069
3070         //or height from current height to 100 and width from current width to 300
3071         myEffects.start({
3072                 'height': 100,
3073                 'width': 300
3074         });
3075         (end)
3076 */
3077
3078 Fx.Styles = Fx.Base.extend({
3079
3080         initialize: function(el, options){
3081                 this.element = $(el);
3082                 this.parent(options);
3083         },
3084
3085         setNow: function(){
3086                 for (var p in this.from) this.now[p] = this.css[p].getNow(this.from[p], this.to[p], this);
3087         },
3088
3089         set: function(to){
3090                 var parsed = {};
3091                 this.css = {};
3092                 for (var p in to){
3093                         this.css[p] = Fx.CSS.select(p, to[p]);
3094                         parsed[p] = this.css[p].parse(to[p]);
3095                 }
3096                 return this.parent(parsed);
3097         },
3098
3099         /*
3100         Property: start
3101                 The function you'll actually use to execute a transition.
3102
3103         Arguments:
3104                 an object
3105
3106         Example:
3107                 see <Fx.Styles>
3108         */
3109
3110         start: function(obj){
3111                 if (this.timer && this.options.wait) return this;
3112                 this.now = {};
3113                 this.css = {};
3114                 var from = {}, to = {};
3115                 for (var p in obj){
3116                         var parsed = Fx.CSS.parse(this.element, p, obj[p]);
3117                         from[p] = parsed.from;
3118                         to[p] = parsed.to;
3119                         this.css[p] = parsed.css;
3120                 }
3121                 return this.parent(from, to);
3122         },
3123
3124         increase: function(){
3125                 for (var p in this.now) this.element.setStyle(p, this.css[p].getValue(this.now[p], this.options.unit));
3126         }
3127
3128 });
3129
3130 /*
3131 Class: Element
3132         Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
3133 */
3134
3135 Element.extend({
3136
3137         /*
3138         Property: effects
3139                 Applies an <Fx.Styles> to the Element; This a shortcut for <Fx.Styles>.
3140
3141         Example:
3142                 >var myEffects = $(myElement).effects({duration: 1000, transition: Fx.Transitions.sineInOut});
3143                 >myEffects.start({'height': [10, 100], 'width': [900, 300]});
3144         */
3145
3146         effects: function(options){
3147                 return new Fx.Styles(this, options);
3148         }
3149
3150 });
3151
3152 /*
3153 Script: Fx.Elements.js
3154         Contains <Fx.Elements>
3155
3156 Author:
3157         Valerio Proietti, <http://mad4milk.net>
3158
3159 License:
3160         MIT-style license.
3161 */
3162
3163 /*
3164 Class: Fx.Elements
3165         Fx.Elements allows you to apply any number of styles transitions to a selection of elements. Includes colors (must be in hex format).
3166
3167 Arguments:
3168         elements - a collection of elements the effects will be applied to.
3169         options - same as <Fx.Base> options.
3170 */
3171
3172 Fx.Elements = Fx.Base.extend({
3173
3174         initialize: function(elements, options){
3175                 this.elements = $$(elements);
3176                 this.parent(options);
3177         },
3178
3179         setNow: function(){
3180                 for (var i in this.from){
3181                         var iFrom = this.from[i], iTo = this.to[i], iCss = this.css[i], iNow = this.now[i] = {};
3182                         for (var p in iFrom) iNow[p] = iCss[p].getNow(iFrom[p], iTo[p], this);
3183                 }
3184         },
3185
3186         set: function(to){
3187                 var parsed = {};
3188                 this.css = {};
3189                 for (var i in to){
3190                         var iTo = to[i], iCss = this.css[i] = {}, iParsed = parsed[i] = {};
3191                         for (var p in iTo){
3192                                 iCss[p] = Fx.CSS.select(p, iTo[p]);
3193                                 iParsed[p] = iCss[p].parse(iTo[p]);
3194                         }
3195                 }
3196                 return this.parent(parsed);
3197         },
3198
3199         /*
3200         Property: start
3201                 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.
3202
3203         Example:
3204                 (start code)
3205                 var myElementsEffects = new Fx.Elements($$('a'));
3206                 myElementsEffects.start({
3207                         '0': { //let's change the first element's opacity and width
3208                                 'opacity': [0,1],
3209                                 'width': [100,200]
3210                         },
3211                         '1': { //and the second one's opacity
3212                                 'opacity': [0.2, 0.5]
3213                         }
3214                 });
3215                 (end)
3216         */
3217
3218         start: function(obj){
3219                 if (this.timer && this.options.wait) return this;
3220                 this.now = {};
3221                 this.css = {};
3222                 var from = {}, to = {};
3223                 for (var i in obj){
3224                         var iProps = obj[i], iFrom = from[i] = {}, iTo = to[i] = {}, iCss = this.css[i] = {};
3225                         for (var p in iProps){
3226                                 var parsed = Fx.CSS.parse(this.elements[i], p, iProps[p]);
3227                                 iFrom[p] = parsed.from;
3228                                 iTo[p] = parsed.to;
3229                                 iCss[p] = parsed.css;
3230                         }
3231                 }
3232                 return this.parent(from, to);
3233         },
3234
3235         increase: function(){
3236                 for (var i in this.now){
3237                         var iNow = this.now[i], iCss = this.css[i];
3238                         for (var p in iNow) this.elements[i].setStyle(p, iCss[p].getValue(iNow[p], this.options.unit));
3239                 }
3240         }
3241
3242 });
3243
3244 /*
3245 Script: Fx.Scroll.js
3246         Contains <Fx.Scroll>
3247
3248 Author:
3249         Valerio Proietti, <http://mad4milk.net>
3250
3251 License:
3252         MIT-style license.
3253 */
3254
3255 /*
3256 Class: Fx.Scroll
3257         Scroll any element with an overflow, including the window element.
3258
3259 Arguments:
3260         element - the element to scroll
3261         options - same as <Fx.Base> options.
3262 */
3263
3264 Fx.Scroll = Fx.Base.extend({
3265
3266         initialize: function(element, options){
3267                 this.now = [];
3268                 this.element = $(element);
3269                 this.addEvent('onStart', function(){
3270                         this.element.addEvent('mousewheel', this.stop.bind(this, false));
3271                 }.bind(this));
3272                 this.removeEvent('onComplete', function(){
3273                         this.element.removeEvent('mousewheel', this.stop.bind(this, false));
3274                 }.bind(this));
3275                 this.parent(options);
3276         },
3277
3278         setNow: function(){
3279                 for (var i = 0; i < 2; i++) this.now[i] = this.compute(this.from[i], this.to[i]);
3280         },
3281
3282         /*
3283         Property: scrollTo
3284                 Scrolls the chosen element to the x/y coordinates.
3285
3286         Arguments:
3287                 x - the x coordinate to scroll the element to
3288                 y - the y coordinate to scroll the element to
3289         */
3290
3291         scrollTo: function(x, y){
3292                 if (this.timer && this.options.wait) return this;
3293                 var el = this.element.getSize();
3294                 var values = {'x': x, 'y': y};
3295                 for (var z in el.size){
3296                         var max = el.scrollSize[z] - el.size[z];
3297                         if ($chk(values[z])) values[z] = ($type(values[z]) == 'number') ? Math.max(Math.min(values[z], max), 0) : max;
3298                         else values[z] = el.scroll[z];
3299                 }
3300                 return this.start([el.scroll.x, el.scroll.y], [values.x, values.y]);
3301         },
3302
3303         /*
3304         Property: toTop
3305                 Scrolls the chosen element to its maximum top.
3306         */
3307
3308         toTop: function(){
3309                 return this.scrollTo(false, 0);
3310         },
3311
3312         /*
3313         Property: toBottom
3314                 Scrolls the chosen element to its maximum bottom.
3315         */
3316
3317         toBottom: function(){
3318                 return this.scrollTo(false, 'full');
3319         },
3320
3321         /*
3322         Property: toLeft
3323                 Scrolls the chosen element to its maximum left.
3324         */
3325
3326         toLeft: function(){
3327                 return this.scrollTo(0, false);
3328         },
3329
3330         /*
3331         Property: toRight
3332                 Scrolls the chosen element to its maximum right.
3333         */
3334
3335         toRight: function(){
3336                 return this.scrollTo('full', false);
3337         },
3338
3339         /*
3340         Property: toElement
3341                 Scrolls the specified element to the position the passed in element is found. Only usable if the chosen element is == window.
3342
3343         Arguments:
3344                 el - the $(element) to scroll the window to
3345         */
3346
3347         toElement: function(el){
3348                 return this.scrollTo($(el).getLeft(), $(el).getTop());
3349         },
3350
3351         increase: function(){
3352                 this.element.scrollTo(this.now[0], this.now[1]);
3353         }
3354
3355 });
3356
3357 /*
3358 Script: Fx.Slide.js
3359         Contains <Fx.Slide>
3360
3361 Author:
3362         Valerio Proietti, <http://mad4milk.net>
3363
3364 License:
3365         MIT-style license.
3366 */
3367
3368 /*
3369 Class: Fx.Slide
3370         The slide effect; slides an element in horizontally or vertically, the contents will fold inside. Extends <Fx.Base>, inherits all its properties.
3371
3372 Note:
3373         This effect works on any block element, but the element *cannot be positioned*; no margins or absolute positions. To position the element, put it inside another element (a wrapper div, for instance) and position that instead.
3374
3375 Options:
3376         mode - set it to vertical or horizontal. Defaults to vertical.
3377         and all the <Fx.Base> options
3378
3379 Example:
3380         (start code)
3381         var mySlider = new Fx.Slide('myElement', {duration: 500});
3382         mySlider.toggle() //toggle the slider up and down.
3383         (end)
3384 */
3385
3386 Fx.Slide = Fx.Base.extend({
3387
3388         initialize: function(el, options){
3389                 this.element = $(el).setStyle('margin', 0);
3390                 this.wrapper = new Element('div').injectAfter(this.element).setStyle('overflow', 'hidden').adopt(this.element);
3391                 this.setOptions({'mode': 'vertical'}, options);
3392                 this.now = [];
3393                 this.parent(this.options);
3394         },
3395
3396         setNow: function(){
3397                 for (var i = 0; i < 2; i++) this.now[i] = this.compute(this.from[i], this.to[i]);
3398         },
3399
3400         vertical: function(){
3401                 this.margin = 'top';
3402                 this.layout = 'height';
3403                 this.offset = this.element.offsetHeight;
3404                 return [this.element.getStyle('margin-top').toInt(), this.wrapper.getStyle('height').toInt()];
3405         },
3406
3407         horizontal: function(){
3408                 this.margin = 'left';
3409                 this.layout = 'width';
3410                 this.offset = this.element.offsetWidth;
3411                 return [this.element.getStyle('margin-left').toInt(), this.wrapper.getStyle('width').toInt()];
3412         },
3413
3414         /*
3415         Property: slideIn
3416                 slides the elements in view horizontally or vertically, depending on the mode parameter or options.mode.
3417         */
3418
3419         slideIn: function(mode){
3420                 return this.start(this[mode || this.options.mode](), [0, this.offset]);
3421         },
3422
3423         /*
3424         Property: slideOut
3425                 slides the elements out of the view horizontally or vertically, depending on the mode parameter or options.mode.
3426         */
3427
3428         slideOut: function(mode){
3429                 return this.start(this[mode || this.options.mode](), [-this.offset, 0]);
3430         },
3431
3432         /*
3433         Property: hide
3434                 Hides the element without a transition.
3435         */
3436
3437         hide: function(mode){
3438                 this[mode || this.options.mode]();
3439                 return this.set([-this.offset, 0]);
3440         },
3441
3442         /*
3443         Property: show
3444                 Shows the element without a transition.
3445         */
3446
3447         show: function(mode){
3448                 this[mode || this.options.mode]();
3449                 return this.set([0, this.offset]);
3450         },
3451
3452         /*
3453         Property: toggle
3454                 Slides in or Out the element, depending on its state
3455         */
3456
3457         toggle: function(mode){
3458                 if (this.wrapper.offsetHeight == 0 || this.wrapper.offsetWidth == 0) return this.slideIn(mode);
3459                 else return this.slideOut(mode);
3460         },
3461
3462         increase: function(){
3463                 this.element.setStyle('margin-'+this.margin, this.now[0]+this.options.unit);
3464                 this.wrapper.setStyle(this.layout, this.now[1]+this.options.unit);
3465         }
3466
3467 });
3468
3469 /*
3470 Script: Fx.Transitions.js
3471         Cool transitions, to be used with all the effects.
3472
3473 Author:
3474         Robert Penner, <http://www.robertpenner.com/easing/>, modified to be used with mootools.
3475
3476 License:
3477         Easing Equations v1.5, (c) 2003 Robert Penner, all rights reserved. Open Source BSD License.
3478 */
3479
3480 /*
3481 Class: Fx.Transitions
3482         A collection of tweaning transitions for use with the <Fx.Base> classes.
3483 */
3484
3485 Fx.Transitions = {
3486
3487         /* Property: linear */
3488         linear: function(t, b, c, d){
3489                 return c*t/d + b;
3490         },
3491
3492         /* Property: quadIn */
3493         quadIn: function(t, b, c, d){
3494                 return c*(t/=d)*t + b;
3495         },
3496
3497         /* Property: quatOut */
3498         quadOut: function(t, b, c, d){
3499                 return -c *(t/=d)*(t-2) + b;
3500         },
3501
3502         /* Property: quadInOut */
3503         quadInOut: function(t, b, c, d){
3504                 if ((t/=d/2) < 1) return c/2*t*t + b;
3505                 return -c/2 * ((--t)*(t-2) - 1) + b;
3506         },
3507
3508         /* Property: cubicIn */
3509         cubicIn: function(t, b, c, d){
3510                 return c*(t/=d)*t*t + b;
3511         },
3512
3513         /* Property: cubicOut */
3514         cubicOut: function(t, b, c, d){
3515                 return c*((t=t/d-1)*t*t + 1) + b;
3516         },
3517
3518         /* Property: cubicInOut */
3519         cubicInOut: function(t, b, c, d){
3520                 if ((t/=d/2) < 1) return c/2*t*t*t + b;
3521                 return c/2*((t-=2)*t*t + 2) + b;
3522         },
3523
3524         /* Property: quartIn */
3525         quartIn: function(t, b, c, d){
3526                 return c*(t/=d)*t*t*t + b;
3527         },
3528
3529         /* Property: quartOut */
3530         quartOut: function(t, b, c, d){
3531                 return -c * ((t=t/d-1)*t*t*t - 1) + b;
3532         },
3533
3534         /* Property: quartInOut */
3535         quartInOut: function(t, b, c, d){
3536                 if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
3537                 return -c/2 * ((t-=2)*t*t*t - 2) + b;
3538         },
3539
3540         /* Property: quintIn */
3541         quintIn: function(t, b, c, d){
3542                 return c*(t/=d)*t*t*t*t + b;
3543         },
3544
3545         /* Property: quintOut */
3546         quintOut: function(t, b, c, d){
3547                 return c*((t=t/d-1)*t*t*t*t + 1) + b;
3548         },
3549
3550         /* Property: quintInOut */
3551         quintInOut: function(t, b, c, d){
3552                 if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
3553                 return c/2*((t-=2)*t*t*t*t + 2) + b;
3554         },
3555
3556         /* Property: sineIn */
3557         sineIn: function(t, b, c, d){
3558                 return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
3559         },
3560
3561         /* Property: sineOut */
3562         sineOut: function(t, b, c, d){
3563                 return c * Math.sin(t/d * (Math.PI/2)) + b;
3564         },
3565
3566         /* Property: sineInOut */
3567         sineInOut: function(t, b, c, d){
3568                 return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
3569         },
3570
3571         /* Property: expoIn */
3572         expoIn: function(t, b, c, d){
3573                 return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
3574         },
3575
3576         /* Property: expoOut */
3577         expoOut: function(t, b, c, d){
3578                 return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
3579         },
3580
3581         /* Property: expoInOut */
3582         expoInOut: function(t, b, c, d){
3583                 if (t==0) return b;
3584                 if (t==d) return b+c;
3585                 if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
3586                 return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
3587         },
3588
3589         /* Property: circIn */
3590         circIn: function(t, b, c, d){
3591                 return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
3592         },
3593
3594         /* Property: circOut */
3595         circOut: function(t, b, c, d){
3596                 return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
3597         },
3598
3599         /* Property: circInOut */
3600         circInOut: function(t, b, c, d){
3601                 if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
3602                 return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
3603         },
3604
3605         /* Property: elasticIn */
3606         elasticIn: function(t, b, c, d, a, p){
3607                 if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; if (!a) a = 1;
3608                 if (a < Math.abs(c)){ a=c; var s=p/4; }
3609                 else var s = p/(2*Math.PI) * Math.asin(c/a);
3610                 return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
3611         },
3612
3613         /* Property: elasticOut */
3614         elasticOut: function(t, b, c, d, a, p){
3615                 if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; if (!a) a = 1;
3616                 if (a < Math.abs(c)){ a=c; var s=p/4; }
3617                 else var s = p/(2*Math.PI) * Math.asin(c/a);
3618                 return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
3619         },
3620
3621         /* Property: elasticInOut */
3622         elasticInOut: function(t, b, c, d, a, p){
3623                 if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); if (!a) a = 1;
3624                 if (a < Math.abs(c)){ a=c; var s=p/4; }
3625                 else var s = p/(2*Math.PI) * Math.asin(c/a);
3626                 if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
3627                 return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
3628         },
3629
3630         /* Property: backIn */
3631         backIn: function(t, b, c, d, s){
3632                 if (!s) s = 1.70158;
3633                 return c*(t/=d)*t*((s+1)*t - s) + b;
3634         },
3635
3636         /* Property: backOut */
3637         backOut: function(t, b, c, d, s){
3638                 if (!s) s = 1.70158;
3639                 return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
3640         },
3641
3642         /* Property: backInOut */
3643         backInOut: function(t, b, c, d, s){
3644                 if (!s) s = 1.70158;
3645                 if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
3646                 return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
3647         },
3648
3649         /* Property: bounceIn */
3650         bounceIn: function(t, b, c, d){
3651                 return c - Fx.Transitions.bounceOut (d-t, 0, c, d) + b;
3652         },
3653
3654         /* Property: bounceOut */
3655         bounceOut: function(t, b, c, d){
3656                 if ((t/=d) < (1/2.75)){
3657                         return c*(7.5625*t*t) + b;
3658                 } else if (t < (2/2.75)){
3659                         return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
3660                 } else if (t < (2.5/2.75)){
3661                         return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
3662                 } else {
3663                         return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
3664                 }
3665         },
3666
3667         /* Property: bounceInOut */
3668         bounceInOut: function(t, b, c, d){
3669                 if (t < d/2) return Fx.Transitions.bounceIn(t*2, 0, c, d) * .5 + b;
3670                 return Fx.Transitions.bounceOut(t*2-d, 0, c, d) * .5 + c*.5 + b;
3671         }
3672
3673 };
3674
3675 /*
3676 Script: Drag.Base.js
3677         Contains <Drag.Base>, <Element.makeResizable>
3678
3679 Author:
3680         Valerio Proietti, <http://mad4milk.net>
3681
3682 License:
3683         MIT-style license.
3684 */
3685
3686 var Drag = {};
3687
3688 /*
3689 Class: Drag.Base
3690         Modify two css properties of an element based on the position of the mouse.
3691
3692 Arguments:
3693         el - the $(element) to apply the transformations to.
3694         options - optional. The options object.
3695
3696 Options:
3697         handle - the $(element) to act as the handle for the draggable element. defaults to the $(element) itself.
3698         modifiers - an object. see Modifiers Below.
3699         onStart - optional, function to execute when the user starts to drag (on mousedown);
3700         onComplete - optional, function to execute when the user completes the drag.
3701         onDrag - optional, function to execute at every step of the drag
3702         limit - an object, see Limit below.
3703         snap - optional, the distance you have to drag before the element starts to respond to the drag. defaults to false
3704
3705         modifiers:
3706                 x - string, the style you want to modify when the mouse moves in an horizontal direction. defaults to 'left'
3707                 y - string, the style you want to modify when the mouse moves in a vertical direction. defaults to 'top'
3708
3709         limit:
3710                 x - array with start and end limit relative to modifiers.x
3711                 y - array with start and end limit relative to modifiers.y
3712 */
3713
3714 Drag.Base = new Class({
3715
3716         getOptions: function(){
3717                 return {
3718                         handle: false,
3719                         unit: 'px',
3720                         onStart: Class.empty, 
3721                         onComplete: Class.empty,
3722                         onSnap: Class.empty,
3723                         onDrag: Class.empty,
3724                         limit: false,
3725                         modifiers: {x: 'left', y: 'top'},
3726                         snap: 6
3727                 };
3728         },
3729
3730         initialize: function(el, options){
3731                 this.setOptions(this.getOptions(), options);
3732                 this.element = $(el);
3733                 this.handle = $(this.options.handle) || this.element;
3734                 this.mouse = {'now': {}, 'pos': {}};
3735                 this.value = {'start': {}, 'now': {}};
3736                 this.bound = {'start': this.start.bindWithEvent(this)};
3737                 this.handle.addEvent('mousedown', this.bound.start);
3738                 if (this.options.initialize) this.options.initialize.call(this);
3739         },
3740
3741         start: function(event){
3742                 this.mouse.start = event.page;
3743                 var limit = this.options.limit;
3744                 this.limit = {'x': [], 'y': []};
3745                 for (var z in this.options.modifiers){
3746                         this.value.now[z] = this.element.getStyle(this.options.modifiers[z]).toInt();
3747                         this.mouse.pos[z] = event.page[z] - this.value.now[z];
3748                         if (limit && limit[z]){
3749                                 for (var i = 0; i < 2; i++){
3750                                         if ($chk(limit[z][i])) this.limit[z][i] = limit[z][i].apply ? limit[z][i].call(this) : limit[z][i];
3751                                 }
3752                         }
3753                 }
3754                 this.bound.drag = this.drag.bindWithEvent(this);
3755                 this.bound.checkAndDrag = this.checkAndDrag.bindWithEvent(this);
3756                 this.bound.stop = this.stop.bind(this);
3757                 document.addEvent('mousemove', this.options.snap ? this.bound.checkAndDrag : this.bound.drag);
3758                 document.addEvent('mouseup', this.bound.stop);
3759                 this.fireEvent('onStart', this.element);
3760                 event.stop();
3761         },
3762
3763         checkAndDrag: function(event){
3764                 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)));
3765                 if (distance > this.options.snap){
3766                         document.removeEvent('mousemove', this.bound.checkAndDrag);
3767                         document.addEvent('mousemove', this.bound.drag);
3768                         this.drag(event);
3769                         this.fireEvent('onSnap', this.element);
3770                 }
3771                 event.stop();
3772         },
3773
3774         drag: function(event){
3775                 this.out = false;
3776                 this.mouse.now = event.page;
3777                 for (var z in this.options.modifiers){
3778                         this.value.now[z] = event.page[z] - this.mouse.pos[z];
3779                         if (this.limit[z]){
3780                                 if ($chk(this.limit[z][1]) && (this.value.now[z] > this.limit[z][1])){
3781                                         this.value.now[z] = this.limit[z][1];
3782                                         this.out = true;
3783                                 } else if ($chk(this.limit[z][0]) && (this.value.now[z] < this.limit[z][0])){
3784                                         this.value.now[z] = this.limit[z][0];
3785                                         this.out = true;
3786                                 }
3787                         }
3788                         this.element.setStyle(this.options.modifiers[z], this.value.now[z] + this.options.unit);
3789                 }
3790                 this.fireEvent('onDrag', this.element);
3791                 event.stop();
3792         },
3793         
3794         detach: function(){
3795                 this.handle.removeEvent('mousedown', this.bound.start);
3796         },
3797
3798         stop: function(){
3799                 document.removeEvent('mousemove', this.bound.drag);
3800                 document.removeEvent('mouseup', this.bound.stop);
3801                 this.fireEvent('onComplete', this.element);
3802         }
3803
3804 });
3805
3806 Drag.Base.implement(new Events);
3807 Drag.Base.implement(new Options);
3808
3809 /*
3810 Class: Element
3811         Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
3812 */
3813
3814 Element.extend({
3815
3816         /*
3817         Property: makeResizable
3818                 Makes an element resizable (by dragging) with the supplied options.
3819
3820         Arguments:
3821                 options - see <Drag.Base> for acceptable options.
3822         */
3823
3824         makeResizable: function(options){
3825                 return new Drag.Base(this, Object.extend(options || {}, {modifiers: {x: 'width', y: 'height'}}));
3826         }
3827
3828 });
3829
3830 /*
3831 Script: Scroller.js
3832         Contains the <Scroller>.
3833
3834 Author:
3835         Valerio Proietti, <http://mad4milk.net>
3836
3837 License:
3838         MIT-style license.
3839 */
3840
3841 /*
3842 Class: Scroller
3843         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.
3844         You must call its start method to start listening to mouse movements.
3845
3846 Arguments:
3847         element - required, the element to scroll.
3848         options - optional, see options below, and <Fx.Base> options.
3849
3850 Options:
3851         area - integer, the necessary boundaries to make the element scroll.
3852         velocity - integer, velocity ratio, the modifier for the window scrolling speed.
3853         onChange - optionally, when the mouse reaches some boundaries, you can choose to alter some other values, instead of the scrolling offsets.
3854                 Automatically passes as parameters x and y values.
3855 */
3856
3857 var Scroller = new Class({
3858
3859         getOptions: function(){
3860                 return {
3861                         area: 20,
3862                         velocity: 1,
3863                         onChange: function(x, y){
3864                                 this.element.scrollTo(x, y);
3865                         }
3866                 };
3867         },
3868
3869         initialize: function(element, options){
3870                 this.setOptions(this.getOptions(), options);
3871                 this.element = $(element);
3872                 this.mousemover = ([window, document].test(element)) ? $(document.body) : this.element;
3873         },
3874
3875         /*
3876         Property: start
3877                 The scroller starts listening to mouse movements.
3878         */
3879
3880         start: function(){
3881                 this.coord = this.getCoords.bindWithEvent(this);
3882                 this.mousemover.addEvent('mousemove', this.coord);
3883         },
3884
3885         /*
3886         Property: stop
3887                 The scroller stops listening to mouse movements.
3888         */
3889
3890         stop: function(){
3891                 this.mousemover.removeEvent('mousemove', this.coord);
3892                 this.timer = $clear(this.timer);
3893         },
3894
3895         getCoords: function(event){
3896                 this.page = (this.element == window) ? event.client : event.page;
3897                 if (!this.timer) this.timer = this.scroll.periodical(50, this);
3898         },
3899
3900         scroll: function(){
3901                 var el = this.element.getSize();
3902                 var pos = this.element.getOffsets();
3903
3904                 var change = {'x': 0, 'y': 0};
3905                 for (var z in this.page){
3906                         if (this.page[z] < (this.options.area + pos[z]) && el.scroll[z] != 0)
3907                                 change[z] = (this.page[z] - this.options.area - pos[z]) * this.options.velocity;
3908                         else if (this.page[z] + this.options.area > (el.size[z] + pos[z]) && el.scroll[z] + el.size[z] != el.scrollSize[z])
3909                                 change[z] = (this.page[z] - el.size[z] + this.options.area - pos[z]) * this.options.velocity;
3910                 }
3911                 if (change.y || change.x) this.fireEvent('onChange', [el.scroll.x + change.x, el.scroll.y + change.y]);
3912         }
3913
3914 });
3915
3916 Scroller.implement(new Events);
3917 Scroller.implement(new Options);
3918
3919 /*
3920 Script: Slider.js
3921         Contains <Slider>
3922
3923 Author:
3924         Valerio Proietti, <http://mad4milk.net>
3925
3926 License:
3927         MIT-style license.
3928 */
3929
3930 /*
3931 Class: Slider
3932         Creates a slider with two elements: a knob and a container. Returns the values.
3933
3934 Arguments:
3935         element - the knob container
3936         knob - the handle
3937         options - see Options below
3938
3939 Options:
3940         onChange - a function to fire when the value changes.
3941         onComplete - a function to fire when you're done dragging.
3942         onTick - optionally, you can alter the onTick behavior, for example displaying an effect of the knob moving to the desired position. 
3943                 Passes as parameter the new position.
3944         steps - the number of steps for your slider.
3945         mode - either 'horizontal' or 'vertical'. defaults to horizontal.
3946         wheel - experimental! Also use the mouse wheel to control the slider. defaults to false.
3947 */
3948
3949 var Slider = new Class({
3950
3951         getOptions: function(){
3952                 return {
3953                         onChange: Class.empty,
3954                         onComplete: Class.empty,
3955                         onTick: function(pos){
3956                                 this.knob.setStyle(this.p, pos+'px');
3957                         },
3958                         steps: 100,
3959                         mode: 'horizontal',
3960                         wheel: false
3961                 };
3962         },
3963
3964         initialize: function(el, knob, options){
3965                 this.element = $(el);
3966                 this.knob = $(knob);
3967                 this.setOptions(this.getOptions(), options);
3968
3969                 this.previousChange = -1;
3970                 this.previousEnd = -1;
3971                 this.step = -1;
3972
3973                 this.element.addEvent('mousedown', this.clickedElement.bindWithEvent(this));
3974
3975                 if (this.options.wheel) this.element.addEvent('mousewheel', this.scrolledElement.bindWithEvent(this));
3976
3977                 if (this.options.mode == 'horizontal'){
3978                         this.z = 'x'; this.p = 'left';
3979                         this.max = this.element.offsetWidth-this.knob.offsetWidth;
3980                         this.half = this.knob.offsetWidth/2;
3981                         this.getPos = this.element.getLeft.bind(this.element);
3982                 } else if (this.options.mode == 'vertical'){
3983                         this.z = 'y'; this.p = 'top';
3984                         this.max = this.element.offsetHeight-this.knob.offsetHeight;
3985                         this.half = this.knob.offsetHeight/2;
3986                         this.getPos = this.element.getTop.bind(this.element);
3987                 }
3988
3989                 this.knob.setStyle('position', 'relative').setStyle(this.p, 0);
3990
3991                 var modSlide = {}, limSlide = {};
3992
3993                 limSlide[this.z] = [0, this.max];
3994                 modSlide[this.z] = this.p;
3995
3996                 this.drag = new Drag.Base(this.knob, {
3997                         limit: limSlide,
3998                         snap: 0,
3999                         modifiers: modSlide,
4000                         onStart: function(){
4001                                 this.draggedKnob();
4002                         }.bind(this),
4003                         onDrag: function(){
4004                                 this.draggedKnob();
4005                         }.bind(this),
4006                         onComplete: function(){
4007                                 this.draggedKnob();
4008                                 this.end();
4009                         }.bind(this)
4010                 });
4011                 if (this.options.initialize) this.options.initialize.call(this);
4012         },
4013
4014         /*
4015         Property: set
4016                 The slider will get the step you pass.
4017
4018         Arguments:
4019                 step - one integer
4020         */
4021
4022         set: function(step){
4023                 if (step > this.options.steps) step = this.options.steps;
4024                 else if (step < 0) step = 0;
4025                 this.step = step;
4026                 this.checkStep();
4027                 this.end();
4028                 this.fireEvent('onTick', this.toPosition(this.step)+'');
4029                 return this;
4030         },
4031
4032         scrolledElement: function(event){
4033                 if (event.wheel < 0) this.set(this.step + 1);
4034                 else if (event.wheel > 0) this.set(this.step - 1);
4035                 event.stop();
4036         },
4037
4038         clickedElement: function(event){
4039                 var position = event.page[this.z] - this.getPos() - this.half;
4040                 if (position > this.max) position = this.max;
4041                 else if (position < 0) position = 0;
4042                 this.step = this.toStep(position);
4043                 this.checkStep();
4044                 this.end();
4045                 this.fireEvent('onTick', position+'');
4046         },
4047
4048         draggedKnob: function(){
4049                 this.step = this.toStep(this.drag.value.now[this.z]);
4050                 this.checkStep();
4051         },
4052
4053         checkStep: function(){
4054                 if (this.previousChange != this.step){
4055                         this.previousChange = this.step;
4056                         this.fireEvent('onChange', this.step);
4057                 }
4058         },
4059
4060         end: function(){
4061                 if (this.previousEnd !== this.step){
4062                         this.previousEnd = this.step;
4063                         this.fireEvent('onComplete', this.step+'');
4064                 }
4065         },
4066
4067         toStep: function(position){
4068                 return Math.round(position/this.max*this.options.steps);
4069         },
4070
4071         toPosition: function(step){
4072                 return (this.max)*step/this.options.steps;
4073         }
4074
4075 });
4076
4077 Slider.implement(new Events);
4078 Slider.implement(new Options);