3 My Object Oriented javascript.
6 Valerio Proietti, <http://mad4milk.net>
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.
19 The base class object of the <http://mootools.net> framework.
22 properties - the collection of properties that apply to the class. Creates a new class, its initialize method will fire upon class instantiation.
27 initialize: function(name){
31 var myCat = new Cat('Micia');
32 alert myCat.name; //alerts 'Micia'
36 var Class = function(properties){
37 var klass = function(){
38 if (this.initialize && arguments[0] != 'noinit') return this.initialize.apply(this, arguments);
41 for (var property in this) klass[property] = this[property];
42 klass.prototype = properties;
48 Returns an empty function
51 Class.empty = function(){};
57 Returns the copy of the Class extended with the passed in properties.
60 properties - the properties to add to the base class in this new Class.
64 var Animal = new Class({
65 initialize: function(age){
69 var Cat = Animal.extend({
70 initialize: function(name, age){
71 this.parent(age); //will call the previous initialize;
75 var myCat = new Cat('Micia', 20);
76 alert myCat.name; //alerts 'Micia'
77 alert myCat.age; //alerts 20
81 extend: function(properties){
82 var pr0t0typ3 = new this('noinit');
84 var parentize = function(previous, current){
85 if (!previous.apply || !current.apply) return false;
87 this.parent = previous;
88 return current.apply(this, arguments);
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;
98 return new Class(pr0t0typ3);
103 Implements the passed in properties to the base Class prototypes, altering the base class, unlike <Class.extend>.
106 properties - the properties to add to the base class.
110 var Animal = new Class({
111 initialize: function(age){
116 setName: function(name){
120 var myAnimal = new Animal(20);
121 myAnimal.setName('Micia');
122 alert(myAnimal.name); //alerts 'Micia'
126 implement: function(properties){
127 for (var property in properties) this.prototype[property] = properties[property];
132 /* Section: Object related Functions */
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.
150 Object.extend(firstOb, secondOb);
151 //firstOb will become:
154 'lastName': 'Dorian',
161 The first object, extended.
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];
172 Function: Object.Native
173 Will add a .extend method to the objects passed as a parameter, equivalent to <Class.implement>
176 a number of classes/native javascript objects
180 Object.Native = function(){
181 for (var i = 0; i < arguments.length; i++) arguments[i].extend = Class.prototype.implement;
184 new Object.Native(Function, Array, String, Number, Class);
188 Contains Utility functions
191 Valerio Proietti, <http://mad4milk.net>
197 //htmlelement mapping
199 if (typeof HTMLElement == 'undefined'){
200 var HTMLElement = Class.empty;
201 HTMLElement.prototype = {};
206 Returns the type of object that matches the element passed in.
209 obj - the object to inspect.
212 >var myString = 'hello';
213 >$type(myString); //returns "string"
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.
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';
235 switch (obj.nodeType){
236 case 1: return 'element';
237 case 3: return obj.nodeValue.test('\\S') ? 'textnode' : 'whitespace';
246 Returns true if the passed in value/object exists or is 0, otherwise returns false.
247 Useful to accept zeroes.
251 return !!(obj || obj === 0);
256 Returns the first object if defined, otherwise returns the second.
259 function $pick(obj, picked){
260 return ($type(obj)) ? obj : picked;
265 Returns a random integer number between the two passed in values.
268 min - integer, the minimum value (inclusive).
269 max - integer, the maximum value (inclusive).
272 a random integer between min and max.
275 function $random(min, max){
276 return Math.floor(Math.random() * (max - min + 1) + min);
281 clears a timeout or an Interval.
287 timer - the setInterval or setTimeout to clear.
290 >var myTimer = myFunction.delay(5000); //wait 5 seconds and execute my function.
291 >myTimer = $clear(myTimer); //nevermind
294 <Function.delay>, <Function.periodical>
297 function $clear(timer){
299 clearInterval(timer);
303 /* Section: Browser Detection */
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.
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;
320 Contains Array prototypes and the function <$A>;
323 Valerio Proietti, <http://mad4milk.net>
331 A collection of The Array Object prototype methods.
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>
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);
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>
352 Array.prototype.map = Array.prototype.map || function(fn, bind){
354 for (var i = 0; i < this.length; i++) results[i] = fn.call(bind, this[i], i, this);
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>
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;
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>
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;
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>
390 Array.prototype.indexOf = Array.prototype.indexOf || function(item, from){
392 if (from < 0) from = Math.max(0, this.length + from);
393 while (from < this.length){
394 if(this[from] === item) return from;
406 Same as <Array.forEach>.
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.
413 >var Animals = ['Cat', 'Dog', 'Coala'];
414 >Animals.forEach(function(animal){
415 > document.write(animal)
419 each: Array.prototype.forEach,
423 Copy the array and returns it.
429 >var letters = ["a","b","c"];
430 >var copy = ["a","b","c"].copy();
435 for (var i = 0; i < this.length; i++) newArray[i] = this[i];
441 Removes all occurrences of an item from the array.
444 item - the item to remove
447 the Array with all occurrences of the item removed.
450 >["1","2","3","2"].remove("2") // ["1","3"];
453 remove: function(item){
455 while (i < this.length){
456 if (this[i] == item) this.splice(i, 1);
464 Tests an array for the presence of an item.
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.
471 true - the item was found
475 >["a","b","c"].test("a"); // true
476 >["a","b","c"].test("d"); // false
479 test: function(item, from){
480 return this.indexOf(item, from) != -1;
485 Extends an array with another
488 newArray - the array to extend ours with
491 >var Animals = ['Cat', 'Dog', 'Coala'];
492 >Animals.extend(['Lizard']);
493 >//Animals is now: ['Cat', 'Dog', 'Coala', 'Lizard'];
496 extend: function(newArray){
497 for (var i = 0; i < newArray.length; i++) this.push(newArray[i]);
503 Creates an object with key-value pairs based on the array of keywords passed in
504 and the current content of the array.
507 keys - the array of keywords.
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.
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];
528 /* Section: Utility Functions */
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.
537 function myFunction(){
538 $A(arguments).each(argument, function(){
542 //the above will alert all the arguments passed to the function myFunction.
547 return Array.prototype.copy.call(array);
552 use to iterate through iterables that are not regular arrays, such as builtin getElementsByTagName calls, or arguments of a function.
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.
560 function $each(iterable, fn, bind){
561 return Array.prototype.forEach.call(iterable, fn, bind);
566 Contains String prototypes and Number prototypes.
569 Valerio Proietti, <http://mad4milk.net>
577 A collection of The String Object prototype methods.
584 Tests a string with a regular expression.
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)
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>
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
600 test: function(regex, params){
601 return new RegExp(regex, params).test(this);
606 parses a string to an integer.
609 either an int or "NaN" if the string is not a number.
612 >var value = "10px".toInt(); // value is 10
616 return parseInt(this);
620 return parseFloat(this);
625 Converts a hiphenated string to a camelcase string.
628 >"I-like-cookies".camelCase(); //"ILikeCookies"
631 the camel cased string
634 camelCase: function(){
635 return this.replace(/-\D/g, function(match){
636 return match.charAt(1).toUpperCase();
642 Converts a camelCased string to a hyphen-ated string.
645 >"ILikeCookies".hyphenate(); //"I-like-cookies"
648 hyphenate: function(){
649 return this.replace(/\w[A-Z]/g, function(match){
650 return (match.charAt(0)+'-'+match.charAt(1).toLowerCase());
656 Converts the first letter in each word of a string to Uppercase.
659 >"i like cookies".capitalize(); //"I Like Cookies"
662 the capitalized string
665 capitalize: function(){
666 return this.toLowerCase().replace(/\b[a-z]/g, function(match){
667 return match.toUpperCase();
673 Trims the leading and trailing spaces off a string.
676 >" i like cookies ".trim() //"i like cookies"
683 return this.replace(/^\s+|\s+$/g, '');
688 trims (<String.trim>) a string AND removes all the double spaces in a string.
694 >" i like cookies \n\n".clean() //"i like cookies"
698 return this.replace(/\s{2,}/g, ' ').trim();
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)";
706 array - boolean value, defaults to false. Use true if you want the array ['FF', '33', '00'] as output instead of #FF3300
709 hex string or array. returns transparent if the fourth value of rgba in input string is 0,
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]
717 rgbToHex: function(array){
718 var rgb = this.match(/\d{1,3}/g);
719 return (rgb) ? rgb.rgbToHex(array) : false;
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');
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)";
733 >"#112233".hexToRgb(); //"rgb(17,34,51)"
734 >"#112233".hexToRgb(true); //[17,34,51]
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;
746 rgbToHex: function(array){
747 if (this.length < 3) return false;
748 if (this[3] && this[3] == 0) return 'transparent';
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);
754 return array ? hex : '#'+hex.join('');
757 hexToRgb: function(array){
758 if (this.length != 4) return false;
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));
764 return array ? rgb : 'rgb('+rgb.join(',')+')';
771 contains the internal method toInt.
778 Returns this number; useful because toInt must work on both Strings and Numbers.
782 return parseInt(this);
786 return parseFloat(this);
793 Contains Function prototypes and utility functions .
796 Valerio Proietti, <http://mad4milk.net>
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
807 A collection of The Function Object prototype methods.
812 create: function(options){
814 options = Object.extend({
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;
827 event = (options.event === true) ? event || window.event : new options.event(event);
828 args = [event].concat(args);
830 var returns = function(){
831 return fn.apply(options.bind, args);
833 if (options.delay) return setTimeout(returns, options.delay);
834 if (options.periodical) return setInterval(returns, options.periodical);
835 if (options.attempt){
837 var result = returns();
843 } else return returns();
849 Shortcut to create closures with arguments and bind.
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.
859 >myFunction.pass([arg1, arg2], myElement);
862 pass: function(args, bind){
863 return this.create({'arguments': args, 'bind': bind});
868 Tries to execute the function, returns either the function results or the error.
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.
875 >myFunction.attempt([arg1, arg2], myElement);
878 attempt: function(args, bind){
879 return this.create({'arguments': args, 'bind': bind, 'attempt': true})();
884 method to easily create closures with "this" altered.
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
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
899 >var myBoundFunction = myFunction.bind(myElement);
900 >myBoundFunction(); // this will make the element myElement red.
903 bind: function(bind, args){
904 return this.create({'bind': bind, 'arguments': args});
908 Property: bindAsEventListener
909 cross browser method to pass event firer
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
916 a function with the parameter bind as its "this" and as a pre-passed argument event or window.event, depending on the browser.
919 >function myFunction(event){
920 > alert(event.clientx) //returns the coordinates of the mouse..
922 >myElement.onclick = myFunction.bindAsEventListener(myElement);
925 bindAsEventListener: function(bind, args){
926 return this.create({'bind': bind, 'event': true, 'arguments': args});
931 Delays the execution of a function by a specified duration.
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
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
943 delay: function(ms, bind, args){
944 return this.create({'delay': ms, 'bind': bind, 'arguments': args})();
949 Executes a function in the specified intervals of time
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
957 periodical: function(ms, bind, args){
958 return this.create({'periodical': ms, 'bind': bind, 'arguments': args})();
965 Contains useful Element prototypes, to be used with the dollar function <$>.
968 Valerio Proietti, <http://mad4milk.net>
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
979 Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
982 var Element = new Class({
986 Creates a new element of the type passed in.
989 el - the tag name for the element you wish to create.
992 >var div = new Element('div');
995 initialize: function(el){
996 if ($type(el) == 'string') el = document.createElement(el);
1004 returns the element passed in with all the Element prototypes applied.
1007 el - a reference to an actual element or a string representing the id of an element
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.
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().
1018 a DOM element or false (if no id was found).
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.
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);
1040 var Elements = new Class({});
1042 new Object.Native(Elements);
1044 document.getElementsBySelector = document.getElementsByTagName;
1048 Selects, and extends DOM elements.
1051 HTMLCollection(document.getElementsByTagName, element.childNodes), an array of elements, a string.
1054 if you loaded <Dom.js>, $$ will also accept CSS Selectors.
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>)
1063 array - array of all the dom elements matched
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];
1073 $each(arguments, function(selector){
1074 switch ($type(selector)){
1075 case 'element': elements.push($(selector)); break;
1076 case 'string': selector = document.getElementsBySelector(selector);
1078 if (selector.length){
1079 $each(selector, function(el){
1080 if ($(el)) elements.push(el);
1085 elements._elements_extended_ = true;
1086 return Object.extend(elements, new Elements);
1089 Elements.Multi = function(property){
1091 var args = arguments;
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);
1099 if (elements) items = $$(items);
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);
1114 inject: function(el, where){
1115 el = $(el) || new Element(el);
1117 case "before": $(el.parentNode).insertBefore(this, el); break;
1119 if (!el.getNext()) $(el.parentNode).appendChild(this);
1120 else $(el.parentNode).insertBefore(this, el.getNext());
1122 case "inside": el.appendChild(this);
1128 Property: injectBefore
1129 Inserts the Element before the passed element.
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.
1137 ><div id="myElement"></div>
1138 ><div id="mySecondElement"></div>
1140 >$('mySecondElement').injectBefore('myElement');
1142 ><div id="mySecondElement"></div>
1143 ><div id="myElement"></div>
1147 injectBefore: function(el){
1148 return this.inject(el, 'before');
1152 Property: injectAfter
1153 Same as <Element.injectBefore>, but inserts the element after.
1156 injectAfter: function(el){
1157 return this.inject(el, 'after');
1161 Property: injectInside
1162 Same as <Element.injectBefore>, but inserts the element inside.
1165 injectInside: function(el){
1166 return this.inject(el, 'inside');
1171 Inserts the passed element inside the Element. Works as <Element.injectInside> but in reverse.
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.
1178 adopt: function(el){
1179 this.appendChild($(el) || new Element(el));
1185 Removes the Element from the DOM.
1188 >$('myElement').remove() //bye bye
1192 this.parentNode.removeChild(this);
1198 Clones the Element and returns the cloned one.
1204 >var clone = $('myElement').clone().injectAfter('myElement');
1205 >//clones the Element and append the clone after the Element.
1208 clone: function(contents){
1209 var el = this.cloneNode(contents !== false);
1214 Property: replaceWith
1215 Replaces the Element with an element passed.
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.
1222 the passed in element
1225 >$('myOldElement').replaceWith($('myNewElement')); //$('myOldElement') is gone, and $('myNewElement') is in its place.
1228 replaceWith: function(el){
1229 el = $(el) || new Element(el);
1230 this.parentNode.replaceChild(el, this);
1235 Property: appendText
1236 Appends text node to a DOM element.
1239 text - the text to append.
1242 ><div id="myElement">hey</div>
1243 >$('myElement').appendText(' howdy'); //myElement innerHTML is now "hey howdy"
1246 appendText: function(text){
1248 switch(this.getTag()){
1249 case 'style': this.styleSheet.cssText = text; return this;
1250 case 'script': this.setProperty('text', text); return this;
1253 this.appendChild(document.createTextNode(text));
1259 Tests the Element to see if it has the passed in className.
1262 true - the Element has the class
1266 className - the class name to test.
1269 ><div id="myElement" class="testClass"></div>
1270 >$('myElement').hasClass('testClass'); //returns true
1273 hasClass: function(className){
1274 return this.className.test('(?:^|\\s+)' + className + '(?:\\s+|$)');
1279 Adds the passed in class to the Element, if the element doesnt already have it.
1282 className - the class name to add
1285 ><div id="myElement" class="testClass"></div>
1286 >$('myElement').addClass('newClass'); //<div id="myElement" class="testClass newClass"></div>
1289 addClass: function(className){
1290 if (!this.hasClass(className)) this.className = (this.className+' '+className).clean();
1295 Property: removeClass
1296 works like <Element.addClass>, but removes the class from the element.
1299 removeClass: function(className){
1300 if (this.hasClass(className)) this.className = this.className.replace(className, '').clean();
1305 Property: toggleClass
1306 Adds or removes the passed in class name to the element, depending on if it's present or not.
1309 className - the class to add or remove
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>
1319 toggleClass: function(className){
1320 return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
1325 Sets a css property to the Element.
1328 property - the property to set
1329 value - the value to which to set it
1332 >$('myElement').setStyle('width', '300px'); //the width is now 300px
1335 setStyle: function(property, value){
1336 if (property == 'opacity') this.setOpacity(parseFloat(value));
1337 else this.style[property.camelCase()] = (value.push) ? value.rgbToHex() : value;
1343 Applies a collection of styles to the Element.
1346 source - an object or string containing all the styles to apply
1349 >$('myElement').setStyles({
1350 > border: '1px solid #000',
1357 >$('myElement').setStyle('border: 1px solid #000; width: 300px; height: 400px;');
1360 setStyles: function(source){
1361 switch ($type(source)){
1363 for (var property in source) this.setStyle(property, source[property]);
1366 if (window.ie) this.cssText = source;
1367 else this.setAttribute('style', source);
1373 Property: setOpacity
1374 Sets the opacity of the Element, and sets also visibility == "hidden" if opacity == 0, and visibility = "visible" if opacity == 1.
1377 opacity - Accepts numbers from 0 to 1.
1380 >$('myElement').setOpacity(0.5) //make it 50% transparent
1383 setOpacity: function(opacity){
1385 if(this.style.visibility != "hidden") this.style.visibility = "hidden";
1387 if(this.style.visibility != "visible") this.style.visibility = "visible";
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;
1397 Returns the style of the Element given the property passed in.
1400 property - the css style property you want to retrieve
1403 >$('myElement').getStyle('width'); //returns "400px"
1404 >//but you can also use
1405 >$('myElement').getStyle('width').toInt(); //returns "400"
1408 the style as a string
1411 getStyle: function(property){
1412 property = property.camelCase();
1413 var style = this.style[property] || false;
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(' ');
1420 if (document.defaultView) style = document.defaultView.getComputedStyle(this, null).getPropertyValue(property.hyphenate());
1421 else if (this.currentStyle) style = this.currentStyle[property];
1423 return (style && property.test('color', 'i') && style.test('rgb')) ? style.rgbToHex() : style;
1428 Attaches an event listener to a DOM element.
1431 type - the event to monitor ('click', 'load', etc) without the prefix 'on'.
1432 fn - the function to execute
1435 >$('myElement').addEvent('click', function(){alert('clicked!')});
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);
1447 this.attachEvent('on'+type, fn);
1448 this.events[type].values.push(fn);
1454 addEvents: function(source){
1456 for (var type in source) this.addEvent(type, source[type]);
1462 Property: removeEvent
1463 Works as Element.addEvent, but instead removes the previously added event listener.
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);
1474 this.detachEvent('on'+type, this.events[type].values.splice(pos,1)[0]);
1481 Property: removeEvents
1482 removes all events of a certain type from an element. if no argument is passed in, removes all events.
1485 removeEvents: function(type){
1488 if (this.events[type]){
1489 this.events[type].keys.each(function(fn){
1490 this.removeEvent(type, fn);
1492 this.events[type] = null;
1495 for (var evType in this.events) this.removeEvents(evType);
1504 executes all events of the specified type present in the element.
1507 fireEvent: function(type, args){
1508 if (this.events && this.events[type]){
1510 if ($type(args) != 'array') args = [args];
1511 this.events[type].keys.each(function(fn){
1512 fn.apply(this, args);
1517 getBrother: function(what){
1518 var el = this[what+'Sibling'];
1519 while ($type(el) == 'whitespace') el = el[what+'Sibling'];
1524 Property: getPrevious
1525 Returns the previousSibling of the Element, excluding text nodes.
1528 >$('myElement').getPrevious(); //get the previous DOM element from myElement
1531 the sibling element or undefined if none found.
1534 getPrevious: function(){
1535 return this.getBrother('previous');
1540 Works as Element.getPrevious, but tries to find the nextSibling.
1543 getNext: function(){
1544 return this.getBrother('next');
1549 Works as <Element.getPrevious>, but tries to find the firstChild.
1552 getFirst: function(){
1553 var el = this.firstChild;
1554 while ($type(el) == 'whitespace') el = el.nextSibling;
1560 Works as <Element.getPrevious>, but tries to find the lastChild.
1563 getLast: function(){
1564 var el = this.lastChild;
1565 while ($type(el) == 'whitespace') el = el.previousSibling;
1571 returns the $(element.parentNode)
1574 getParent: function(){
1575 return $(this.parentNode);
1579 Property: getChildren
1580 returns all the $(element.childNodes), excluding text nodes. Returns as <Elements>.
1583 getChildren: function(){
1584 return $$(this.childNodes);
1588 Property: setProperty
1589 Sets an attribute for the Element.
1592 property - the property to assign the value passed in
1593 value - the value to assign to the property passed in
1596 >$('myImage').setProperty('src', 'whatever.gif'); //myImage now points to whatever.gif for its source
1599 setProperty: function(property, value){
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);
1608 if (this.parentNode) this.replaceWith(el);
1611 default: this.setAttribute(property, value);
1617 Property: setProperties
1618 Sets numerous attributes for the Element.
1621 source - an object with key/value pairs.
1624 >$('myElement').setProperties({
1625 > src: 'whatever.gif',
1626 > alt: 'whatever dude'
1628 ><img src="whatever.gif" alt="whatever dude">
1631 setProperties: function(source){
1632 for (var property in source) this.setProperty(property, source[property]);
1638 Sets the innerHTML of the Element.
1641 html - the new innerHTML for the element.
1644 >$('myElement').setHTML(newHTML) //the innerHTML of myElement is now = newHTML
1647 setHTML: function(html){
1648 this.innerHTML = html;
1653 Property: getProperty
1654 Gets the an attribute of the Element.
1657 property - the attribute to retrieve
1660 >$('myImage').getProperty('src') // returns whatever.gif
1663 the value, or an empty string
1666 getProperty: function(property){
1667 return (property == 'class') ? this.className : this.getAttribute(property);
1672 Returns the tagName of the element in lower case.
1675 >$('myImage').getTag() // returns 'img'
1678 The tag name in lower case
1682 return this.tagName.toLowerCase();
1685 getOffsets: function(){
1686 var el = this, offsetLeft = 0, offsetTop = 0;
1688 offsetLeft += el.offsetLeft || 0;
1689 offsetTop += el.offsetTop || 0;
1690 el = el.offsetParent;
1692 return {'x': offsetLeft, 'y': offsetTop};
1697 scrolls the element to the specified coordinated (if the element has an overflow)
1700 x - the x coordinate
1701 y - the y coordinate
1704 >$('myElement').scrollTo(0, 100)
1707 scrollTo: function(x, y){
1708 this.scrollLeft = x;
1714 return an Object representing the size/scroll values of the element.
1718 $('myElement').getSize();
1724 'scroll': {'x': 100, 'y': 100},
1725 'size': {'x': 200, 'y': 400},
1726 'scrollSize': {'x': 300, 'y': 500}
1731 getSize: function(){
1733 'scroll': {'x': this.scrollLeft, 'y': this.scrollTop},
1734 'size': {'x': this.offsetWidth, 'y': this.offsetHeight},
1735 'scrollSize': {'x': this.scrollWidth, 'y': this.scrollHeight}
1741 Returns the distance from the top of the window to the Element.
1745 return this.getOffsets().y;
1750 Returns the distance from the left of the window to the Element.
1753 getLeft: function(){
1754 return this.getOffsets().x;
1758 Property: getPosition
1759 Returns an object with width, height, left, right, top, and bottom, representing the values of the Element
1763 var myValues = $('myElement').getPosition();
1779 getPosition: function(){
1780 var offs = this.getOffsets();
1782 'width': this.offsetWidth,
1783 'height': this.offsetHeight,
1787 obj.right = obj.left + obj.width;
1788 obj.bottom = obj.top + obj.height;
1794 Returns the value of the Element, if its tag is textarea, select or input. no multiple select support.
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;
1808 var Window = window;
1810 window.addEvent = document.addEvent = Element.prototype.addEvent;
1811 window.removeEvent = document.removeEvent = Element.prototype.removeEvent;
1817 collect: function(element){
1818 Garbage.elements.push(element);
1822 window.removeEvent('unload', Garbage.trash);
1823 Garbage.elements.each(function(el){
1825 for (var p in Element.prototype) HTMLElement[p] = window[p] = document[p] = el[p] = null;
1832 window.addEvent('unload', Garbage.trash);
1839 Valerio Proietti, <http://mad4milk.net>, Michael Jackson, <http://ajaxon.com/michael>
1847 Cross browser methods to manage events.
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
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');
1878 var Event = new Class({
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;
1896 this.key = special || String.fromCharCode(this.code).toLowerCase();
1898 } else if (this.type.test('mouse') || this.type == 'click'){
1900 'x': this.event.pageX || this.event.clientX + document.documentElement.scrollLeft,
1901 'y': this.event.pageY || this.event.clientY + document.documentElement.scrollTop
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
1907 this.rightClick = (this.event.which == 3) || (this.event.button == 2);
1909 case 'mouseover': this.relatedTarget = this.event.relatedTarget || this.event.fromElement; break;
1910 case 'mouseout': this.relatedTarget = this.event.relatedTarget || this.event.toElement;
1917 cross browser method to stop an event
1921 this.stopPropagation();
1922 this.preventDefault();
1927 Property: stopPropagation
1928 cross browser method to stop the propagation of an event
1931 stopPropagation: function(){
1932 if (this.event.stopPropagation) this.event.stopPropagation();
1933 else this.event.cancelBubble = true;
1938 Property: preventDefault
1939 cross browser method to prevent the default action of the event
1942 preventDefault: function(){
1943 if (this.event.preventDefault) this.event.preventDefault();
1944 else this.event.returnValue = false;
1965 Property: bindWithEvent
1966 automatically passes mootools Event Class.
1969 bind - optional, the object that the "this" of the function will refer to.
1972 a function with the parameter bind as its "this" and as a pre-passed argument event or window.event, depending on the browser.
1975 >function myFunction(event){
1976 > alert(event.clientx) //returns the coordinates of the mouse..
1978 >myElement.onclick = myFunction.bindWithEvent(myElement);
1981 bindWithEvent: function(bind, args){
1982 return this.create({'bind': bind, 'arguments': args, 'event': Event});
1990 Contains common implementations for custom classes. In Mootools is implemented in <Ajax> and <Fx>.
1993 Valerio Proietti, <http://mad4milk.net>
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.
2007 var myFx = new Fx.Style('element', 'opacity');
2009 myFx.start(1,0).chain(function(){
2011 }).chain(function(){
2013 }).chain(function(){
2016 //the element will appear and disappear three times
2020 var Chain = new Class({
2024 adds a function to the Chain instance stack.
2027 fn - the function to append.
2030 chain: function(fn){
2031 this.chains = this.chains || [];
2032 this.chains.push(fn);
2038 Executes the first function of the Chain instance stack, then removes it. The first function will then become the second.
2041 callChain: function(){
2042 if (this.chains && this.chains.length) this.chains.splice(0, 1)[0].delay(10, this);
2046 Property: clearChain
2047 Clears the stack of a Chain instance.
2050 clearChain: function(){
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
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');
2070 //upon completion it will display the 2 alerts, in order.
2074 var Events = new Class({
2078 adds an event to the stack of events of the Class instance.
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);
2092 fires all events of the specified type in the Class instance.
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})();
2105 Property: removeEvent
2106 removes an event from the stack of events of the Class instance.
2109 removeEvent: function(type, fn){
2110 if (this.events && this.events[type]) this.events[type].remove(fn);
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.
2122 var Options = new Class({
2125 Property: setOptions
2129 defaults - the default set of options
2130 options - the user entered options. can be empty too.
2133 if your Class has <Events> implemented, every option beginning with on, followed by a capital letter (onComplete) becomes an Class instance event.
2136 setOptions: function(defaults, options){
2137 this.options = Object.extend(defaults, options);
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]);
2150 Css Query related function and <Element> extensions
2153 Valerio Proietti, <http://mad4milk.net>
2159 /* Section: Utility Functions */
2163 Selects a single (i.e. the first found) Element based on the selector passed in and an optional filter element.
2166 selector - the css selector to match
2167 filter - optional; a DOM element to limit the scope of the selector match; defaults to document.
2170 >$E('a', 'myElement') //find the first anchor tag inside the DOM element with id 'myElement'
2173 a DOM element - the first element that matches the selector
2176 function $E(selector, filter){
2177 return ($(filter) || document).getElement(selector);
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.
2186 an array of dom elements that match the selector within the filter
2189 selector - css selector to match
2190 filter - optional; a DOM element to limit the scope of the selector match; defaults to document.
2193 >$ES("a") //gets all the anchor tags; synonymous with $$("a")
2194 >$ES('a','myElement') //get all the anchor tags within $('myElement')
2197 function $ES(selector, filter){
2198 return ($(filter) || document).getElementsBySelector(selector);
2203 Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
2209 Property: getElements
2210 Gets all the elements within an element that match the given (single) selector.
2213 selector - the css selector to match
2216 >$('myElement').getElements('a'); // get all anchors within myElement
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.
2222 getElements: function(selector){
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;
2228 param[1] = param[1] || '*';
2231 var el = this.getElementById(param[2]);
2232 if (!el || ((param[1] != '*') && (Element.prototype.getTag.call(el) != param[1]))) return;
2235 filters = $A(this.getElementsByTagName(param[1]));
2238 filters = Elements.prototype.filterByTagName.call(filters, param[1]);
2239 if (param[2]) filters = Elements.prototype.filterById.call(filters, param[2]);
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]);
2248 Property: getElementById
2249 Targets an element with the specified id found inside the Element. Does not overwrite document.getElementById.
2252 id - the id of the element to find.
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;
2265 Property: getElement
2266 Same as <Element.getElements>, but returns only the first. Alternate syntax for <$E>, where filter is the Element.
2269 getElement: function(selector){
2270 return this.getElementsBySelector(selector)[0];
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.
2279 getElementsBySelector: function(selector){
2281 selector.split(',').each(function(sel){
2282 els.extend(this.getElements(sel));
2289 document.extend = Object.extend;
2291 /* Section: document related functions */
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')
2300 getElementsByClassName: function(className){
2301 return document.getElements('.'+className);
2303 getElement: Element.prototype.getElement,
2304 getElements: Element.prototype.getElements,
2305 getElementsBySelector: Element.prototype.getElementsBySelector
2311 Methods for dom queries arrays, as <$$>.
2318 filterById: function(id, tag){
2320 this.each(function(el){
2321 if (el.id == id) found.push(el);
2326 filterByClassName: function(className){
2328 this.each(function(el){
2329 if (Element.prototype.hasClass.call(el, className)) found.push(el);
2334 filterByTagName: function(tagName){
2336 this.each(function(el){
2337 found.extend(el.getElementsByTagName(tagName));
2342 filterByAttribute: function(name, value, operator){
2344 this.each(function(el){
2345 var att = el.getAttribute(name);
2346 if (!att) return found;
2347 if (!operator) return found.push(el);
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);
2364 Contains the class Hash.
2367 Christophe Beyls <http://digitalia.be>
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.
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)
2387 var Hash = new Class({
2391 initialize: function(obj) {
2393 for (var property in obj) {
2394 this.obj[property] = obj[property];
2399 get: function(key) {
2400 return this.obj[key];
2403 set: function(key, value) {
2404 if (value == null) return false;
2405 if (this.obj[key] == undefined) this.length++;
2406 this.obj[key] = value;
2410 remove: function(key) {
2411 if (this.obj[key] == undefined) return false;
2414 for (var property in this.obj){
2415 if (property != key) obj[property] = this.obj[property];
2421 each: function(fn, bind) {
2422 for (var property in this.obj) fn.call(bind || this, property, this.obj[property]);
2425 extend: function(obj){
2426 this.initialize(Object.extend(this.obj, obj));
2431 return (this.length == 0);
2436 for (var property in this.obj) keys.push(property);
2440 values: function() {
2442 for (var property in this.obj) values.push(this.obj[property]);
2450 Shortcut to create an Hash from an Object.
2454 return new Hash(obj);
2459 Contains the Color class.
2462 Michael Jackson <http://ajaxon.com/michael>
2470 Creates a new Color Object, which is an array with some color specific methods.
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);
2482 var Color = new Class({
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);
2491 var colors = $A(arguments);
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));
2499 return new Color(rgb);
2504 for (var i = 0; i < 3; i++) rgb.push(255 - this[i]);
2505 return new Color(rgb);
2511 return new Color(color);
2515 Script: Window.Base.js
2516 Contains Window.onDomReady and Window.disableImageCache
2524 Cross browser methods to get the window size, onDomReady method.
2527 window.extend = Object.extend;
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.
2537 Window.disableImageCache();
2540 disableImageCache: function(){
2541 if (this.ie6) try {document.execCommand("BackgroundImageCache", false, true);} catch (e){};
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;
2551 if (this.timer) this.timer = $clear(this.timer);
2552 Element.prototype.fireEvent.call(this, 'domready');
2553 this.events.domready = null;
2555 if (document.readyState && this.khtml){ //safari and konqueror
2556 this.timer = function(){
2557 if (['loaded','complete'].test(document.readyState)) domReady();
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();
2566 this.addEvent("load", domReady);
2567 document.addEvent("DOMContentLoaded", domReady);
2571 Element.prototype.addEvent.call(this, type, fn);
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);
2581 (c) Dean Edwards/Matthias Miller/John Resig, remastered for mootools. Later touched up by Christophe Beyls <http://digitalia.be>.
2584 init - the function to execute when the DOM is ready
2587 > window.addEvent('domready', function(){alert('the dom is ready')});
2590 onDomReady: function(init){
2591 return this.addEvent('domready', init);
2597 Script: Window.Size.js
2598 Window cross-browser dimensions methods.
2606 Cross browser methods to get the window size, onDomReady method.
2613 Returns an integer representing the width of the browser.
2616 getWidth: function(){
2617 if (this.khtml || this.opera) return this.innerWidth;
2618 else return document.documentElement.clientWidth || document.body.clientWidth;
2623 Returns an integer representing the height of the browser.
2626 getHeight: function(){
2627 if (this.khtml || this.opera) return this.innerHeight;
2628 return document.documentElement.clientHeight || document.body.clientHeight;
2632 Property: getScrollHeight
2633 Returns an integer representing the scrollHeight of the window.
2636 <http://developer.mozilla.org/en/docs/DOM:element.scrollHeight>
2639 getScrollHeight: function(){
2640 return document.documentElement.scrollHeight;
2644 Property: getScrollWidth
2645 Returns an integer representing the scrollWidth of the window.
2648 <http://developer.mozilla.org/en/docs/DOM:element.scrollWidth>
2651 getScrollWidth: function(){
2652 return document.documentElement.scrollWidth;
2656 Property: getScrollTop
2657 Returns an integer representing the scrollTop of the window (the number of pixels the window has scrolled from the top).
2660 <http://developer.mozilla.org/en/docs/DOM:element.scrollTop>
2663 getScrollTop: function(){
2664 return this.pageYOffset || document.documentElement.scrollTop;
2668 Property: getScrollLeft
2669 Returns an integer representing the scrollLeft of the window (the number of pixels the window has scrolled from the left).
2672 <http://developer.mozilla.org/en/docs/DOM:element.scrollLeft>
2675 getScrollLeft: function(){
2676 return this.pageXOffset || document.documentElement.scrollLeft;
2681 Same as <Element.getSize>
2684 getSize: function(){
2686 'scroll': {'x': this.getScrollLeft(), 'y': this.getScrollTop()},
2687 'size': {'x': this.getWidth(), 'y': this.getHeight()},
2688 'scrollSize': {'x': this.getScrollWidth(), 'y': this.getScrollHeight()}
2693 getOffsets: function(){return {'x': 0, 'y': 0}}
2699 Contains <Fx.Base> and two Transitions.
2702 Valerio Proietti, <http://mad4milk.net>
2712 Base class for the Mootools Effects (Moo.Fx) library.
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
2724 Fx.Base = new Class({
2726 getOptions: function(){
2728 onStart: Class.empty,
2729 onComplete: Class.empty,
2730 onCancel: Class.empty,
2731 transition: Fx.Transitions.sineInOut,
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);
2746 var time = new Date().getTime();
2747 if (time < this.time + this.options.duration){
2748 this.cTime = time - this.time;
2755 this.fireEvent('onComplete', this.element, 10);
2762 Immediately sets the value with no transition.
2765 to - the point to jump to
2768 >var myFx = new Fx.Style('myElement', 'opacity').set(0); //will make it immediately transparent
2778 this.now = this.compute(this.from, this.to);
2781 compute: function(from, to){
2782 return this.options.transition(this.cTime, from, (to - from), this.options.duration);
2787 Executes an effect from one position to the other.
2790 from - integer: staring value
2791 to - integer: the ending value
2794 >var myFx = new Fx.Style('myElement', 'opacity').start(0,1); //display a transition from transparent to opaque.
2797 start: function(from, to){
2798 if (!this.options.wait) this.stop();
2799 else if (this.timer) return this;
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);
2810 Stops the transition.
2813 stop: function(end){
2814 if (!this.timer) return this;
2815 this.timer = $clear(this.timer);
2816 if (!end) this.fireEvent('onCancel', this.element);
2821 custom: function(from, to){return this.start(from, to)},
2822 clearTimer: function(end){return this.stop(end)}
2826 Fx.Base.implement(new Chain);
2827 Fx.Base.implement(new Events);
2828 Fx.Base.implement(new Options);
2831 Class: Fx.Transitions
2832 A collection of transition equations for use with the <Fx> Class.
2835 <Fxtransitions.js> for a whole bunch of transitions.
2838 Easing Equations, (c) 2003 Robert Penner (http://www.robertpenner.com/easing/), Open Source BSD License.
2843 /* Property: linear */
2844 linear: function(t, b, c, d){
2848 /* Property: sineInOut */
2849 sineInOut: function(t, b, c, d){
2850 return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
2857 Css parsing class for effects. Required by <Fx.Style>, <Fx.Styles>, <Fx.Elements>. No documentation needed, as its used internally.
2860 Christophe Beyls, <http://www.digitalia.be>,
2861 Valerio Proietti, <http://mad4milk.net>
2869 select: function(property, to){
2870 if (property.test('color', 'i')) return this.Color;
2871 if (to.test && to.test(' ')) return this.Multi;
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){
2880 from = el.getStyle(property);
2882 var css = this.select(property, to);
2883 return {from: css.parse(from), to: css.parse(to), css: css};
2890 parse: function(value){
2891 return parseFloat(value);
2894 getNow: function(from, to, fx){
2895 return fx.compute(from, to);
2898 getValue: function(value, unit){
2906 parse: function(value){
2907 return value.push ? value : value.split(' ').map(function(v){
2908 return parseFloat(v);
2912 getNow: function(from, to, fx){
2914 for (var i = 0; i < from.length; i++) now[i] = fx.compute(from[i], to[i]);
2918 getValue: function(value, unit){
2919 return value.join(unit+' ')+unit;
2926 parse: function(value){
2927 return value.push ? value : value.hexToRgb(true);
2930 getNow: function(from, to, fx){
2932 for (var i = 0; i < from.length; i++) now[i] = Math.round(fx.compute(from[i], to[i]));
2936 getValue: function(value){
2937 return 'rgb('+value.join(',')+')';
2947 Valerio Proietti, <http://mad4milk.net>
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.
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>)
2964 >var marginChange = new Fx.Style('myElement', 'margin-top', {duration:500});
2965 >marginChange.start(10, 100);
2968 Fx.Style = Fx.Base.extend({
2970 initialize: function(el, property, options){
2971 this.element = $(el);
2972 this.property = property;
2973 this.parent(options);
2978 Same as <Fx.Base.set>(0)
2986 this.now = this.css.getNow(this.from, this.to, this);
2990 this.css = Fx.CSS.select(this.property, to);
2991 return this.parent(this.css.parse(to));
2996 displays the transition to the value/values passed in
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
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);
3012 increase: function(){
3013 this.element.setStyle(this.property, this.css.getValue(this.now, this.options.unit));
3020 Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
3027 Applies an <Fx.Style> to the Element; This a shortcut for <Fx.Style>.
3030 >var myEffect = $('myElement').effect('height', {duration: 1000, transition: Fx.Transitions.linear});
3031 >myEffect.start(10, 100);
3034 effect: function(property, options){
3035 return new Fx.Style(this, property, options);
3041 Script: Fx.Styles.js
3042 Contains <Fx.Styles>
3045 Valerio Proietti, <http://mad4milk.net>
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.
3057 el - the $(element) to apply the styles transition to
3058 options - the fx options (see: <Fx.Base>)
3062 var myEffects = new Fx.Styles('myElement', {duration: 1000, transition: Fx.Transitions.linear});
3064 //height from 10 to 100 and width from 900 to 300
3066 'height': [10, 100],
3070 //or height from current height to 100 and width from current width to 300
3078 Fx.Styles = Fx.Base.extend({
3080 initialize: function(el, options){
3081 this.element = $(el);
3082 this.parent(options);
3086 for (var p in this.from) this.now[p] = this.css[p].getNow(this.from[p], this.to[p], this);
3093 this.css[p] = Fx.CSS.select(p, to[p]);
3094 parsed[p] = this.css[p].parse(to[p]);
3096 return this.parent(parsed);
3101 The function you'll actually use to execute a transition.
3110 start: function(obj){
3111 if (this.timer && this.options.wait) return this;
3114 var from = {}, to = {};
3116 var parsed = Fx.CSS.parse(this.element, p, obj[p]);
3117 from[p] = parsed.from;
3119 this.css[p] = parsed.css;
3121 return this.parent(from, to);
3124 increase: function(){
3125 for (var p in this.now) this.element.setStyle(p, this.css[p].getValue(this.now[p], this.options.unit));
3132 Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
3139 Applies an <Fx.Styles> to the Element; This a shortcut for <Fx.Styles>.
3142 >var myEffects = $(myElement).effects({duration: 1000, transition: Fx.Transitions.sineInOut});
3143 >myEffects.start({'height': [10, 100], 'width': [900, 300]});
3146 effects: function(options){
3147 return new Fx.Styles(this, options);
3153 Script: Fx.Elements.js
3154 Contains <Fx.Elements>
3157 Valerio Proietti, <http://mad4milk.net>
3165 Fx.Elements allows you to apply any number of styles transitions to a selection of elements. Includes colors (must be in hex format).
3168 elements - a collection of elements the effects will be applied to.
3169 options - same as <Fx.Base> options.
3172 Fx.Elements = Fx.Base.extend({
3174 initialize: function(elements, options){
3175 this.elements = $$(elements);
3176 this.parent(options);
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);
3190 var iTo = to[i], iCss = this.css[i] = {}, iParsed = parsed[i] = {};
3192 iCss[p] = Fx.CSS.select(p, iTo[p]);
3193 iParsed[p] = iCss[p].parse(iTo[p]);
3196 return this.parent(parsed);
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.
3205 var myElementsEffects = new Fx.Elements($$('a'));
3206 myElementsEffects.start({
3207 '0': { //let's change the first element's opacity and width
3211 '1': { //and the second one's opacity
3212 'opacity': [0.2, 0.5]
3218 start: function(obj){
3219 if (this.timer && this.options.wait) return this;
3222 var from = {}, to = {};
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;
3229 iCss[p] = parsed.css;
3232 return this.parent(from, to);
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));
3245 Script: Fx.Scroll.js
3246 Contains <Fx.Scroll>
3249 Valerio Proietti, <http://mad4milk.net>
3257 Scroll any element with an overflow, including the window element.
3260 element - the element to scroll
3261 options - same as <Fx.Base> options.
3264 Fx.Scroll = Fx.Base.extend({
3266 initialize: function(element, options){
3268 this.element = $(element);
3269 this.addEvent('onStart', function(){
3270 this.element.addEvent('mousewheel', this.stop.bind(this, false));
3272 this.removeEvent('onComplete', function(){
3273 this.element.removeEvent('mousewheel', this.stop.bind(this, false));
3275 this.parent(options);
3279 for (var i = 0; i < 2; i++) this.now[i] = this.compute(this.from[i], this.to[i]);
3284 Scrolls the chosen element to the x/y coordinates.
3287 x - the x coordinate to scroll the element to
3288 y - the y coordinate to scroll the element to
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];
3300 return this.start([el.scroll.x, el.scroll.y], [values.x, values.y]);
3305 Scrolls the chosen element to its maximum top.
3309 return this.scrollTo(false, 0);
3314 Scrolls the chosen element to its maximum bottom.
3317 toBottom: function(){
3318 return this.scrollTo(false, 'full');
3323 Scrolls the chosen element to its maximum left.
3327 return this.scrollTo(0, false);
3332 Scrolls the chosen element to its maximum right.
3335 toRight: function(){
3336 return this.scrollTo('full', false);
3341 Scrolls the specified element to the position the passed in element is found. Only usable if the chosen element is == window.
3344 el - the $(element) to scroll the window to
3347 toElement: function(el){
3348 return this.scrollTo($(el).getLeft(), $(el).getTop());
3351 increase: function(){
3352 this.element.scrollTo(this.now[0], this.now[1]);
3362 Valerio Proietti, <http://mad4milk.net>
3370 The slide effect; slides an element in horizontally or vertically, the contents will fold inside. Extends <Fx.Base>, inherits all its properties.
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.
3376 mode - set it to vertical or horizontal. Defaults to vertical.
3377 and all the <Fx.Base> options
3381 var mySlider = new Fx.Slide('myElement', {duration: 500});
3382 mySlider.toggle() //toggle the slider up and down.
3386 Fx.Slide = Fx.Base.extend({
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);
3393 this.parent(this.options);
3397 for (var i = 0; i < 2; i++) this.now[i] = this.compute(this.from[i], this.to[i]);
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()];
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()];
3416 slides the elements in view horizontally or vertically, depending on the mode parameter or options.mode.
3419 slideIn: function(mode){
3420 return this.start(this[mode || this.options.mode](), [0, this.offset]);
3425 slides the elements out of the view horizontally or vertically, depending on the mode parameter or options.mode.
3428 slideOut: function(mode){
3429 return this.start(this[mode || this.options.mode](), [-this.offset, 0]);
3434 Hides the element without a transition.
3437 hide: function(mode){
3438 this[mode || this.options.mode]();
3439 return this.set([-this.offset, 0]);
3444 Shows the element without a transition.
3447 show: function(mode){
3448 this[mode || this.options.mode]();
3449 return this.set([0, this.offset]);
3454 Slides in or Out the element, depending on its state
3457 toggle: function(mode){
3458 if (this.wrapper.offsetHeight == 0 || this.wrapper.offsetWidth == 0) return this.slideIn(mode);
3459 else return this.slideOut(mode);
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);
3470 Script: Fx.Transitions.js
3471 Cool transitions, to be used with all the effects.
3474 Robert Penner, <http://www.robertpenner.com/easing/>, modified to be used with mootools.
3477 Easing Equations v1.5, (c) 2003 Robert Penner, all rights reserved. Open Source BSD License.
3481 Class: Fx.Transitions
3482 A collection of tweaning transitions for use with the <Fx.Base> classes.
3487 /* Property: linear */
3488 linear: function(t, b, c, d){
3492 /* Property: quadIn */
3493 quadIn: function(t, b, c, d){
3494 return c*(t/=d)*t + b;
3497 /* Property: quatOut */
3498 quadOut: function(t, b, c, d){
3499 return -c *(t/=d)*(t-2) + b;
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;
3508 /* Property: cubicIn */
3509 cubicIn: function(t, b, c, d){
3510 return c*(t/=d)*t*t + b;
3513 /* Property: cubicOut */
3514 cubicOut: function(t, b, c, d){
3515 return c*((t=t/d-1)*t*t + 1) + b;
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;
3524 /* Property: quartIn */
3525 quartIn: function(t, b, c, d){
3526 return c*(t/=d)*t*t*t + b;
3529 /* Property: quartOut */
3530 quartOut: function(t, b, c, d){
3531 return -c * ((t=t/d-1)*t*t*t - 1) + b;
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;
3540 /* Property: quintIn */
3541 quintIn: function(t, b, c, d){
3542 return c*(t/=d)*t*t*t*t + b;
3545 /* Property: quintOut */
3546 quintOut: function(t, b, c, d){
3547 return c*((t=t/d-1)*t*t*t*t + 1) + b;
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;
3556 /* Property: sineIn */
3557 sineIn: function(t, b, c, d){
3558 return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
3561 /* Property: sineOut */
3562 sineOut: function(t, b, c, d){
3563 return c * Math.sin(t/d * (Math.PI/2)) + b;
3566 /* Property: sineInOut */
3567 sineInOut: function(t, b, c, d){
3568 return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
3571 /* Property: expoIn */
3572 expoIn: function(t, b, c, d){
3573 return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
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;
3581 /* Property: expoInOut */
3582 expoInOut: function(t, b, c, d){
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;
3589 /* Property: circIn */
3590 circIn: function(t, b, c, d){
3591 return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
3594 /* Property: circOut */
3595 circOut: function(t, b, c, d){
3596 return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
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;
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;
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;
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;
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;
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;
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;
3649 /* Property: bounceIn */
3650 bounceIn: function(t, b, c, d){
3651 return c - Fx.Transitions.bounceOut (d-t, 0, c, d) + b;
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;
3663 return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
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;
3676 Script: Drag.Base.js
3677 Contains <Drag.Base>, <Element.makeResizable>
3680 Valerio Proietti, <http://mad4milk.net>
3690 Modify two css properties of an element based on the position of the mouse.
3693 el - the $(element) to apply the transformations to.
3694 options - optional. The options object.
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
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'
3710 x - array with start and end limit relative to modifiers.x
3711 y - array with start and end limit relative to modifiers.y
3714 Drag.Base = new Class({
3716 getOptions: function(){
3720 onStart: Class.empty,
3721 onComplete: Class.empty,
3722 onSnap: Class.empty,
3723 onDrag: Class.empty,
3725 modifiers: {x: 'left', y: 'top'},
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);
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];
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);
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);
3769 this.fireEvent('onSnap', this.element);
3774 drag: function(event){
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];
3780 if ($chk(this.limit[z][1]) && (this.value.now[z] > this.limit[z][1])){
3781 this.value.now[z] = this.limit[z][1];
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];
3788 this.element.setStyle(this.options.modifiers[z], this.value.now[z] + this.options.unit);
3790 this.fireEvent('onDrag', this.element);
3795 this.handle.removeEvent('mousedown', this.bound.start);
3799 document.removeEvent('mousemove', this.bound.drag);
3800 document.removeEvent('mouseup', this.bound.stop);
3801 this.fireEvent('onComplete', this.element);
3806 Drag.Base.implement(new Events);
3807 Drag.Base.implement(new Options);
3811 Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
3817 Property: makeResizable
3818 Makes an element resizable (by dragging) with the supplied options.
3821 options - see <Drag.Base> for acceptable options.
3824 makeResizable: function(options){
3825 return new Drag.Base(this, Object.extend(options || {}, {modifiers: {x: 'width', y: 'height'}}));
3832 Contains the <Scroller>.
3835 Valerio Proietti, <http://mad4milk.net>
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.
3847 element - required, the element to scroll.
3848 options - optional, see options below, and <Fx.Base> 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.
3857 var Scroller = new Class({
3859 getOptions: function(){
3863 onChange: function(x, y){
3864 this.element.scrollTo(x, y);
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;
3877 The scroller starts listening to mouse movements.
3881 this.coord = this.getCoords.bindWithEvent(this);
3882 this.mousemover.addEvent('mousemove', this.coord);
3887 The scroller stops listening to mouse movements.
3891 this.mousemover.removeEvent('mousemove', this.coord);
3892 this.timer = $clear(this.timer);
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);
3901 var el = this.element.getSize();
3902 var pos = this.element.getOffsets();
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;
3911 if (change.y || change.x) this.fireEvent('onChange', [el.scroll.x + change.x, el.scroll.y + change.y]);
3916 Scroller.implement(new Events);
3917 Scroller.implement(new Options);
3924 Valerio Proietti, <http://mad4milk.net>
3932 Creates a slider with two elements: a knob and a container. Returns the values.
3935 element - the knob container
3937 options - see Options below
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.
3949 var Slider = new Class({
3951 getOptions: function(){
3953 onChange: Class.empty,
3954 onComplete: Class.empty,
3955 onTick: function(pos){
3956 this.knob.setStyle(this.p, pos+'px');
3964 initialize: function(el, knob, options){
3965 this.element = $(el);
3966 this.knob = $(knob);
3967 this.setOptions(this.getOptions(), options);
3969 this.previousChange = -1;
3970 this.previousEnd = -1;
3973 this.element.addEvent('mousedown', this.clickedElement.bindWithEvent(this));
3975 if (this.options.wheel) this.element.addEvent('mousewheel', this.scrolledElement.bindWithEvent(this));
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);
3989 this.knob.setStyle('position', 'relative').setStyle(this.p, 0);
3991 var modSlide = {}, limSlide = {};
3993 limSlide[this.z] = [0, this.max];
3994 modSlide[this.z] = this.p;
3996 this.drag = new Drag.Base(this.knob, {
3999 modifiers: modSlide,
4000 onStart: function(){
4006 onComplete: function(){
4011 if (this.options.initialize) this.options.initialize.call(this);
4016 The slider will get the step you pass.
4022 set: function(step){
4023 if (step > this.options.steps) step = this.options.steps;
4024 else if (step < 0) step = 0;
4028 this.fireEvent('onTick', this.toPosition(this.step)+'');
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);
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);
4045 this.fireEvent('onTick', position+'');
4048 draggedKnob: function(){
4049 this.step = this.toStep(this.drag.value.now[this.z]);
4053 checkStep: function(){
4054 if (this.previousChange != this.step){
4055 this.previousChange = this.step;
4056 this.fireEvent('onChange', this.step);
4061 if (this.previousEnd !== this.step){
4062 this.previousEnd = this.step;
4063 this.fireEvent('onComplete', this.step+'');
4067 toStep: function(position){
4068 return Math.round(position/this.max*this.options.steps);
4071 toPosition: function(step){
4072 return (this.max)*step/this.options.steps;
4077 Slider.implement(new Events);
4078 Slider.implement(new Options);