3 MooTools - My Object Oriented JavaScript Tools.
9 Copyright (c) 2006-2008 [Valerio Proietti](http://mad4milk.net/).
12 [The MooTools production team](http://mootools.net/developers/).
15 - Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)
16 - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
21 'build': '0d4845aab3d9a4fdee2f0d4a6dd59210e4b697cf'
24 var Native = function(options
){
25 options
= options
|| {};
26 var name
= options
.name
;
27 var legacy
= options
.legacy
;
28 var protect
= options
.protect
;
29 var methods
= options
.implement
;
30 var generics
= options
.generics
;
31 var initialize
= options
.initialize
;
32 var afterImplement
= options
.afterImplement
|| function(){};
33 var object
= initialize
|| legacy
;
34 generics
= generics
!== false;
36 object
.constructor = Native
;
37 object
.$family
= {name
: 'native'};
38 if (legacy
&& initialize
) object
.prototype = legacy
.prototype;
39 object
.prototype.constructor = object
;
42 var family
= name
.toLowerCase();
43 object
.prototype.$family
= {name
: family
};
44 Native
.typize(object
, family
);
47 var add = function(obj
, name
, method
, force
){
48 if (!protect
|| force
|| !obj
.prototype[name
]) obj
.prototype[name
] = method
;
49 if (generics
) Native
.genericize(obj
, name
, protect
);
50 afterImplement
.call(obj
, name
, method
);
54 object
.alias = function(a1
, a2
, a3
){
55 if (typeof a1
== 'string'){
56 if ((a1
= this.prototype[a1
])) return add(this, a2
, a1
, a3
);
58 for (var a
in a1
) this.alias(a
, a1
[a
], a2
);
62 object
.implement = function(a1
, a2
, a3
){
63 if (typeof a1
== 'string') return add(this, a1
, a2
, a3
);
64 for (var p
in a1
) add(this, p
, a1
[p
], a2
);
68 if (methods
) object
.implement(methods
);
73 Native
.genericize = function(object
, property
, check
){
74 if ((!check
|| !object
[property
]) && typeof object
.prototype[property
] == 'function') object
[property
] = function(){
75 var args
= Array
.prototype.slice
.call(arguments
);
76 return object
.prototype[property
].apply(args
.shift(), args
);
80 Native
.implement = function(objects
, properties
){
81 for (var i
= 0, l
= objects
.length
; i
< l
; i
++) objects
[i
].implement(properties
);
84 Native
.typize = function(object
, family
){
85 if (!object
.type
) object
.type = function(item
){
86 return ($type(item
) === family
);
91 var natives
= {'Array': Array
, 'Date': Date
, 'Function': Function
, 'Number': Number
, 'RegExp': RegExp
, 'String': String
};
92 for (var n
in natives
) new Native({name
: n
, initialize
: natives
[n
], protect
: true});
94 var types
= {'boolean': Boolean
, 'native': Native
, 'object': Object
};
95 for (var t
in types
) Native
.typize(types
[t
], t
);
98 'Array': ["concat", "indexOf", "join", "lastIndexOf", "pop", "push", "reverse", "shift", "slice", "sort", "splice", "toString", "unshift", "valueOf"],
99 'String': ["charAt", "charCodeAt", "concat", "indexOf", "lastIndexOf", "match", "replace", "search", "slice", "split", "substr", "substring", "toLowerCase", "toUpperCase", "valueOf"]
101 for (var g
in generics
){
102 for (var i
= generics
[g
].length
; i
--;) Native
.genericize(window
[g
], generics
[g
][i
], true);
106 var Hash
= new Native({
110 initialize: function(object
){
111 if ($type(object
) == 'hash') object
= $unlink(object
.getClean());
112 for (var key
in object
) this[key
] = object
[key
];
120 forEach: function(fn
, bind
){
121 for (var key
in this){
122 if (this.hasOwnProperty(key
)) fn
.call(bind
, this[key
], key
, this);
126 getClean: function(){
128 for (var key
in this){
129 if (this.hasOwnProperty(key
)) clean
[key
] = this[key
];
134 getLength: function(){
136 for (var key
in this){
137 if (this.hasOwnProperty(key
)) length
++;
144 Hash
.alias('forEach', 'each');
148 forEach: function(fn
, bind
){
149 for (var i
= 0, l
= this.length
; i
< l
; i
++) fn
.call(bind
, this[i
], i
, this);
154 Array
.alias('forEach', 'each');
156 function $A(iterable
){
159 for (var i
= 0, l
= iterable
.length
; i
< l
; i
++) array
[i
] = iterable
[i
];
162 return Array
.prototype.slice
.call(iterable
);
165 function $arguments(i
){
172 return !!(obj
|| obj
=== 0);
175 function $clear(timer
){
177 clearInterval(timer
);
181 function $defined(obj
){
182 return (obj
!= undefined);
185 function $each(iterable
, fn
, bind
){
186 var type
= $type(iterable
);
187 ((type
== 'arguments' || type
== 'collection' || type
== 'array') ? Array
: Hash
).each(iterable
, fn
, bind
);
192 function $extend(original
, extended
){
193 for (var key
in (extended
|| {})) original
[key
] = extended
[key
];
198 return new Hash(object
);
201 function $lambda(value
){
202 return (typeof value
== 'function') ? value : function(){
209 for (var i
= 0, l
= arguments
.length
; i
< l
; i
++){
210 var object
= arguments
[i
];
211 if ($type(object
) != 'object') continue;
212 for (var key
in object
){
213 var op
= object
[key
], mp
= mix
[key
];
214 mix
[key
] = (mp
&& $type(op
) == 'object' && $type(mp
) == 'object') ? $merge(mp
, op
) : $unlink(op
);
221 for (var i
= 0, l
= arguments
.length
; i
< l
; i
++){
222 if (arguments
[i
] != undefined) return arguments
[i
];
227 function $random(min
, max
){
228 return Math
.floor(Math
.random() * (max
- min
+ 1) + min
);
231 function $splat(obj
){
232 var type
= $type(obj
);
233 return (type
) ? ((type
!= 'array' && type
!= 'arguments') ? [obj
] : obj
) : [];
236 var $time
= Date
.now
|| function(){
241 for (var i
= 0, l
= arguments
.length
; i
< l
; i
++){
243 return arguments
[i
]();
250 if (obj
== undefined) return false;
251 if (obj
.$family
) return (obj
.$family
.name
== 'number' && !isFinite(obj
)) ? false : obj
.$family
.name
;
253 switch (obj
.nodeType
){
254 case 1: return 'element';
255 case 3: return (/\S/).test(obj
.nodeValue
) ? 'textnode' : 'whitespace';
257 } else if (typeof obj
.length
== 'number'){
258 if (obj
.callee
) return 'arguments';
259 else if (obj
.item
) return 'collection';
264 function $unlink(object
){
266 switch ($type(object
)){
269 for (var p
in object
) unlinked
[p
] = $unlink(object
[p
]);
272 unlinked
= new Hash(object
);
276 for (var i
= 0, l
= object
.length
; i
< l
; i
++) unlinked
[i
] = $unlink(object
[i
]);
278 default: return object
;
286 The Browser Core. Contains Browser initialization, Window and Document, and the Browser Hash.
292 var Browser
= $merge({
294 Engine
: {name
: 'unknown', version
: 0},
296 Platform
: {name
: (window
.orientation
!= undefined) ? 'ipod' : (navigator
.platform
.match(/mac|win|linux/i) || ['other'])[0].toLowerCase()},
298 Features
: {xpath
: !!(document
.evaluate
), air
: !!(window
.runtime
), query
: !!(document
.querySelector
)},
305 return (!window
.opera
) ? false : ((arguments
.callee
.caller
) ? 960 : ((document
.getElementsByClassName
) ? 950 : 925));
309 return (!window
.ActiveXObject
) ? false : ((window
.XMLHttpRequest
) ? 5 : 4);
313 return (navigator
.taintEnabled
) ? false : ((Browser
.Features
.xpath
) ? ((Browser
.Features
.query
) ? 525 : 420) : 419);
317 return (document
.getBoxObjectFor
== undefined) ? false : ((document
.getElementsByClassName
) ? 19 : 18);
324 Browser
.Platform
[Browser
.Platform
.name
] = true;
326 Browser
.detect = function(){
328 for (var engine
in this.Engines
){
329 var version
= this.Engines
[engine
]();
331 this.Engine
= {name
: engine
, version
: version
};
332 this.Engine
[engine
] = this.Engine
[engine
+ version
] = true;
337 return {name
: engine
, version
: version
};
343 Browser
.Request = function(){
344 return $try(function(){
345 return new XMLHttpRequest();
347 return new ActiveXObject('MSXML2.XMLHTTP');
351 Browser
.Features
.xhr
= !!(Browser
.Request());
353 Browser
.Plugins
.Flash
= (function(){
354 var version
= ($try(function(){
355 return navigator
.plugins
['Shockwave Flash'].description
;
357 return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
358 }) || '0 r0').match(/\d+/g);
359 return {version
: parseInt(version
[0] || 0 + '.' + version
[1] || 0), build
: parseInt(version
[2] || 0)};
362 function $exec(text
){
363 if (!text
) return text
;
364 if (window
.execScript
){
365 window
.execScript(text
);
367 var script
= document
.createElement('script');
368 script
.setAttribute('type', 'text/javascript');
369 script
[(Browser
.Engine
.webkit
&& Browser
.Engine
.version
< 420) ? 'innerText' : 'text'] = text
;
370 document
.head
.appendChild(script
);
371 document
.head
.removeChild(script
);
378 var $uid
= (Browser
.Engine
.trident
) ? function(item
){
379 return (item
.uid
|| (item
.uid
= [Native
.UID
++]))[0];
381 return item
.uid
|| (item
.uid
= Native
.UID
++);
384 var Window
= new Native({
388 legacy
: (Browser
.Engine
.trident
) ? null: window
.Window
,
390 initialize: function(win
){
393 win
.Element
= $empty
;
394 if (Browser
.Engine
.webkit
) win
.document
.createElement("iframe"); //fixes safari 2
395 win
.Element
.prototype = (Browser
.Engine
.webkit
) ? window
["[[DOMElement.prototype]]"] : {};
397 win
.document
.window
= win
;
398 return $extend(win
, Window
.Prototype
);
401 afterImplement: function(property
, value
){
402 window
[property
] = Window
.Prototype
[property
] = value
;
407 Window
.Prototype
= {$family
: {name
: 'window'}};
411 var Document
= new Native({
415 legacy
: (Browser
.Engine
.trident
) ? null: window
.Document
,
417 initialize: function(doc
){
419 doc
.head
= doc
.getElementsByTagName('head')[0];
420 doc
.html
= doc
.getElementsByTagName('html')[0];
421 if (Browser
.Engine
.trident
&& Browser
.Engine
.version
<= 4) $try(function(){
422 doc
.execCommand("BackgroundImageCache", false, true);
424 if (Browser
.Engine
.trident
) doc
.window
.attachEvent('onunload', function() {
425 doc
.window
.detachEvent('onunload', arguments
.callee
);
426 doc
.head
= doc
.html
= doc
.window
= null;
428 return $extend(doc
, Document
.Prototype
);
431 afterImplement: function(property
, value
){
432 document
[property
] = Document
.Prototype
[property
] = value
;
437 Document
.Prototype
= {$family
: {name
: 'document'}};
439 new Document(document
);
444 Contains Array Prototypes like each, contains, and erase.
452 every: function(fn
, bind
){
453 for (var i
= 0, l
= this.length
; i
< l
; i
++){
454 if (!fn
.call(bind
, this[i
], i
, this)) return false;
459 filter: function(fn
, bind
){
461 for (var i
= 0, l
= this.length
; i
< l
; i
++){
462 if (fn
.call(bind
, this[i
], i
, this)) results
.push(this[i
]);
468 return this.filter($defined
);
471 indexOf: function(item
, from){
472 var len
= this.length
;
473 for (var i
= (from < 0) ? Math
.max(0, len
+ from) : from || 0; i
< len
; i
++){
474 if (this[i
] === item
) return i
;
479 map: function(fn
, bind
){
481 for (var i
= 0, l
= this.length
; i
< l
; i
++) results
[i
] = fn
.call(bind
, this[i
], i
, this);
485 some: function(fn
, bind
){
486 for (var i
= 0, l
= this.length
; i
< l
; i
++){
487 if (fn
.call(bind
, this[i
], i
, this)) return true;
492 associate: function(keys
){
493 var obj
= {}, length
= Math
.min(this.length
, keys
.length
);
494 for (var i
= 0; i
< length
; i
++) obj
[keys
[i
]] = this[i
];
498 link: function(object
){
500 for (var i
= 0, l
= this.length
; i
< l
; i
++){
501 for (var key
in object
){
502 if (object
[key
](this[i
])){
503 result
[key
] = this[i
];
512 contains: function(item
, from){
513 return this.indexOf(item
, from) != -1;
516 extend: function(array
){
517 for (var i
= 0, j
= array
.length
; i
< j
; i
++) this.push(array
[i
]);
522 return (this.length
) ? this[this.length
- 1] : null;
525 getRandom: function(){
526 return (this.length
) ? this[$random(0, this.length
- 1)] : null;
529 include: function(item
){
530 if (!this.contains(item
)) this.push(item
);
534 combine: function(array
){
535 for (var i
= 0, l
= array
.length
; i
< l
; i
++) this.include(array
[i
]);
539 erase: function(item
){
540 for (var i
= this.length
; i
--; i
){
541 if (this[i
] === item
) this.splice(i
, 1);
553 for (var i
= 0, l
= this.length
; i
< l
; i
++){
554 var type
= $type(this[i
]);
556 array
= array
.concat((type
== 'array' || type
== 'collection' || type
== 'arguments') ? Array
.flatten(this[i
]) : this[i
]);
561 hexToRgb: function(array
){
562 if (this.length
!= 3) return null;
563 var rgb
= this.map(function(value
){
564 if (value
.length
== 1) value
+= value
;
565 return value
.toInt(16);
567 return (array
) ? rgb
: 'rgb(' + rgb
+ ')';
570 rgbToHex: function(array
){
571 if (this.length
< 3) return null;
572 if (this.length
== 4 && this[3] == 0 && !array
) return 'transparent';
574 for (var i
= 0; i
< 3; i
++){
575 var bit
= (this[i
] - 0).toString(16);
576 hex
.push((bit
.length
== 1) ? '0' + bit
: bit
);
578 return (array
) ? hex
: '#' + hex
.join('');
586 Contains Function Prototypes like create, bind, pass, and delay.
594 extend: function(properties
){
595 for (var property
in properties
) this[property
] = properties
[property
];
599 create: function(options
){
601 options
= options
|| {};
602 return function(event
){
603 var args
= options
.arguments
;
604 args
= (args
!= undefined) ? $splat(args
) : Array
.slice(arguments
, (options
.event
) ? 1 : 0);
605 if (options
.event
) args
= [event
|| window
.event
].extend(args
);
606 var returns = function(){
607 return self
.apply(options
.bind
|| null, args
);
609 if (options
.delay
) return setTimeout(returns
, options
.delay
);
610 if (options
.periodical
) return setInterval(returns
, options
.periodical
);
611 if (options
.attempt
) return $try(returns
);
616 run: function(args
, bind
){
617 return this.apply(bind
, $splat(args
));
620 pass: function(args
, bind
){
621 return this.create({bind
: bind
, arguments
: args
});
624 bind: function(bind
, args
){
625 return this.create({bind
: bind
, arguments
: args
});
628 bindWithEvent: function(bind
, args
){
629 return this.create({bind
: bind
, arguments
: args
, event
: true});
632 attempt: function(args
, bind
){
633 return this.create({bind
: bind
, arguments
: args
, attempt
: true})();
636 delay: function(delay
, bind
, args
){
637 return this.create({bind
: bind
, arguments
: args
, delay
: delay
})();
640 periodical: function(periodical
, bind
, args
){
641 return this.create({bind
: bind
, arguments
: args
, periodical
: periodical
})();
649 Contains Number Prototypes like limit, round, times, and ceil.
657 limit: function(min
, max
){
658 return Math
.min(max
, Math
.max(min
, this));
661 round: function(precision
){
662 precision
= Math
.pow(10, precision
|| 0);
663 return Math
.round(this * precision
) / precision
;
666 times: function(fn
, bind
){
667 for (var i
= 0; i
< this; i
++) fn
.call(bind
, i
, this);
671 return parseFloat(this);
674 toInt: function(base
){
675 return parseInt(this, base
|| 10);
680 Number
.alias('times', 'each');
684 math
.each(function(name
){
685 if (!Number
[name
]) methods
[name
] = function(){
686 return Math
[name
].apply(null, [this].concat($A(arguments
)));
689 Number
.implement(methods
);
690 })(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
695 Contains String Prototypes like camelCase, capitalize, test, and toInt.
703 test: function(regex
, params
){
704 return ((typeof regex
== 'string') ? new RegExp(regex
, params
) : regex
).test(this);
707 contains: function(string
, separator
){
708 return (separator
) ? (separator
+ this + separator
).indexOf(separator
+ string
+ separator
) > -1 : this.indexOf(string
) > -1;
712 return this.replace(/^\s+|\s+$/g, '');
716 return this.replace(/\s+/g, ' ').trim();
719 camelCase: function(){
720 return this.replace(/-\D/g, function(match
){
721 return match
.charAt(1).toUpperCase();
725 hyphenate: function(){
726 return this.replace(/[A-Z]/g, function(match
){
727 return ('-' + match
.charAt(0).toLowerCase());
731 capitalize: function(){
732 return this.replace(/\b[a-z]/g, function(match
){
733 return match
.toUpperCase();
737 escapeRegExp: function(){
738 return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
741 toInt: function(base
){
742 return parseInt(this, base
|| 10);
746 return parseFloat(this);
749 hexToRgb: function(array
){
750 var hex
= this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
751 return (hex
) ? hex
.slice(1).hexToRgb(array
) : null;
754 rgbToHex: function(array
){
755 var rgb
= this.match(/\d{1,3}/g);
756 return (rgb
) ? rgb
.rgbToHex(array
) : null;
759 stripScripts: function(option
){
761 var text
= this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){
762 scripts
+= arguments
[1] + '\n';
765 if (option
=== true) $exec(scripts
);
766 else if ($type(option
) == 'function') option(scripts
, text
);
770 substitute: function(object
, regexp
){
771 return this.replace(regexp
|| (/\\?\{([^{}]+)\}/g), function(match
, name
){
772 if (match
.charAt(0) == '\\') return match
.slice(1);
773 return (object
[name
] != undefined) ? object
[name
] : '';
782 Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects.
790 has
: Object
.prototype.hasOwnProperty
,
792 keyOf: function(value
){
793 for (var key
in this){
794 if (this.hasOwnProperty(key
) && this[key
] === value
) return key
;
799 hasValue: function(value
){
800 return (Hash
.keyOf(this, value
) !== null);
803 extend: function(properties
){
804 Hash
.each(properties
, function(value
, key
){
805 Hash
.set(this, key
, value
);
810 combine: function(properties
){
811 Hash
.each(properties
, function(value
, key
){
812 Hash
.include(this, key
, value
);
817 erase: function(key
){
818 if (this.hasOwnProperty(key
)) delete this[key
];
823 return (this.hasOwnProperty(key
)) ? this[key
] : null;
826 set: function(key
, value
){
827 if (!this[key
] || this.hasOwnProperty(key
)) this[key
] = value
;
832 Hash
.each(this, function(value
, key
){
838 include: function(key
, value
){
840 if (k
== undefined) this[key
] = value
;
844 map: function(fn
, bind
){
845 var results
= new Hash
;
846 Hash
.each(this, function(value
, key
){
847 results
.set(key
, fn
.call(bind
, value
, key
, this));
852 filter: function(fn
, bind
){
853 var results
= new Hash
;
854 Hash
.each(this, function(value
, key
){
855 if (fn
.call(bind
, value
, key
, this)) results
.set(key
, value
);
860 every: function(fn
, bind
){
861 for (var key
in this){
862 if (this.hasOwnProperty(key
) && !fn
.call(bind
, this[key
], key
)) return false;
867 some: function(fn
, bind
){
868 for (var key
in this){
869 if (this.hasOwnProperty(key
) && fn
.call(bind
, this[key
], key
)) return true;
876 Hash
.each(this, function(value
, key
){
882 getValues: function(){
884 Hash
.each(this, function(value
){
890 toQueryString: function(base
){
891 var queryString
= [];
892 Hash
.each(this, function(value
, key
){
893 if (base
) key
= base
+ '[' + key
+ ']';
895 switch ($type(value
)){
896 case 'object': result
= Hash
.toQueryString(value
, key
); break;
899 value
.each(function(val
, i
){
902 result
= Hash
.toQueryString(qs
, key
);
904 default: result
= key
+ '=' + encodeURIComponent(value
);
906 if (value
!= undefined) queryString
.push(result
);
909 return queryString
.join('&');
914 Hash
.alias({keyOf
: 'indexOf', hasValue
: 'contains'});
919 Contains the Event Native, to make the event object completely crossbrowser.
925 var Event
= new Native({
929 initialize: function(event
, win
){
931 var doc
= win
.document
;
932 event
= event
|| win
.event
;
933 if (event
.$extended
) return event
;
934 this.$extended
= true;
935 var type
= event
.type
;
936 var target
= event
.target
|| event
.srcElement
;
937 while (target
&& target
.nodeType
== 3) target
= target
.parentNode
;
939 if (type
.test(/key/)){
940 var code
= event
.which
|| event
.keyCode
;
941 var key
= Event
.Keys
.keyOf(code
);
942 if (type
== 'keydown'){
943 var fKey
= code
- 111;
944 if (fKey
> 0 && fKey
< 13) key
= 'f' + fKey
;
946 key
= key
|| String
.fromCharCode(code
).toLowerCase();
947 } else if (type
.match(/(click|mouse|menu)/i)){
948 doc
= (!doc
.compatMode
|| doc
.compatMode
== 'CSS1Compat') ? doc
.html
: doc
.body
;
950 x
: event
.pageX
|| event
.clientX
+ doc
.scrollLeft
,
951 y
: event
.pageY
|| event
.clientY
+ doc
.scrollTop
954 x
: (event
.pageX
) ? event
.pageX
- win
.pageXOffset
: event
.clientX
,
955 y
: (event
.pageY
) ? event
.pageY
- win
.pageYOffset
: event
.clientY
957 if (type
.match(/DOMMouseScroll|mousewheel/)){
958 var wheel
= (event
.wheelDelta
) ? event
.wheelDelta
/ 120 : -(event
.detail
|| 0) / 3;
960 var rightClick
= (event
.which
== 3) || (event
.button
== 2);
962 if (type
.match(/over|out/)){
964 case 'mouseover': related
= event
.relatedTarget
|| event
.fromElement
; break;
965 case 'mouseout': related
= event
.relatedTarget
|| event
.toElement
;
968 while (related
&& related
.nodeType
== 3) related
= related
.parentNode
;
970 }).create({attempt
: Browser
.Engine
.gecko
})()) related
= false;
974 return $extend(this, {
980 rightClick
: rightClick
,
984 relatedTarget
: related
,
990 shift
: event
.shiftKey
,
991 control
: event
.ctrlKey
,
999 Event
.Keys
= new Hash({
1015 return this.stopPropagation().preventDefault();
1018 stopPropagation: function(){
1019 if (this.event
.stopPropagation
) this.event
.stopPropagation();
1020 else this.event
.cancelBubble
= true;
1024 preventDefault: function(){
1025 if (this.event
.preventDefault
) this.event
.preventDefault();
1026 else this.event
.returnValue
= false;
1035 Contains the Class Function for easily creating, extending, and implementing reusable Classes.
1041 var Class
= new Native({
1045 initialize: function(properties
){
1046 properties
= properties
|| {};
1047 var klass = function(){
1048 for (var key
in this){
1049 if ($type(this[key
]) != 'function') this[key
] = $unlink(this[key
]);
1051 this.constructor = klass
;
1052 if (Class
.prototyping
) return this;
1053 var instance
= (this.initialize
) ? this.initialize
.apply(this, arguments
) : this;
1054 if (this.options
&& this.options
.initialize
) this.options
.initialize
.call(this);
1058 for (var mutator
in Class
.Mutators
){
1059 if (!properties
[mutator
]) continue;
1060 properties
= Class
.Mutators
[mutator
](properties
, properties
[mutator
]);
1061 delete properties
[mutator
];
1064 $extend(klass
, this);
1065 klass
.constructor = Class
;
1066 klass
.prototype = properties
;
1074 Extends: function(self
, klass
){
1075 Class
.prototyping
= klass
.prototype;
1076 var subclass
= new klass
;
1077 delete subclass
.parent
;
1078 subclass
= Class
.inherit(subclass
, self
);
1079 delete Class
.prototyping
;
1083 Implements: function(self
, klasses
){
1084 $splat(klasses
).each(function(klass
){
1085 Class
.prototying
= klass
;
1086 $extend(self
, ($type(klass
) == 'class') ? new klass
: klass
);
1087 delete Class
.prototyping
;
1096 inherit: function(object
, properties
){
1097 var caller
= arguments
.callee
.caller
;
1098 for (var key
in properties
){
1099 var override
= properties
[key
];
1100 var previous
= object
[key
];
1101 var type
= $type(override
);
1102 if (previous
&& type
== 'function'){
1103 if (override
!= previous
){
1105 override
.__parent
= previous
;
1106 object
[key
] = override
;
1108 Class
.override(object
, key
, override
);
1111 } else if(type
== 'object'){
1112 object
[key
] = $merge(previous
, override
);
1114 object
[key
] = override
;
1118 if (caller
) object
.parent = function(){
1119 return arguments
.callee
.caller
.__parent
.apply(this, arguments
);
1125 override: function(object
, name
, method
){
1126 var parent
= Class
.prototyping
;
1127 if (parent
&& object
[name
] != parent
[name
]) parent
= null;
1128 var override = function(){
1129 var previous
= this.parent
;
1130 this.parent
= parent
? parent
[name
] : object
[name
];
1131 var value
= method
.apply(this, arguments
);
1132 this.parent
= previous
;
1135 object
[name
] = override
;
1142 implement: function(){
1143 var proto
= this.prototype;
1144 $each(arguments
, function(properties
){
1145 Class
.inherit(proto
, properties
);
1154 Script: Class.Extras.js
1155 Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.
1161 var Chain
= new Class({
1166 this.$chain
.extend(Array
.flatten(arguments
));
1170 callChain: function(){
1171 return (this.$chain
.length
) ? this.$chain
.shift().apply(this, arguments
) : false;
1174 clearChain: function(){
1175 this.$chain
.empty();
1181 var Events
= new Class({
1185 addEvent: function(type
, fn
, internal){
1186 type
= Events
.removeOn(type
);
1188 this.$events
[type
] = this.$events
[type
] || [];
1189 this.$events
[type
].include(fn
);
1190 if (internal) fn
.internal = true;
1195 addEvents: function(events
){
1196 for (var type
in events
) this.addEvent(type
, events
[type
]);
1200 fireEvent: function(type
, args
, delay
){
1201 type
= Events
.removeOn(type
);
1202 if (!this.$events
|| !this.$events
[type
]) return this;
1203 this.$events
[type
].each(function(fn
){
1204 fn
.create({'bind': this, 'delay': delay
, 'arguments': args
})();
1209 removeEvent: function(type
, fn
){
1210 type
= Events
.removeOn(type
);
1211 if (!this.$events
[type
]) return this;
1212 if (!fn
.internal) this.$events
[type
].erase(fn
);
1216 removeEvents: function(events
){
1217 if ($type(events
) == 'object'){
1218 for (var type
in events
) this.removeEvent(type
, events
[type
]);
1221 if (events
) events
= Events
.removeOn(events
);
1222 for (var type
in this.$events
){
1223 if (events
&& events
!= type
) continue;
1224 var fns
= this.$events
[type
];
1225 for (var i
= fns
.length
; i
--; i
) this.removeEvent(type
, fns
[i
]);
1232 Events
.removeOn = function(string
){
1233 return string
.replace(/^on([A-Z])/, function(full
, first
) {
1234 return first
.toLowerCase();
1238 var Options
= new Class({
1240 setOptions: function(){
1241 this.options
= $merge
.run([this.options
].extend(arguments
));
1242 if (!this.addEvent
) return this;
1243 for (var option
in this.options
){
1244 if ($type(this.options
[option
]) != 'function' || !(/^on[A-Z]/).test(option
)) continue;
1245 this.addEvent(option
, this.options
[option
]);
1246 delete this.options
[option
];
1256 One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser,
1257 time-saver methods to let you easily work with HTML Elements.
1263 var Element
= new Native({
1267 legacy
: window
.Element
,
1269 initialize: function(tag
, props
){
1270 var konstructor
= Element
.Constructors
.get(tag
);
1271 if (konstructor
) return konstructor(props
);
1272 if (typeof tag
== 'string') return document
.newElement(tag
, props
);
1273 return $(tag
).set(props
);
1276 afterImplement: function(key
, value
){
1277 Element
.Prototype
[key
] = value
;
1278 if (Array
[key
]) return;
1279 Elements
.implement(key
, function(){
1280 var items
= [], elements
= true;
1281 for (var i
= 0, j
= this.length
; i
< j
; i
++){
1282 var returns
= this[i
][key
].apply(this[i
], arguments
);
1283 items
.push(returns
);
1284 if (elements
) elements
= ($type(returns
) == 'element');
1286 return (elements
) ? new Elements(items
) : items
;
1292 Element
.Prototype
= {$family
: {name
: 'element'}};
1294 Element
.Constructors
= new Hash
;
1296 var IFrame
= new Native({
1302 initialize: function(){
1303 var params
= Array
.link(arguments
, {properties
: Object
.type
, iframe
: $defined
});
1304 var props
= params
.properties
|| {};
1305 var iframe
= $(params
.iframe
) || false;
1306 var onload
= props
.onload
|| $empty
;
1307 delete props
.onload
;
1308 props
.id
= props
.name
= $pick(props
.id
, props
.name
, iframe
.id
, iframe
.name
, 'IFrame_' + $time());
1309 iframe
= new Element(iframe
|| 'iframe', props
);
1310 var onFrameLoad = function(){
1311 var host
= $try(function(){
1312 return iframe
.contentWindow
.location
.host
;
1314 if (host
&& host
== window
.location
.host
){
1315 var win
= new Window(iframe
.contentWindow
);
1316 new Document(iframe
.contentWindow
.document
);
1317 $extend(win
.Element
.prototype, Element
.Prototype
);
1319 onload
.call(iframe
.contentWindow
, iframe
.contentWindow
.document
);
1321 (window
.frames
[props
.id
]) ? onFrameLoad() : iframe
.addListener('load', onFrameLoad
);
1327 var Elements
= new Native({
1329 initialize: function(elements
, options
){
1330 options
= $extend({ddup
: true, cash
: true}, options
);
1331 elements
= elements
|| [];
1332 if (options
.ddup
|| options
.cash
){
1333 var uniques
= {}, returned
= [];
1334 for (var i
= 0, l
= elements
.length
; i
< l
; i
++){
1335 var el
= $.element(elements
[i
], !options
.cash
);
1337 if (uniques
[el
.uid
]) continue;
1338 uniques
[el
.uid
] = true;
1342 elements
= returned
;
1344 return (options
.cash
) ? $extend(elements
, this) : elements
;
1349 Elements
.implement({
1351 filter: function(filter
, bind
){
1352 if (!filter
) return this;
1353 return new Elements(Array
.filter(this, (typeof filter
== 'string') ? function(item
){
1354 return item
.match(filter
);
1360 Document
.implement({
1362 newElement: function(tag
, props
){
1363 if (Browser
.Engine
.trident
&& props
){
1364 ['name', 'type', 'checked'].each(function(attribute
){
1365 if (!props
[attribute
]) return;
1366 tag
+= ' ' + attribute
+ '="' + props
[attribute
] + '"';
1367 if (attribute
!= 'checked') delete props
[attribute
];
1369 tag
= '<' + tag
+ '>';
1371 return $.element(this.createElement(tag
)).set(props
);
1374 newTextNode: function(text
){
1375 return this.createTextNode(text
);
1378 getDocument: function(){
1382 getWindow: function(){
1390 $: function(el
, nocash
){
1391 if (el
&& el
.$family
&& el
.uid
) return el
;
1392 var type
= $type(el
);
1393 return ($[type
]) ? $[type
](el
, nocash
, this.document
) : null;
1396 $$: function(selector
){
1397 if (arguments
.length
== 1 && typeof selector
== 'string') return this.document
.getElements(selector
);
1399 var args
= Array
.flatten(arguments
);
1400 for (var i
= 0, l
= args
.length
; i
< l
; i
++){
1402 switch ($type(item
)){
1403 case 'element': elements
.push(item
); break;
1404 case 'string': elements
.extend(this.document
.getElements(item
, true));
1407 return new Elements(elements
);
1410 getDocument: function(){
1411 return this.document
;
1414 getWindow: function(){
1420 $.string = function(id
, nocash
, doc
){
1421 id
= doc
.getElementById(id
);
1422 return (id
) ? $.element(id
, nocash
) : null;
1425 $.element = function(el
, nocash
){
1427 if (!nocash
&& !el
.$family
&& !(/^object|embed$/i).test(el
.tagName
)){
1428 var proto
= Element
.Prototype
;
1429 for (var p
in proto
) el
[p
] = proto
[p
];
1434 $.object = function(obj
, nocash
, doc
){
1435 if (obj
.toElement
) return $.element(obj
.toElement(doc
), nocash
);
1439 $.textnode
= $.whitespace
= $.window
= $.document
= $arguments(0);
1441 Native
.implement([Element
, Document
], {
1443 getElement: function(selector
, nocash
){
1444 return $(this.getElements(selector
, true)[0] || null, nocash
);
1447 getElements: function(tags
, nocash
){
1448 tags
= tags
.split(',');
1450 var ddup
= (tags
.length
> 1);
1451 tags
.each(function(tag
){
1452 var partial
= this.getElementsByTagName(tag
.trim());
1453 (ddup
) ? elements
.extend(partial
) : elements
= partial
;
1455 return new Elements(elements
, {ddup
: ddup
, cash
: !nocash
});
1462 var collected
= {}, storage
= {};
1463 var props
= {input
: 'checked', option
: 'selected', textarea
: (Browser
.Engine
.webkit
&& Browser
.Engine
.version
< 420) ? 'innerHTML' : 'value'};
1465 var get = function(uid
){
1466 return (storage
[uid
] || (storage
[uid
] = {}));
1469 var clean = function(item
, retain
){
1472 if (Browser
.Engine
.trident
){
1473 if (item
.clearAttributes
){
1474 var clone
= retain
&& item
.cloneNode(false);
1475 item
.clearAttributes();
1476 if (clone
) item
.mergeAttributes(clone
);
1477 } else if (item
.removeEvents
){
1478 item
.removeEvents();
1480 if ((/object/i).test(item
.tagName
)){
1481 for (var p
in item
){
1482 if (typeof item
[p
] == 'function') item
[p
] = $empty
;
1484 Element
.dispose(item
);
1488 collected
[uid
] = storage
[uid
] = null;
1491 var purge = function(){
1492 Hash
.each(collected
, clean
);
1493 if (Browser
.Engine
.trident
) $A(document
.getElementsByTagName('object')).each(clean
);
1494 if (window
.CollectGarbage
) CollectGarbage();
1495 collected
= storage
= null;
1498 var walk = function(element
, walk
, start
, match
, all
, nocash
){
1499 var el
= element
[start
|| walk
];
1502 if (el
.nodeType
== 1 && (!match
|| Element
.match(el
, match
))){
1503 if (!all
) return $(el
, nocash
);
1508 return (all
) ? new Elements(elements
, {ddup
: false, cash
: !nocash
}) : null;
1512 'html': 'innerHTML',
1513 'class': 'className',
1515 'text': (Browser
.Engine
.trident
|| (Browser
.Engine
.webkit
&& Browser
.Engine
.version
< 420)) ? 'innerText' : 'textContent'
1517 var bools
= ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readonly', 'multiple', 'selected', 'noresize', 'defer'];
1518 var camels
= ['value', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly', 'rowSpan', 'tabIndex', 'useMap'];
1520 Hash
.extend(attributes
, bools
.associate(bools
));
1521 Hash
.extend(attributes
, camels
.associate(camels
.map(String
.toLowerCase
)));
1525 before: function(context
, element
){
1526 if (element
.parentNode
) element
.parentNode
.insertBefore(context
, element
);
1529 after: function(context
, element
){
1530 if (!element
.parentNode
) return;
1531 var next
= element
.nextSibling
;
1532 (next
) ? element
.parentNode
.insertBefore(context
, next
) : element
.parentNode
.appendChild(context
);
1535 bottom: function(context
, element
){
1536 element
.appendChild(context
);
1539 top: function(context
, element
){
1540 var first
= element
.firstChild
;
1541 (first
) ? element
.insertBefore(context
, first
) : element
.appendChild(context
);
1546 inserters
.inside
= inserters
.bottom
;
1548 Hash
.each(inserters
, function(inserter
, where
){
1550 where
= where
.capitalize();
1552 Element
.implement('inject' + where
, function(el
){
1553 inserter(this, $(el
, true));
1557 Element
.implement('grab' + where
, function(el
){
1558 inserter($(el
, true), this);
1566 set: function(prop
, value
){
1567 switch ($type(prop
)){
1569 for (var p
in prop
) this.set(p
, prop
[p
]);
1572 var property
= Element
.Properties
.get(prop
);
1573 (property
&& property
.set) ? property
.set.apply(this, Array
.slice(arguments
, 1)) : this.setProperty(prop
, value
);
1578 get: function(prop
){
1579 var property
= Element
.Properties
.get(prop
);
1580 return (property
&& property
.get) ? property
.get.apply(this, Array
.slice(arguments
, 1)) : this.getProperty(prop
);
1583 erase: function(prop
){
1584 var property
= Element
.Properties
.get(prop
);
1585 (property
&& property
.erase
) ? property
.erase
.apply(this) : this.removeProperty(prop
);
1589 setProperty: function(attribute
, value
){
1590 var key
= attributes
[attribute
];
1591 if (value
== undefined) return this.removeProperty(attribute
);
1592 if (key
&& bools
[attribute
]) value
= !!value
;
1593 (key
) ? this[key
] = value
: this.setAttribute(attribute
, '' + value
);
1597 setProperties: function(attributes
){
1598 for (var attribute
in attributes
) this.setProperty(attribute
, attributes
[attribute
]);
1602 getProperty: function(attribute
){
1603 var key
= attributes
[attribute
];
1604 var value
= (key
) ? this[key
] : this.getAttribute(attribute
, 2);
1605 return (bools
[attribute
]) ? !!value
: (key
) ? value
: value
|| null;
1608 getProperties: function(){
1609 var args
= $A(arguments
);
1610 return args
.map(this.getProperty
, this).associate(args
);
1613 removeProperty: function(attribute
){
1614 var key
= attributes
[attribute
];
1615 (key
) ? this[key
] = (key
&& bools
[attribute
]) ? false : '' : this.removeAttribute(attribute
);
1619 removeProperties: function(){
1620 Array
.each(arguments
, this.removeProperty
, this);
1624 hasClass: function(className
){
1625 return this.className
.contains(className
, ' ');
1628 addClass: function(className
){
1629 if (!this.hasClass(className
)) this.className
= (this.className
+ ' ' + className
).clean();
1633 removeClass: function(className
){
1634 this.className
= this.className
.replace(new RegExp('(^|\\s)' + className
+ '(?:\\s|$)'), '$1');
1638 toggleClass: function(className
){
1639 return this.hasClass(className
) ? this.removeClass(className
) : this.addClass(className
);
1643 Array
.flatten(arguments
).each(function(element
){
1644 element
= $(element
, true);
1645 if (element
) this.appendChild(element
);
1650 appendText: function(text
, where
){
1651 return this.grab(this.getDocument().newTextNode(text
), where
);
1654 grab: function(el
, where
){
1655 inserters
[where
|| 'bottom']($(el
, true), this);
1659 inject: function(el
, where
){
1660 inserters
[where
|| 'bottom'](this, $(el
, true));
1664 replaces: function(el
){
1666 el
.parentNode
.replaceChild(this, el
);
1670 wraps: function(el
, where
){
1672 return this.replaces(el
).grab(el
, where
);
1675 getPrevious: function(match
, nocash
){
1676 return walk(this, 'previousSibling', null, match
, false, nocash
);
1679 getAllPrevious: function(match
, nocash
){
1680 return walk(this, 'previousSibling', null, match
, true, nocash
);
1683 getNext: function(match
, nocash
){
1684 return walk(this, 'nextSibling', null, match
, false, nocash
);
1687 getAllNext: function(match
, nocash
){
1688 return walk(this, 'nextSibling', null, match
, true, nocash
);
1691 getFirst: function(match
, nocash
){
1692 return walk(this, 'nextSibling', 'firstChild', match
, false, nocash
);
1695 getLast: function(match
, nocash
){
1696 return walk(this, 'previousSibling', 'lastChild', match
, false, nocash
);
1699 getParent: function(match
, nocash
){
1700 return walk(this, 'parentNode', null, match
, false, nocash
);
1703 getParents: function(match
, nocash
){
1704 return walk(this, 'parentNode', null, match
, true, nocash
);
1707 getChildren: function(match
, nocash
){
1708 return walk(this, 'nextSibling', 'firstChild', match
, true, nocash
);
1711 getWindow: function(){
1712 return this.ownerDocument
.window
;
1715 getDocument: function(){
1716 return this.ownerDocument
;
1719 getElementById: function(id
, nocash
){
1720 var el
= this.ownerDocument
.getElementById(id
);
1721 if (!el
) return null;
1722 for (var parent
= el
.parentNode
; parent
!= this; parent
= parent
.parentNode
){
1723 if (!parent
) return null;
1725 return $.element(el
, nocash
);
1728 getSelected: function(){
1729 return new Elements($A(this.options
).filter(function(option
){
1730 return option
.selected
;
1734 getComputedStyle: function(property
){
1735 if (this.currentStyle
) return this.currentStyle
[property
.camelCase()];
1736 var computed
= this.getDocument().defaultView
.getComputedStyle(this, null);
1737 return (computed
) ? computed
.getPropertyValue([property
.hyphenate()]) : null;
1740 toQueryString: function(){
1741 var queryString
= [];
1742 this.getElements('input, select, textarea', true).each(function(el
){
1743 if (!el
.name
|| el
.disabled
) return;
1744 var value
= (el
.tagName
.toLowerCase() == 'select') ? Element
.getSelected(el
).map(function(opt
){
1746 }) : ((el
.type
== 'radio' || el
.type
== 'checkbox') && !el
.checked
) ? null : el
.value
;
1747 $splat(value
).each(function(val
){
1748 if (typeof val
!= 'undefined') queryString
.push(el
.name
+ '=' + encodeURIComponent(val
));
1751 return queryString
.join('&');
1754 clone: function(contents
, keepid
){
1755 contents
= contents
!== false;
1756 var clone
= this.cloneNode(contents
);
1757 var clean = function(node
, element
){
1758 if (!keepid
) node
.removeAttribute('id');
1759 if (Browser
.Engine
.trident
){
1760 node
.clearAttributes();
1761 node
.mergeAttributes(element
);
1762 node
.removeAttribute('uid');
1764 var no
= node
.options
, eo
= element
.options
;
1765 for (var j
= no
.length
; j
--;) no
[j
].selected
= eo
[j
].selected
;
1768 var prop
= props
[element
.tagName
.toLowerCase()];
1769 if (prop
&& element
[prop
]) node
[prop
] = element
[prop
];
1773 var ce
= clone
.getElementsByTagName('*'), te
= this.getElementsByTagName('*');
1774 for (var i
= ce
.length
; i
--;) clean(ce
[i
], te
[i
]);
1781 destroy: function(){
1782 Element
.empty(this);
1783 Element
.dispose(this);
1789 $A(this.childNodes
).each(function(node
){
1790 Element
.destroy(node
);
1795 dispose: function(){
1796 return (this.parentNode
) ? this.parentNode
.removeChild(this) : this;
1799 hasChild: function(el
){
1801 if (!el
) return false;
1802 if (Browser
.Engine
.webkit
&& Browser
.Engine
.version
< 420) return $A(this.getElementsByTagName(el
.tagName
)).contains(el
);
1803 return (this.contains
) ? (this != el
&& this.contains(el
)) : !!(this.compareDocumentPosition(el
) & 16);
1806 match: function(tag
){
1807 return (!tag
|| (tag
== this) || (Element
.get(this, 'tag') == tag
));
1812 Native
.implement([Element
, Window
, Document
], {
1814 addListener: function(type
, fn
){
1815 if (type
== 'unload'){
1816 var old
= fn
, self
= this;
1818 self
.removeListener('unload', fn
);
1822 collected
[this.uid
] = this;
1824 if (this.addEventListener
) this.addEventListener(type
, fn
, false);
1825 else this.attachEvent('on' + type
, fn
);
1829 removeListener: function(type
, fn
){
1830 if (this.removeEventListener
) this.removeEventListener(type
, fn
, false);
1831 else this.detachEvent('on' + type
, fn
);
1835 retrieve: function(property
, dflt
){
1836 var storage
= get(this.uid
), prop
= storage
[property
];
1837 if (dflt
!= undefined && prop
== undefined) prop
= storage
[property
] = dflt
;
1841 store: function(property
, value
){
1842 var storage
= get(this.uid
);
1843 storage
[property
] = value
;
1847 eliminate: function(property
){
1848 var storage
= get(this.uid
);
1849 delete storage
[property
];
1855 window
.addListener('unload', purge
);
1859 Element
.Properties
= new Hash
;
1861 Element
.Properties
.style
= {
1863 set: function(style
){
1864 this.style
.cssText
= style
;
1868 return this.style
.cssText
;
1872 this.style
.cssText
= '';
1877 Element
.Properties
.tag
= {
1880 return this.tagName
.toLowerCase();
1885 Element
.Properties
.html
= (function(){
1886 var wrapper
= document
.createElement('div');
1888 var translations
= {
1889 table
: [1, '<table>', '</table>'],
1890 select
: [1, '<select>', '</select>'],
1891 tbody
: [2, '<table><tbody>', '</tbody></table>'],
1892 tr
: [3, '<table><tbody><tr>', '</tr></tbody></table>']
1894 translations
.thead
= translations
.tfoot
= translations
.tbody
;
1898 var html
= Array
.flatten(arguments
).join('');
1899 var wrap
= Browser
.Engine
.trident
&& translations
[this.get('tag')];
1901 var first
= wrapper
;
1902 first
.innerHTML
= wrap
[1] + html
+ wrap
[2];
1903 for (var i
= wrap
[0]; i
--;) first
= first
.firstChild
;
1904 this.empty().adopt(first
.childNodes
);
1906 this.innerHTML
= html
;
1911 html
.erase
= html
.set;
1916 if (Browser
.Engine
.webkit
&& Browser
.Engine
.version
< 420) Element
.Properties
.text
= {
1918 if (this.innerText
) return this.innerText
;
1919 var temp
= this.ownerDocument
.newElement('div', {html
: this.innerHTML
}).inject(this.ownerDocument
.body
);
1920 var text
= temp
.innerText
;
1928 Script: Element.Event.js
1929 Contains Element methods for dealing with events, and custom Events.
1935 Element
.Properties
.events
= {set: function(events
){
1936 this.addEvents(events
);
1939 Native
.implement([Element
, Window
, Document
], {
1941 addEvent: function(type
, fn
){
1942 var events
= this.retrieve('events', {});
1943 events
[type
] = events
[type
] || {'keys': [], 'values': []};
1944 if (events
[type
].keys
.contains(fn
)) return this;
1945 events
[type
].keys
.push(fn
);
1946 var realType
= type
, custom
= Element
.Events
.get(type
), condition
= fn
, self
= this;
1948 if (custom
.onAdd
) custom
.onAdd
.call(this, fn
);
1949 if (custom
.condition
){
1950 condition = function(event
){
1951 if (custom
.condition
.call(this, event
)) return fn
.call(this, event
);
1955 realType
= custom
.base
|| realType
;
1957 var defn = function(){
1958 return fn
.call(self
);
1960 var nativeEvent
= Element
.NativeEvents
[realType
];
1962 if (nativeEvent
== 2){
1963 defn = function(event
){
1964 event
= new Event(event
, self
.getWindow());
1965 if (condition
.call(self
, event
) === false) event
.stop();
1968 this.addListener(realType
, defn
);
1970 events
[type
].values
.push(defn
);
1974 removeEvent: function(type
, fn
){
1975 var events
= this.retrieve('events');
1976 if (!events
|| !events
[type
]) return this;
1977 var pos
= events
[type
].keys
.indexOf(fn
);
1978 if (pos
== -1) return this;
1979 events
[type
].keys
.splice(pos
, 1);
1980 var value
= events
[type
].values
.splice(pos
, 1)[0];
1981 var custom
= Element
.Events
.get(type
);
1983 if (custom
.onRemove
) custom
.onRemove
.call(this, fn
);
1984 type
= custom
.base
|| type
;
1986 return (Element
.NativeEvents
[type
]) ? this.removeListener(type
, value
) : this;
1989 addEvents: function(events
){
1990 for (var event
in events
) this.addEvent(event
, events
[event
]);
1994 removeEvents: function(events
){
1995 if ($type(events
) == 'object'){
1996 for (var type
in events
) this.removeEvent(type
, events
[type
]);
1999 var attached
= this.retrieve('events');
2000 if (!attached
) return this;
2002 for (var type
in attached
) this.removeEvents(type
);
2003 this.eliminate('events');
2004 } else if (attached
[events
]){
2005 while (attached
[events
].keys
[0]) this.removeEvent(events
, attached
[events
].keys
[0]);
2006 attached
[events
] = null;
2011 fireEvent: function(type
, args
, delay
){
2012 var events
= this.retrieve('events');
2013 if (!events
|| !events
[type
]) return this;
2014 events
[type
].keys
.each(function(fn
){
2015 fn
.create({'bind': this, 'delay': delay
, 'arguments': args
})();
2020 cloneEvents: function(from, type
){
2022 var fevents
= from.retrieve('events');
2023 if (!fevents
) return this;
2025 for (var evType
in fevents
) this.cloneEvents(from, evType
);
2026 } else if (fevents
[type
]){
2027 fevents
[type
].keys
.each(function(fn
){
2028 this.addEvent(type
, fn
);
2036 Element
.NativeEvents
= {
2037 click
: 2, dblclick
: 2, mouseup
: 2, mousedown
: 2, contextmenu
: 2, //mouse buttons
2038 mousewheel
: 2, DOMMouseScroll
: 2, //mouse wheel
2039 mouseover
: 2, mouseout
: 2, mousemove
: 2, selectstart
: 2, selectend
: 2, //mouse movement
2040 keydown
: 2, keypress
: 2, keyup
: 2, //keyboard
2041 focus
: 2, blur
: 2, change
: 2, reset
: 2, select
: 2, submit
: 2, //form elements
2042 load
: 1, unload
: 1, beforeunload
: 2, resize
: 1, move: 1, DOMContentLoaded
: 1, readystatechange
: 1, //window
2043 error
: 1, abort
: 1, scroll
: 1 //misc
2048 var $check = function(event
){
2049 var related
= event
.relatedTarget
;
2050 if (related
== undefined) return true;
2051 if (related
=== false) return false;
2052 return ($type(this) != 'document' && related
!= this && related
.prefix
!= 'xul' && !this.hasChild(related
));
2055 Element
.Events
= new Hash({
2068 base
: (Browser
.Engine
.gecko
) ? 'DOMMouseScroll' : 'mousewheel'
2077 Script: Element.Style.js
2078 Contains methods for interacting with the styles of Elements in a fashionable way.
2084 Element
.Properties
.styles
= {set: function(styles
){
2085 this.setStyles(styles
);
2088 Element
.Properties
.opacity
= {
2090 set: function(opacity
, novisibility
){
2093 if (this.style
.visibility
!= 'hidden') this.style
.visibility
= 'hidden';
2095 if (this.style
.visibility
!= 'visible') this.style
.visibility
= 'visible';
2098 if (!this.currentStyle
|| !this.currentStyle
.hasLayout
) this.style
.zoom
= 1;
2099 if (Browser
.Engine
.trident
) this.style
.filter
= (opacity
== 1) ? '' : 'alpha(opacity=' + opacity
* 100 + ')';
2100 this.style
.opacity
= opacity
;
2101 this.store('opacity', opacity
);
2105 return this.retrieve('opacity', 1);
2112 setOpacity: function(value
){
2113 return this.set('opacity', value
, true);
2116 getOpacity: function(){
2117 return this.get('opacity');
2120 setStyle: function(property
, value
){
2122 case 'opacity': return this.set('opacity', parseFloat(value
));
2123 case 'float': property
= (Browser
.Engine
.trident
) ? 'styleFloat' : 'cssFloat';
2125 property
= property
.camelCase();
2126 if ($type(value
) != 'string'){
2127 var map
= (Element
.Styles
.get(property
) || '@').split(' ');
2128 value
= $splat(value
).map(function(val
, i
){
2129 if (!map
[i
]) return '';
2130 return ($type(val
) == 'number') ? map
[i
].replace('@', Math
.round(val
)) : val
;
2132 } else if (value
== String(Number(value
))){
2133 value
= Math
.round(value
);
2135 this.style
[property
] = value
;
2139 getStyle: function(property
){
2141 case 'opacity': return this.get('opacity');
2142 case 'float': property
= (Browser
.Engine
.trident
) ? 'styleFloat' : 'cssFloat';
2144 property
= property
.camelCase();
2145 var result
= this.style
[property
];
2148 for (var style
in Element
.ShortStyles
){
2149 if (property
!= style
) continue;
2150 for (var s
in Element
.ShortStyles
[style
]) result
.push(this.getStyle(s
));
2151 return result
.join(' ');
2153 result
= this.getComputedStyle(property
);
2156 result
= String(result
);
2157 var color
= result
.match(/rgba?\([\d\s,]+\)/);
2158 if (color
) result
= result
.replace(color
[0], color
[0].rgbToHex());
2160 if (Browser
.Engine
.presto
|| (Browser
.Engine
.trident
&& !$chk(parseInt(result
)))){
2161 if (property
.test(/^(height|width)$/)){
2162 var values
= (property
== 'width') ? ['left', 'right'] : ['top', 'bottom'], size
= 0;
2163 values
.each(function(value
){
2164 size
+= this.getStyle('border-' + value
+ '-width').toInt() + this.getStyle('padding-' + value
).toInt();
2166 return this['offset' + property
.capitalize()] - size
+ 'px';
2168 if ((Browser
.Engine
.presto
) && String(result
).test('px')) return result
;
2169 if (property
.test(/(border(.+)Width|margin|padding)/)) return '0px';
2174 setStyles: function(styles
){
2175 for (var style
in styles
) this.setStyle(style
, styles
[style
]);
2179 getStyles: function(){
2181 Array
.each(arguments
, function(key
){
2182 result
[key
] = this.getStyle(key
);
2189 Element
.Styles
= new Hash({
2190 left
: '@px', top
: '@px', bottom
: '@px', right
: '@px',
2191 width
: '@px', height
: '@px', maxWidth
: '@px', maxHeight
: '@px', minWidth
: '@px', minHeight
: '@px',
2192 backgroundColor
: 'rgb(@, @, @)', backgroundPosition
: '@px @px', color
: 'rgb(@, @, @)',
2193 fontSize
: '@px', letterSpacing
: '@px', lineHeight
: '@px', clip
: 'rect(@px @px @px @px)',
2194 margin
: '@px @px @px @px', padding
: '@px @px @px @px', border
: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)',
2195 borderWidth
: '@px @px @px @px', borderStyle
: '@ @ @ @', borderColor
: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)',
2196 zIndex
: '@', 'zoom': '@', fontWeight
: '@', textIndent
: '@px', opacity
: '@'
2199 Element
.ShortStyles
= {margin
: {}, padding
: {}, border
: {}, borderWidth
: {}, borderStyle
: {}, borderColor
: {}};
2201 ['Top', 'Right', 'Bottom', 'Left'].each(function(direction
){
2202 var Short
= Element
.ShortStyles
;
2203 var All
= Element
.Styles
;
2204 ['margin', 'padding'].each(function(style
){
2205 var sd
= style
+ direction
;
2206 Short
[style
][sd
] = All
[sd
] = '@px';
2208 var bd
= 'border' + direction
;
2209 Short
.border
[bd
] = All
[bd
] = '@px @ rgb(@, @, @)';
2210 var bdw
= bd
+ 'Width', bds
= bd
+ 'Style', bdc
= bd
+ 'Color';
2212 Short
.borderWidth
[bdw
] = Short
[bd
][bdw
] = All
[bdw
] = '@px';
2213 Short
.borderStyle
[bds
] = Short
[bd
][bds
] = All
[bds
] = '@';
2214 Short
.borderColor
[bdc
] = Short
[bd
][bdc
] = All
[bdc
] = 'rgb(@, @, @)';
2219 Script: Element.Dimensions.js
2220 Contains methods to work with size, scroll, or positioning of Elements and the window object.
2226 - Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html).
2227 - Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html).
2234 scrollTo: function(x
, y
){
2236 this.getWindow().scrollTo(x
, y
);
2238 this.scrollLeft
= x
;
2244 getSize: function(){
2245 if (isBody(this)) return this.getWindow().getSize();
2246 return {x
: this.offsetWidth
, y
: this.offsetHeight
};
2249 getScrollSize: function(){
2250 if (isBody(this)) return this.getWindow().getScrollSize();
2251 return {x
: this.scrollWidth
, y
: this.scrollHeight
};
2254 getScroll: function(){
2255 if (isBody(this)) return this.getWindow().getScroll();
2256 return {x
: this.scrollLeft
, y
: this.scrollTop
};
2259 getScrolls: function(){
2260 var element
= this, position
= {x
: 0, y
: 0};
2261 while (element
&& !isBody(element
)){
2262 position
.x
+= element
.scrollLeft
;
2263 position
.y
+= element
.scrollTop
;
2264 element
= element
.parentNode
;
2269 getOffsetParent: function(){
2271 if (isBody(element
)) return null;
2272 if (!Browser
.Engine
.trident
) return element
.offsetParent
;
2273 while ((element
= element
.parentNode
) && !isBody(element
)){
2274 if (styleString(element
, 'position') != 'static') return element
;
2279 getOffsets: function(){
2280 if (Browser
.Engine
.trident
){
2281 var bound
= this.getBoundingClientRect(), html
= this.getDocument().documentElement
;
2283 x
: bound
.left
+ html
.scrollLeft
- html
.clientLeft
,
2284 y
: bound
.top
+ html
.scrollTop
- html
.clientTop
2288 var element
= this, position
= {x
: 0, y
: 0};
2289 if (isBody(this)) return position
;
2291 while (element
&& !isBody(element
)){
2292 position
.x
+= element
.offsetLeft
;
2293 position
.y
+= element
.offsetTop
;
2295 if (Browser
.Engine
.gecko
){
2296 if (!borderBox(element
)){
2297 position
.x
+= leftBorder(element
);
2298 position
.y
+= topBorder(element
);
2300 var parent
= element
.parentNode
;
2301 if (parent
&& styleString(parent
, 'overflow') != 'visible'){
2302 position
.x
+= leftBorder(parent
);
2303 position
.y
+= topBorder(parent
);
2305 } else if (element
!= this && Browser
.Engine
.webkit
){
2306 position
.x
+= leftBorder(element
);
2307 position
.y
+= topBorder(element
);
2310 element
= element
.offsetParent
;
2312 if (Browser
.Engine
.gecko
&& !borderBox(this)){
2313 position
.x
-= leftBorder(this);
2314 position
.y
-= topBorder(this);
2319 getPosition: function(relative
){
2320 if (isBody(this)) return {x
: 0, y
: 0};
2321 var offset
= this.getOffsets(), scroll
= this.getScrolls();
2322 var position
= {x
: offset
.x
- scroll
.x
, y
: offset
.y
- scroll
.y
};
2323 var relativePosition
= (relative
&& (relative
= $(relative
))) ? relative
.getPosition() : {x
: 0, y
: 0};
2324 return {x
: position
.x
- relativePosition
.x
, y
: position
.y
- relativePosition
.y
};
2327 getCoordinates: function(element
){
2328 if (isBody(this)) return this.getWindow().getCoordinates();
2329 var position
= this.getPosition(element
), size
= this.getSize();
2330 var obj
= {left
: position
.x
, top
: position
.y
, width
: size
.x
, height
: size
.y
};
2331 obj
.right
= obj
.left
+ obj
.width
;
2332 obj
.bottom
= obj
.top
+ obj
.height
;
2336 computePosition: function(obj
){
2337 return {left
: obj
.x
- styleNumber(this, 'margin-left'), top
: obj
.y
- styleNumber(this, 'margin-top')};
2340 position: function(obj
){
2341 return this.setStyles(this.computePosition(obj
));
2346 Native
.implement([Document
, Window
], {
2348 getSize: function(){
2349 var win
= this.getWindow();
2350 if (Browser
.Engine
.presto
|| Browser
.Engine
.webkit
) return {x
: win
.innerWidth
, y
: win
.innerHeight
};
2351 var doc
= getCompatElement(this);
2352 return {x
: doc
.clientWidth
, y
: doc
.clientHeight
};
2355 getScroll: function(){
2356 var win
= this.getWindow();
2357 var doc
= getCompatElement(this);
2358 return {x
: win
.pageXOffset
|| doc
.scrollLeft
, y
: win
.pageYOffset
|| doc
.scrollTop
};
2361 getScrollSize: function(){
2362 var doc
= getCompatElement(this);
2363 var min
= this.getSize();
2364 return {x
: Math
.max(doc
.scrollWidth
, min
.x
), y
: Math
.max(doc
.scrollHeight
, min
.y
)};
2367 getPosition: function(){
2368 return {x
: 0, y
: 0};
2371 getCoordinates: function(){
2372 var size
= this.getSize();
2373 return {top
: 0, left
: 0, bottom
: size
.y
, right
: size
.x
, height
: size
.y
, width
: size
.x
};
2380 var styleString
= Element
.getComputedStyle
;
2382 function styleNumber(element
, style
){
2383 return styleString(element
, style
).toInt() || 0;
2386 function borderBox(element
){
2387 return styleString(element
, '-moz-box-sizing') == 'border-box';
2390 function topBorder(element
){
2391 return styleNumber(element
, 'border-top-width');
2394 function leftBorder(element
){
2395 return styleNumber(element
, 'border-left-width');
2398 function isBody(element
){
2399 return (/^(?:body|html)$/i).test(element
.tagName
);
2402 function getCompatElement(element
){
2403 var doc
= element
.getDocument();
2404 return (!doc
.compatMode
|| doc
.compatMode
== 'CSS1Compat') ? doc
.html
: doc
.body
;
2411 Native
.implement([Window
, Document
, Element
], {
2413 getHeight: function(){
2414 return this.getSize().y
;
2417 getWidth: function(){
2418 return this.getSize().x
;
2421 getScrollTop: function(){
2422 return this.getScroll().y
;
2425 getScrollLeft: function(){
2426 return this.getScroll().x
;
2429 getScrollHeight: function(){
2430 return this.getScrollSize().y
;
2433 getScrollWidth: function(){
2434 return this.getScrollSize().x
;
2438 return this.getPosition().y
;
2441 getLeft: function(){
2442 return this.getPosition().x
;
2449 Script: Selectors.js
2450 Adds advanced CSS Querying capabilities for targeting elements. Also includes pseudoselectors support.
2456 Native
.implement([Document
, Element
], {
2458 getElements: function(expression
, nocash
){
2459 expression
= expression
.split(',');
2460 var items
, local
= {};
2461 for (var i
= 0, l
= expression
.length
; i
< l
; i
++){
2462 var selector
= expression
[i
], elements
= Selectors
.Utils
.search(this, selector
, local
);
2463 if (i
!= 0 && elements
.item
) elements
= $A(elements
);
2464 items
= (i
== 0) ? elements
: (items
.item
) ? $A(items
).concat(elements
) : items
.concat(elements
);
2466 return new Elements(items
, {ddup
: (expression
.length
> 1), cash
: !nocash
});
2473 match: function(selector
){
2474 if (!selector
|| (selector
== this)) return true;
2475 var tagid
= Selectors
.Utils
.parseTagAndID(selector
);
2476 var tag
= tagid
[0], id
= tagid
[1];
2477 if (!Selectors
.Filters
.byID(this, id
) || !Selectors
.Filters
.byTag(this, tag
)) return false;
2478 var parsed
= Selectors
.Utils
.parseSelector(selector
);
2479 return (parsed
) ? Selectors
.Utils
.filter(this, parsed
, {}) : true;
2484 var Selectors
= {Cache
: {nth
: {}, parsed
: {}}};
2486 Selectors
.RegExps
= {
2489 quick
: (/^(\w+|\*)$/),
2490 splitter
: (/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g),
2491 combined
: (/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)(["']?)([^\4]*?)\4)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g)
2496 chk: function(item
, uniques
){
2497 if (!uniques
) return true;
2498 var uid
= $uid(item
);
2499 if (!uniques
[uid
]) return uniques
[uid
] = true;
2503 parseNthArgument: function(argument
){
2504 if (Selectors
.Cache
.nth
[argument
]) return Selectors
.Cache
.nth
[argument
];
2505 var parsed
= argument
.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/);
2506 if (!parsed
) return false;
2507 var inta
= parseInt(parsed
[1]);
2508 var a
= (inta
|| inta
=== 0) ? inta
: 1;
2509 var special
= parsed
[2] || false;
2510 var b
= parseInt(parsed
[3]) || 0;
2513 while (b
< 1) b
+= a
;
2514 while (b
>= a
) b
-= a
;
2520 case 'n': parsed
= {a
: a
, b
: b
, special
: 'n'}; break;
2521 case 'odd': parsed
= {a
: 2, b
: 0, special
: 'n'}; break;
2522 case 'even': parsed
= {a
: 2, b
: 1, special
: 'n'}; break;
2523 case 'first': parsed
= {a
: 0, special
: 'index'}; break;
2524 case 'last': parsed
= {special
: 'last-child'}; break;
2525 case 'only': parsed
= {special
: 'only-child'}; break;
2526 default: parsed
= {a
: (a
- 1), special
: 'index'};
2529 return Selectors
.Cache
.nth
[argument
] = parsed
;
2532 parseSelector: function(selector
){
2533 if (Selectors
.Cache
.parsed
[selector
]) return Selectors
.Cache
.parsed
[selector
];
2534 var m
, parsed
= {classes
: [], pseudos
: [], attributes
: []};
2535 while ((m
= Selectors
.RegExps
.combined
.exec(selector
))){
2536 var cn
= m
[1], an
= m
[2], ao
= m
[3], av
= m
[5], pn
= m
[6], pa
= m
[7];
2538 parsed
.classes
.push(cn
);
2540 var parser
= Selectors
.Pseudo
.get(pn
);
2541 if (parser
) parsed
.pseudos
.push({parser
: parser
, argument
: pa
});
2542 else parsed
.attributes
.push({name
: pn
, operator
: '=', value
: pa
});
2544 parsed
.attributes
.push({name
: an
, operator
: ao
, value
: av
});
2547 if (!parsed
.classes
.length
) delete parsed
.classes
;
2548 if (!parsed
.attributes
.length
) delete parsed
.attributes
;
2549 if (!parsed
.pseudos
.length
) delete parsed
.pseudos
;
2550 if (!parsed
.classes
&& !parsed
.attributes
&& !parsed
.pseudos
) parsed
= null;
2551 return Selectors
.Cache
.parsed
[selector
] = parsed
;
2554 parseTagAndID: function(selector
){
2555 var tag
= selector
.match(Selectors
.RegExps
.tag
);
2556 var id
= selector
.match(Selectors
.RegExps
.id
);
2557 return [(tag
) ? tag
[1] : '*', (id
) ? id
[1] : false];
2560 filter: function(item
, parsed
, local
){
2562 if (parsed
.classes
){
2563 for (i
= parsed
.classes
.length
; i
--; i
){
2564 var cn
= parsed
.classes
[i
];
2565 if (!Selectors
.Filters
.byClass(item
, cn
)) return false;
2568 if (parsed
.attributes
){
2569 for (i
= parsed
.attributes
.length
; i
--; i
){
2570 var att
= parsed
.attributes
[i
];
2571 if (!Selectors
.Filters
.byAttribute(item
, att
.name
, att
.operator
, att
.value
)) return false;
2574 if (parsed
.pseudos
){
2575 for (i
= parsed
.pseudos
.length
; i
--; i
){
2576 var psd
= parsed
.pseudos
[i
];
2577 if (!Selectors
.Filters
.byPseudo(item
, psd
.parser
, psd
.argument
, local
)) return false;
2583 getByTagAndID: function(ctx
, tag
, id
){
2585 var item
= (ctx
.getElementById
) ? ctx
.getElementById(id
, true) : Element
.getElementById(ctx
, id
, true);
2586 return (item
&& Selectors
.Filters
.byTag(item
, tag
)) ? [item
] : [];
2588 return ctx
.getElementsByTagName(tag
);
2592 search: function(self
, expression
, local
){
2595 var selectors
= expression
.trim().replace(Selectors
.RegExps
.splitter
, function(m0
, m1
, m2
){
2600 var items
, filtered
, item
;
2602 for (var i
= 0, l
= selectors
.length
; i
< l
; i
++){
2604 var selector
= selectors
[i
];
2606 if (i
== 0 && Selectors
.RegExps
.quick
.test(selector
)){
2607 items
= self
.getElementsByTagName(selector
);
2611 var splitter
= splitters
[i
- 1];
2613 var tagid
= Selectors
.Utils
.parseTagAndID(selector
);
2614 var tag
= tagid
[0], id
= tagid
[1];
2617 items
= Selectors
.Utils
.getByTagAndID(self
, tag
, id
);
2619 var uniques
= {}, found
= [];
2620 for (var j
= 0, k
= items
.length
; j
< k
; j
++) found
= Selectors
.Getters
[splitter
](found
, items
[j
], tag
, id
, uniques
);
2624 var parsed
= Selectors
.Utils
.parseSelector(selector
);
2628 for (var m
= 0, n
= items
.length
; m
< n
; m
++){
2630 if (Selectors
.Utils
.filter(item
, parsed
, local
)) filtered
.push(item
);
2643 Selectors
.Getters
= {
2645 ' ': function(found
, self
, tag
, id
, uniques
){
2646 var items
= Selectors
.Utils
.getByTagAndID(self
, tag
, id
);
2647 for (var i
= 0, l
= items
.length
; i
< l
; i
++){
2648 var item
= items
[i
];
2649 if (Selectors
.Utils
.chk(item
, uniques
)) found
.push(item
);
2654 '>': function(found
, self
, tag
, id
, uniques
){
2655 var children
= Selectors
.Utils
.getByTagAndID(self
, tag
, id
);
2656 for (var i
= 0, l
= children
.length
; i
< l
; i
++){
2657 var child
= children
[i
];
2658 if (child
.parentNode
== self
&& Selectors
.Utils
.chk(child
, uniques
)) found
.push(child
);
2663 '+': function(found
, self
, tag
, id
, uniques
){
2664 while ((self
= self
.nextSibling
)){
2665 if (self
.nodeType
== 1){
2666 if (Selectors
.Utils
.chk(self
, uniques
) && Selectors
.Filters
.byTag(self
, tag
) && Selectors
.Filters
.byID(self
, id
)) found
.push(self
);
2673 '~': function(found
, self
, tag
, id
, uniques
){
2674 while ((self
= self
.nextSibling
)){
2675 if (self
.nodeType
== 1){
2676 if (!Selectors
.Utils
.chk(self
, uniques
)) break;
2677 if (Selectors
.Filters
.byTag(self
, tag
) && Selectors
.Filters
.byID(self
, id
)) found
.push(self
);
2685 Selectors
.Filters
= {
2687 byTag: function(self
, tag
){
2688 return (tag
== '*' || (self
.tagName
&& self
.tagName
.toLowerCase() == tag
));
2691 byID: function(self
, id
){
2692 return (!id
|| (self
.id
&& self
.id
== id
));
2695 byClass: function(self
, klass
){
2696 return (self
.className
&& self
.className
.contains(klass
, ' '));
2699 byPseudo: function(self
, parser
, argument
, local
){
2700 return parser
.call(self
, argument
, local
);
2703 byAttribute: function(self
, name
, operator
, value
){
2704 var result
= Element
.prototype.getProperty
.call(self
, name
);
2705 if (!result
) return (operator
== '!=');
2706 if (!operator
|| value
== undefined) return true;
2708 case '=': return (result
== value
);
2709 case '*=': return (result
.contains(value
));
2710 case '^=': return (result
.substr(0, value
.length
) == value
);
2711 case '$=': return (result
.substr(result
.length
- value
.length
) == value
);
2712 case '!=': return (result
!= value
);
2713 case '~=': return result
.contains(value
, ' ');
2714 case '|=': return result
.contains(value
, '-');
2721 Selectors
.Pseudo
= new Hash({
2723 // w3c pseudo selectors
2725 checked: function(){
2726 return this.checked
;
2730 return !(this.innerText
|| this.textContent
|| '').length
;
2733 not: function(selector
){
2734 return !Element
.match(this, selector
);
2737 contains: function(text
){
2738 return (this.innerText
|| this.textContent
|| '').contains(text
);
2741 'first-child': function(){
2742 return Selectors
.Pseudo
.index
.call(this, 0);
2745 'last-child': function(){
2747 while ((element
= element
.nextSibling
)){
2748 if (element
.nodeType
== 1) return false;
2753 'only-child': function(){
2755 while ((prev
= prev
.previousSibling
)){
2756 if (prev
.nodeType
== 1) return false;
2759 while ((next
= next
.nextSibling
)){
2760 if (next
.nodeType
== 1) return false;
2765 'nth-child': function(argument
, local
){
2766 argument
= (argument
== undefined) ? 'n' : argument
;
2767 var parsed
= Selectors
.Utils
.parseNthArgument(argument
);
2768 if (parsed
.special
!= 'n') return Selectors
.Pseudo
[parsed
.special
].call(this, parsed
.a
, local
);
2770 local
.positions
= local
.positions
|| {};
2771 var uid
= $uid(this);
2772 if (!local
.positions
[uid
]){
2774 while ((self
= self
.previousSibling
)){
2775 if (self
.nodeType
!= 1) continue;
2777 var position
= local
.positions
[$uid(self
)];
2778 if (position
!= undefined){
2779 count
= position
+ count
;
2783 local
.positions
[uid
] = count
;
2785 return (local
.positions
[uid
] % parsed
.a
== parsed
.b
);
2788 // custom pseudo selectors
2790 index: function(index
){
2791 var element
= this, count
= 0;
2792 while ((element
= element
.previousSibling
)){
2793 if (element
.nodeType
== 1 && ++count
> index
) return false;
2795 return (count
== index
);
2798 even: function(argument
, local
){
2799 return Selectors
.Pseudo
['nth-child'].call(this, '2n+1', local
);
2802 odd: function(argument
, local
){
2803 return Selectors
.Pseudo
['nth-child'].call(this, '2n', local
);
2811 Contains the domready custom event.
2817 Element
.Events
.domready
= {
2819 onAdd: function(fn
){
2820 if (Browser
.loaded
) fn
.call(this);
2827 var domready = function(){
2828 if (Browser
.loaded
) return;
2829 Browser
.loaded
= true;
2830 window
.fireEvent('domready');
2831 document
.fireEvent('domready');
2834 if (Browser
.Engine
.trident
){
2835 var temp
= document
.createElement('div');
2838 temp
.doScroll('left');
2839 return $(temp
).inject(document
.body
).set('html', 'temp').dispose();
2840 })) ? domready() : arguments
.callee
.delay(50);
2842 } else if (Browser
.Engine
.webkit
&& Browser
.Engine
.version
< 525){
2844 (['loaded', 'complete'].contains(document
.readyState
)) ? domready() : arguments
.callee
.delay(50);
2847 window
.addEvent('load', domready
);
2848 document
.addEvent('DOMContentLoaded', domready
);
2856 JSON encoder and decoder.
2862 <http://www.json.org/>
2865 var JSON
= new Hash({
2867 $specialChars
: {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'},
2869 $replaceChars: function(chr
){
2870 return JSON
.$specialChars
[chr
] || '\\u00' + Math
.floor(chr
.charCodeAt() / 16).toString(16) + (chr
.charCodeAt() % 16).toString(16);
2873 encode: function(obj
){
2874 switch ($type(obj
)){
2876 return '"' + obj
.replace(/[\x00-\x1f\\"]/g, JSON
.$replaceChars
) + '"';
2878 return '[' + String(obj
.map(JSON
.encode
).filter($defined
)) + ']';
2879 case 'object': case 'hash':
2881 Hash
.each(obj
, function(value
, key
){
2882 var json
= JSON
.encode(value
);
2883 if (json
) string
.push(JSON
.encode(key
) + ':' + json
);
2885 return '{' + string
+ '}';
2886 case 'number': case 'boolean': return String(obj
);
2887 case false: return 'null';
2892 decode: function(string
, secure
){
2893 if ($type(string
) != 'string' || !string
.length
) return null;
2894 if (secure
&& !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string
.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) return null;
2895 return eval('(' + string
+ ')');
2900 Native
.implement([Hash
, Array
, String
, Number
], {
2903 return JSON
.encode(this);
2911 Class for creating, loading, and saving browser Cookies.
2917 Based on the functions by Peter-Paul Koch (http://quirksmode.org).
2920 var Cookie
= new Class({
2922 Implements
: Options
,
2932 initialize: function(key
, options
){
2934 this.setOptions(options
);
2937 write: function(value
){
2938 value
= encodeURIComponent(value
);
2939 if (this.options
.domain
) value
+= '; domain=' + this.options
.domain
;
2940 if (this.options
.path
) value
+= '; path=' + this.options
.path
;
2941 if (this.options
.duration
){
2942 var date
= new Date();
2943 date
.setTime(date
.getTime() + this.options
.duration
* 24 * 60 * 60 * 1000);
2944 value
+= '; expires=' + date
.toGMTString();
2946 if (this.options
.secure
) value
+= '; secure';
2947 this.options
.document
.cookie
= this.key
+ '=' + value
;
2952 var value
= this.options
.document
.cookie
.match('(?:^|;)\\s*' + this.key
.escapeRegExp() + '=([^;]*)');
2953 return (value
) ? decodeURIComponent(value
[1]) : null;
2956 dispose: function(){
2957 new Cookie(this.key
, $merge(this.options
, {duration
: -1})).write('');
2963 Cookie
.write = function(key
, value
, options
){
2964 return new Cookie(key
, options
).write(value
);
2967 Cookie
.read = function(key
){
2968 return new Cookie(key
).read();
2971 Cookie
.dispose = function(key
, options
){
2972 return new Cookie(key
, options
).dispose();
2978 Wrapper for embedding SWF movies. Supports (and fixes) External Interface Communication.
2984 Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject.
2987 var Swiff
= new Class({
2989 Implements
: [Options
],
2999 allowScriptAccess
: 'always',
3000 wMode
: 'transparent',
3007 toElement: function(){
3011 initialize: function(path
, options
){
3012 this.instance
= 'Swiff_' + $time();
3014 this.setOptions(options
);
3015 options
= this.options
;
3016 var id
= this.id
= options
.id
|| this.instance
;
3017 var container
= $(options
.container
);
3019 Swiff
.CallBacks
[this.instance
] = {};
3021 var params
= options
.params
, vars
= options
.vars
, callBacks
= options
.callBacks
;
3022 var properties
= $extend({height
: options
.height
, width
: options
.width
}, options
.properties
);
3026 for (var callBack
in callBacks
){
3027 Swiff
.CallBacks
[this.instance
][callBack
] = (function(option
){
3029 return option
.apply(self
.object
, arguments
);
3031 })(callBacks
[callBack
]);
3032 vars
[callBack
] = 'Swiff.CallBacks.' + this.instance
+ '.' + callBack
;
3035 params
.flashVars
= Hash
.toQueryString(vars
);
3036 if (Browser
.Engine
.trident
){
3037 properties
.classid
= 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000';
3038 params
.movie
= path
;
3040 properties
.type
= 'application/x-shockwave-flash';
3041 properties
.data
= path
;
3043 var build
= '<object id="' + id
+ '"';
3044 for (var property
in properties
) build
+= ' ' + property
+ '="' + properties
[property
] + '"';
3046 for (var param
in params
){
3047 if (params
[param
]) build
+= '<param name="' + param
+ '" value="' + params
[param
] + '" />';
3049 build
+= '</object>';
3050 this.object
= ((container
) ? container
.empty() : new Element('div')).set('html', build
).firstChild
;
3053 replaces: function(element
){
3054 element
= $(element
, true);
3055 element
.parentNode
.replaceChild(this.toElement(), element
);
3059 inject: function(element
){
3060 $(element
, true).appendChild(this.toElement());
3065 return Swiff
.remote
.apply(Swiff
, [this.toElement()].extend(arguments
));
3070 Swiff
.CallBacks
= {};
3072 Swiff
.remote = function(obj
, fn
){
3073 var rs
= obj
.CallFunction('<invoke name="' + fn
+ '" returntype="javascript">' + __flash__argumentsToXML(arguments
, 2) + '</invoke>');
3080 Contains the basic animation logic to be extended by all other Fx Classes.
3086 var Fx
= new Class({
3088 Implements
: [Chain
, Events
, Options
],
3102 initialize: function(options
){
3103 this.subject
= this.subject
|| this;
3104 this.setOptions(options
);
3105 this.options
.duration
= Fx
.Durations
[this.options
.duration
] || this.options
.duration
.toInt();
3106 var wait
= this.options
.wait
;
3107 if (wait
=== false) this.options
.link
= 'cancel';
3110 getTransition: function(){
3112 return -(Math
.cos(Math
.PI
* p
) - 1) / 2;
3118 if (time
< this.time
+ this.options
.duration
){
3119 var delta
= this.transition((time
- this.time
) / this.options
.duration
);
3120 this.set(this.compute(this.from, this.to
, delta
));
3122 this.set(this.compute(this.from, this.to
, 1));
3131 compute: function(from, to
, delta
){
3132 return Fx
.compute(from, to
, delta
);
3135 check: function(caller
){
3136 if (!this.timer
) return true;
3137 switch (this.options
.link
){
3138 case 'cancel': this.cancel(); return true;
3139 case 'chain': this.chain(caller
.bind(this, Array
.slice(arguments
, 1))); return false;
3144 start: function(from, to
){
3145 if (!this.check(arguments
.callee
, from, to
)) return this;
3149 this.transition
= this.getTransition();
3155 complete: function(){
3156 if (this.stopTimer()) this.onComplete();
3161 if (this.stopTimer()) this.onCancel();
3165 onStart: function(){
3166 this.fireEvent('start', this.subject
);
3169 onComplete: function(){
3170 this.fireEvent('complete', this.subject
);
3171 if (!this.callChain()) this.fireEvent('chainComplete', this.subject
);
3174 onCancel: function(){
3175 this.fireEvent('cancel', this.subject
).clearChain();
3188 stopTimer: function(){
3189 if (!this.timer
) return false;
3190 this.time
= $time() - this.time
;
3191 this.timer
= $clear(this.timer
);
3195 startTimer: function(){
3196 if (this.timer
) return false;
3197 this.time
= $time() - this.time
;
3198 this.timer
= this.step
.periodical(Math
.round(1000 / this.options
.fps
), this);
3204 Fx
.compute = function(from, to
, delta
){
3205 return (to
- from) * delta
+ from;
3208 Fx
.Durations
= {'short': 250, 'normal': 500, 'long': 1000};
3213 Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements.
3219 Fx
.CSS
= new Class({
3223 //prepares the base from/to object
3225 prepare: function(element
, property
, values
){
3226 values
= $splat(values
);
3227 var values1
= values
[1];
3228 if (!$chk(values1
)){
3229 values
[1] = values
[0];
3230 values
[0] = element
.getStyle(property
);
3232 var parsed
= values
.map(this.parse
);
3233 return {from: parsed
[0], to
: parsed
[1]};
3236 //parses a value into an array
3238 parse: function(value
){
3239 value
= $lambda(value
)();
3240 value
= (typeof value
== 'string') ? value
.split(' ') : $splat(value
);
3241 return value
.map(function(val
){
3244 Fx
.CSS
.Parsers
.each(function(parser
, key
){
3246 var parsed
= parser
.parse(val
);
3247 if ($chk(parsed
)) found
= {value
: parsed
, parser
: parser
};
3249 found
= found
|| {value
: val
, parser
: Fx
.CSS
.Parsers
.String
};
3254 //computes by a from and to prepared objects, using their parsers.
3256 compute: function(from, to
, delta
){
3258 (Math
.min(from.length
, to
.length
)).times(function(i
){
3259 computed
.push({value
: from[i
].parser
.compute(from[i
].value
, to
[i
].value
, delta
), parser
: from[i
].parser
});
3261 computed
.$family
= {name
: 'fx:css:value'};
3265 //serves the value as settable
3267 serve: function(value
, unit
){
3268 if ($type(value
) != 'fx:css:value') value
= this.parse(value
);
3270 value
.each(function(bit
){
3271 returned
= returned
.concat(bit
.parser
.serve(bit
.value
, unit
));
3276 //renders the change to an element
3278 render: function(element
, property
, value
, unit
){
3279 element
.setStyle(property
, this.serve(value
, unit
));
3282 //searches inside the page css to find the values for a selector
3284 search: function(selector
){
3285 if (Fx
.CSS
.Cache
[selector
]) return Fx
.CSS
.Cache
[selector
];
3287 Array
.each(document
.styleSheets
, function(sheet
, j
){
3288 var href
= sheet
.href
;
3289 if (href
&& href
.contains('://') && !href
.contains(document
.domain
)) return;
3290 var rules
= sheet
.rules
|| sheet
.cssRules
;
3291 Array
.each(rules
, function(rule
, i
){
3292 if (!rule
.style
) return;
3293 var selectorText
= (rule
.selectorText
) ? rule
.selectorText
.replace(/^\w+/, function(m
){
3294 return m
.toLowerCase();
3296 if (!selectorText
|| !selectorText
.test('^' + selector
+ '$')) return;
3297 Element
.Styles
.each(function(value
, style
){
3298 if (!rule
.style
[style
] || Element
.ShortStyles
[style
]) return;
3299 value
= String(rule
.style
[style
]);
3300 to
[style
] = (value
.test(/^rgb/)) ? value
.rgbToHex() : value
;
3304 return Fx
.CSS
.Cache
[selector
] = to
;
3311 Fx
.CSS
.Parsers
= new Hash({
3314 parse: function(value
){
3315 if (value
.match(/^#[0-9a-f]{3,6}$/i)) return value
.hexToRgb(true);
3316 return ((value
= value
.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value
[1], value
[2], value
[3]] : false;
3318 compute: function(from, to
, delta
){
3319 return from.map(function(value
, i
){
3320 return Math
.round(Fx
.compute(from[i
], to
[i
], delta
));
3323 serve: function(value
){
3324 return value
.map(Number
);
3330 compute
: Fx
.compute
,
3331 serve: function(value
, unit
){
3332 return (unit
) ? value
+ unit
: value
;
3337 parse
: $lambda(false),
3338 compute
: $arguments(1),
3339 serve
: $arguments(0)
3347 Formerly Fx.Style, effect to transition any CSS property for an element.
3353 Fx
.Tween
= new Class({
3357 initialize: function(element
, options
){
3358 this.element
= this.subject
= $(element
);
3359 this.parent(options
);
3362 set: function(property
, now
){
3363 if (arguments
.length
== 1){
3365 property
= this.property
|| this.options
.property
;
3367 this.render(this.element
, property
, now
, this.options
.unit
);
3371 start: function(property
, from, to
){
3372 if (!this.check(arguments
.callee
, property
, from, to
)) return this;
3373 var args
= Array
.flatten(arguments
);
3374 this.property
= this.options
.property
|| args
.shift();
3375 var parsed
= this.prepare(this.element
, this.property
, args
);
3376 return this.parent(parsed
.from, parsed
.to
);
3381 Element
.Properties
.tween
= {
3383 set: function(options
){
3384 var tween
= this.retrieve('tween');
3385 if (tween
) tween
.cancel();
3386 return this.eliminate('tween').store('tween:options', $extend({link
: 'cancel'}, options
));
3389 get: function(options
){
3390 if (options
|| !this.retrieve('tween')){
3391 if (options
|| !this.retrieve('tween:options')) this.set('tween', options
);
3392 this.store('tween', new Fx
.Tween(this, this.retrieve('tween:options')));
3394 return this.retrieve('tween');
3401 tween: function(property
, from, to
){
3402 this.get('tween').start(arguments
);
3406 fade: function(how
){
3407 var fade
= this.get('tween'), o
= 'opacity', toggle
;
3408 how
= $pick(how
, 'toggle');
3410 case 'in': fade
.start(o
, 1); break;
3411 case 'out': fade
.start(o
, 0); break;
3412 case 'show': fade
.set(o
, 1); break;
3413 case 'hide': fade
.set(o
, 0); break;
3415 var flag
= this.retrieve('fade:flag', this.get('opacity') == 1);
3416 fade
.start(o
, (flag
) ? 0 : 1);
3417 this.store('fade:flag', !flag
);
3420 default: fade
.start(o
, arguments
);
3422 if (!toggle
) this.eliminate('fade:flag');
3426 highlight: function(start
, end
){
3428 end
= this.retrieve('highlight:original', this.getStyle('background-color'));
3429 end
= (end
== 'transparent') ? '#fff' : end
;
3431 var tween
= this.get('tween');
3432 tween
.start('background-color', start
|| '#ffff88', end
).chain(function(){
3433 this.setStyle('background-color', this.retrieve('highlight:original'));
3444 Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules.
3450 Fx
.Morph
= new Class({
3454 initialize: function(element
, options
){
3455 this.element
= this.subject
= $(element
);
3456 this.parent(options
);
3460 if (typeof now
== 'string') now
= this.search(now
);
3461 for (var p
in now
) this.render(this.element
, p
, now
[p
], this.options
.unit
);
3465 compute: function(from, to
, delta
){
3467 for (var p
in from) now
[p
] = this.parent(from[p
], to
[p
], delta
);
3471 start: function(properties
){
3472 if (!this.check(arguments
.callee
, properties
)) return this;
3473 if (typeof properties
== 'string') properties
= this.search(properties
);
3474 var from = {}, to
= {};
3475 for (var p
in properties
){
3476 var parsed
= this.prepare(this.element
, p
, properties
[p
]);
3477 from[p
] = parsed
.from;
3480 return this.parent(from, to
);
3485 Element
.Properties
.morph
= {
3487 set: function(options
){
3488 var morph
= this.retrieve('morph');
3489 if (morph
) morph
.cancel();
3490 return this.eliminate('morph').store('morph:options', $extend({link
: 'cancel'}, options
));
3493 get: function(options
){
3494 if (options
|| !this.retrieve('morph')){
3495 if (options
|| !this.retrieve('morph:options')) this.set('morph', options
);
3496 this.store('morph', new Fx
.Morph(this, this.retrieve('morph:options')));
3498 return this.retrieve('morph');
3505 morph: function(props
){
3506 this.get('morph').start(props
);
3514 Script: Fx.Transitions.js
3515 Contains a set of advanced transitions to be used with any of the Fx Classes.
3521 Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified and optimized to be used with MooTools.
3526 getTransition: function(){
3527 var trans
= this.options
.transition
|| Fx
.Transitions
.Sine
.easeInOut
;
3528 if (typeof trans
== 'string'){
3529 var data
= trans
.split(':');
3530 trans
= Fx
.Transitions
;
3531 trans
= trans
[data
[0]] || trans
[data
[0].capitalize()];
3532 if (data
[1]) trans
= trans
['ease' + data
[1].capitalize() + (data
[2] ? data
[2].capitalize() : '')];
3539 Fx
.Transition = function(transition
, params
){
3540 params
= $splat(params
);
3541 return $extend(transition
, {
3542 easeIn: function(pos
){
3543 return transition(pos
, params
);
3545 easeOut: function(pos
){
3546 return 1 - transition(1 - pos
, params
);
3548 easeInOut: function(pos
){
3549 return (pos
<= 0.5) ? transition(2 * pos
, params
) / 2 : (2 - transition(2 * (1 - pos
), params
)) / 2;
3554 Fx
.Transitions
= new Hash({
3556 linear
: $arguments(0)
3560 Fx
.Transitions
.extend = function(transitions
){
3561 for (var transition
in transitions
) Fx
.Transitions
[transition
] = new Fx
.Transition(transitions
[transition
]);
3564 Fx
.Transitions
.extend({
3566 Pow: function(p
, x
){
3567 return Math
.pow(p
, x
[0] || 6);
3571 return Math
.pow(2, 8 * (p
- 1));
3575 return 1 - Math
.sin(Math
.acos(p
));
3579 return 1 - Math
.sin((1 - p
) * Math
.PI
/ 2);
3582 Back: function(p
, x
){
3584 return Math
.pow(p
, 2) * ((x
+ 1) * p
- x
);
3587 Bounce: function(p
){
3589 for (var a
= 0, b
= 1; 1; a
+= b
, b
/= 2){
3590 if (p
>= (7 - 4 * a
) / 11){
3591 value
= b
* b
- Math
.pow((11 - 6 * a
- 11 * p
) / 4, 2);
3598 Elastic: function(p
, x
){
3599 return Math
.pow(2, 10 * --p
) * Math
.cos(20 * p
* Math
.PI
* (x
[0] || 1) / 3);
3604 ['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition
, i
){
3605 Fx
.Transitions
[transition
] = new Fx
.Transition(function(p
){
3606 return Math
.pow(p
, [i
+ 2]);
3613 Powerful all purpose Request Class. Uses XMLHTTPRequest.
3619 var Request
= new Class({
3621 Implements
: [Chain
, Events
, Options
],
3629 onException: $empty,*/
3633 'X-Requested-With': 'XMLHttpRequest',
3634 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
3648 initialize: function(options
){
3649 this.xhr
= new Browser
.Request();
3650 this.setOptions(options
);
3651 this.options
.isSuccess
= this.options
.isSuccess
|| this.isSuccess
;
3652 this.headers
= new Hash(this.options
.headers
);
3655 onStateChange: function(){
3656 if (this.xhr
.readyState
!= 4 || !this.running
) return;
3657 this.running
= false;
3660 this.status
= this.xhr
.status
;
3662 if (this.options
.isSuccess
.call(this, this.status
)){
3663 this.response
= {text
: this.xhr
.responseText
, xml
: this.xhr
.responseXML
};
3664 this.success(this.response
.text
, this.response
.xml
);
3666 this.response
= {text
: null, xml
: null};
3669 this.xhr
.onreadystatechange
= $empty
;
3672 isSuccess: function(){
3673 return ((this.status
>= 200) && (this.status
< 300));
3676 processScripts: function(text
){
3677 if (this.options
.evalResponse
|| (/(ecma|java)script/).test(this.getHeader('Content-type'))) return $exec(text
);
3678 return text
.stripScripts(this.options
.evalScripts
);
3681 success: function(text
, xml
){
3682 this.onSuccess(this.processScripts(text
), xml
);
3685 onSuccess: function(){
3686 this.fireEvent('complete', arguments
).fireEvent('success', arguments
).callChain();
3689 failure: function(){
3693 onFailure: function(){
3694 this.fireEvent('complete').fireEvent('failure', this.xhr
);
3697 setHeader: function(name
, value
){
3698 this.headers
.set(name
, value
);
3702 getHeader: function(name
){
3703 return $try(function(){
3704 return this.xhr
.getResponseHeader(name
);
3708 check: function(caller
){
3709 if (!this.running
) return true;
3710 switch (this.options
.link
){
3711 case 'cancel': this.cancel(); return true;
3712 case 'chain': this.chain(caller
.bind(this, Array
.slice(arguments
, 1))); return false;
3717 send: function(options
){
3718 if (!this.check(arguments
.callee
, options
)) return this;
3719 this.running
= true;
3721 var type
= $type(options
);
3722 if (type
== 'string' || type
== 'element') options
= {data
: options
};
3724 var old
= this.options
;
3725 options
= $extend({data
: old
.data
, url
: old
.url
, method
: old
.method
}, options
);
3726 var data
= options
.data
, url
= options
.url
, method
= options
.method
;
3728 switch ($type(data
)){
3729 case 'element': data
= $(data
).toQueryString(); break;
3730 case 'object': case 'hash': data
= Hash
.toQueryString(data
);
3733 if (this.options
.format
){
3734 var format
= 'format=' + this.options
.format
;
3735 data
= (data
) ? format
+ '&' + data
: format
;
3738 if (this.options
.emulation
&& ['put', 'delete'].contains(method
)){
3739 var _method
= '_method=' + method
;
3740 data
= (data
) ? _method
+ '&' + data
: _method
;
3744 if (this.options
.urlEncoded
&& method
== 'post'){
3745 var encoding
= (this.options
.encoding
) ? '; charset=' + this.options
.encoding
: '';
3746 this.headers
.set('Content-type', 'application/x-www-form-urlencoded' + encoding
);
3749 if (data
&& method
== 'get'){
3750 url
= url
+ (url
.contains('?') ? '&' : '?') + data
;
3754 this.xhr
.open(method
.toUpperCase(), url
, this.options
.async
);
3756 this.xhr
.onreadystatechange
= this.onStateChange
.bind(this);
3758 this.headers
.each(function(value
, key
){
3760 this.xhr
.setRequestHeader(key
, value
);
3762 this.fireEvent('exception', [key
, value
]);
3766 this.fireEvent('request');
3767 this.xhr
.send(data
);
3768 if (!this.options
.async
) this.onStateChange();
3773 if (!this.running
) return this;
3774 this.running
= false;
3776 this.xhr
.onreadystatechange
= $empty
;
3777 this.xhr
= new Browser
.Request();
3778 this.fireEvent('cancel');
3787 ['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method
){
3788 methods
[method
] = function(){
3789 var params
= Array
.link(arguments
, {url
: String
.type
, data
: $defined
});
3790 return this.send($extend(params
, {method
: method
.toLowerCase()}));
3794 Request
.implement(methods
);
3798 Element
.Properties
.send
= {
3800 set: function(options
){
3801 var send
= this.retrieve('send');
3802 if (send
) send
.cancel();
3803 return this.eliminate('send').store('send:options', $extend({
3804 data
: this, link
: 'cancel', method
: this.get('method') || 'post', url
: this.get('action')
3808 get: function(options
){
3809 if (options
|| !this.retrieve('send')){
3810 if (options
|| !this.retrieve('send:options')) this.set('send', options
);
3811 this.store('send', new Request(this.retrieve('send:options')));
3813 return this.retrieve('send');
3820 send: function(url
){
3821 var sender
= this.get('send');
3822 sender
.send({data
: this, url
: url
|| sender
.options
.url
});
3830 Script: Request.HTML.js
3831 Extends the basic Request Class with additional methods for interacting with HTML responses.
3837 Request
.HTML
= new Class({
3847 processHTML: function(text
){
3848 var match
= text
.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
3849 text
= (match
) ? match
[1] : text
;
3851 var container
= new Element('div');
3853 return $try(function(){
3854 var root
= '<root>' + text
+ '</root>', doc
;
3855 if (Browser
.Engine
.trident
){
3856 doc
= new ActiveXObject('Microsoft.XMLDOM');
3860 doc
= new DOMParser().parseFromString(root
, 'text/xml');
3862 root
= doc
.getElementsByTagName('root')[0];
3863 for (var i
= 0, k
= root
.childNodes
.length
; i
< k
; i
++){
3864 var child
= Element
.clone(root
.childNodes
[i
], true, true);
3865 if (child
) container
.grab(child
);
3868 }) || container
.set('html', text
);
3871 success: function(text
){
3872 var options
= this.options
, response
= this.response
;
3874 response
.html
= text
.stripScripts(function(script
){
3875 response
.javascript
= script
;
3878 var temp
= this.processHTML(response
.html
);
3880 response
.tree
= temp
.childNodes
;
3881 response
.elements
= temp
.getElements('*');
3883 if (options
.filter
) response
.tree
= response
.elements
.filter(options
.filter
);
3884 if (options
.update
) $(options
.update
).empty().set('html', response
.html
);
3885 if (options
.evalScripts
) $exec(response
.javascript
);
3887 this.onSuccess(response
.tree
, response
.elements
, response
.html
, response
.javascript
);
3892 Element
.Properties
.load
= {
3894 set: function(options
){
3895 var load
= this.retrieve('load');
3896 if (load
) load
.cancel();
3897 return this.eliminate('load').store('load:options', $extend({data
: this, link
: 'cancel', update
: this, method
: 'get'}, options
));
3900 get: function(options
){
3901 if (options
|| ! this.retrieve('load')){
3902 if (options
|| !this.retrieve('load:options')) this.set('load', options
);
3903 this.store('load', new Request
.HTML(this.retrieve('load:options')));
3905 return this.retrieve('load');
3913 this.get('load').send(Array
.link(arguments
, {data
: Object
.type
, url
: String
.type
}));
3921 Script: Request.JSON.js
3922 Extends the basic Request Class with additional methods for sending and receiving JSON data.
3928 Request
.JSON
= new Class({
3936 initialize: function(options
){
3937 this.parent(options
);
3938 this.headers
.extend({'Accept': 'application/json', 'X-Request': 'JSON'});
3941 success: function(text
){
3942 this.response
.json
= JSON
.decode(text
, this.options
.secure
);
3943 this.onSuccess(this.response
.json
, text
);