86a706005b24b0a0465aec76699dcfc3e35b8b02
[jquery.git] / jquery / jquery.js
1 /*
2  * jQuery - New Wave Javascript
3  *
4  * Copyright (c) 2006 John Resig (jquery.com)
5  * Licensed under the MIT License:
6  *   http://www.opensource.org/licenses/mit-license.php
7  *
8  * $Date$
9  * $Rev$
10  */
11
12 // Global undefined variable
13 window.undefined = window.undefined;
14
15 /**
16  * Create a new jQuery Object
17  * @constructor
18  */
19 function jQuery(a,c) {
20
21         // Shortcut for document ready (because $(document).each() is silly)
22         if ( a && a.constructor == Function )
23                 return $(document).ready(a);
24
25         // Make sure t hat a selection was provided
26         a = a || jQuery.context || document;
27
28         /*
29          * Handle support for overriding other $() functions. Way too many libraries
30          * provide this function to simply ignore it and overwrite it.
31          */
32
33         // Check to see if this is a possible collision case
34         if ( jQuery._$ && !c && a.constructor == String && 
35       
36                 // Make sure that the expression is a colliding one
37                 !/[^a-zA-Z0-9_-]/.test(a) &&
38         
39                 // and that there are no elements that match it
40                 // (this is the one truly ambiguous case)
41                 !document.getElementsByTagName(a).length )
42
43                         // Use the default method, in case it works some voodoo
44                         return jQuery._$( a );
45
46         // Watch for when a jQuery object is passed as the selector
47         if ( a.jquery )
48                 return a;
49
50         // Watch for when a jQuery object is passed at the context
51         if ( c && c.jquery )
52                 return $(c.get()).find(a);
53         
54         // If the context is global, return a new object
55         if ( window == this )
56                 return new jQuery(a,c);
57
58         // Watch for when an array is passed in
59         this.get( a.constructor == Array ?
60                 // Assume that it's an array of DOM Elements
61                 a :
62
63                 // Find the matching elements and save them for later
64                 jQuery.find( a, c ) );
65
66         var fn = arguments[ arguments.length - 1 ];
67         if ( fn && fn.constructor == Function )
68                 this.each(fn);
69 }
70
71 // Map over the $ in case of overwrite
72 if ( $ )
73         jQuery._$ = $;
74
75 // Map the jQuery namespace to the '$' one
76 var $ = jQuery;
77
78 jQuery.fn = jQuery.prototype = {
79         /**
80          * The current SVN version of jQuery.
81          *
82          * @private
83          * @property
84          * @name jquery
85          * @type String
86          */
87         jquery: "$Rev$",
88         
89         /**
90          * The number of elements currently matched.
91          *
92          * @example $("img").length;
93          * @before <img src="test1.jpg"/> <img src="test2.jpg"/>
94          * @result 2
95          *
96          * @property
97          * @name length
98          * @type Number
99          */
100         
101         /**
102          * The number of elements currently matched.
103          *
104          * @example $("img").size();
105          * @before <img src="test1.jpg"/> <img src="test2.jpg"/>
106          * @result 2
107          *
108          * @name size
109          * @type Number
110          */
111         size: function() {
112                 return this.length;
113         },
114         
115         /**
116          * Access all matched elements. This serves as a backwards-compatible
117          * way of accessing all matched elements (other than the jQuery object
118          * itself, which is, in fact, an array of elements).
119          *
120          * @example $("img").get();
121          * @before <img src="test1.jpg"/> <img src="test2.jpg"/>
122          * @result [ <img src="test1.jpg"/> <img src="test2.jpg"/> ]
123          *
124          * @name get
125          * @type Array<Element>
126          */
127          
128         /**
129          * Access a single matched element. <tt>num</tt> is used to access the 
130          * <tt>num</tt>th element matched.
131          *
132          * @example $("img").get(1);
133          * @before <img src="test1.jpg"/> <img src="test2.jpg"/>
134          * @result [ <img src="test1.jpg"/> ]
135          *
136          * @name get
137          * @type Element
138          * @param Number num Access the element in the <tt>num</tt>th position.
139          */
140          
141         /**
142          * Set the jQuery object to an array of elements.
143          *
144          * @example $("img").get([ document.body ]);
145          * @result $("img").get() == [ document.body ]
146          *
147          * @private
148          * @name get
149          * @type jQuery
150          * @param Elements elems An array of elements
151          */
152         get: function( num ) {
153                 // Watch for when an array (of elements) is passed in
154                 if ( num && num.constructor == Array ) {
155                 
156                         // Use a tricky hack to make the jQuery object
157                         // look and feel like an array
158                         this.length = 0;
159                         [].push.apply( this, num );
160                         
161                         return this;
162                 } else
163                         return num == undefined ?
164
165                                 // Return a 'clean' array
166                                 jQuery.map( this, function(a){ return a } ) :
167
168                                 // Return just the object
169                                 this[num];
170         },
171         
172         /**
173          * Execute a function within the context of every matched element.
174          * This means that every time the passed-in function is executed
175          * (which is once for every element matched) the 'this' keyword
176          * points to the specific element.
177          *
178          * Additionally, the function, when executed, is passed a single
179          * argument representing the position of the element in the matched
180          * set.
181          *
182          * @example $("img").each(function(){ this.src = "test.jpg"; });
183          * @before <img/> <img/>
184          * @result <img src="test.jpg"/> <img src="test.jpg"/>
185          *
186          * @name each
187          * @type jQuery
188          * @param Function fn A function to execute
189          */
190         each: function( fn ) {
191                 // Iterate through all of the matched elements
192                 for ( var i = 0; i < this.length; i++ )
193                 
194                         // Execute the function within the context of each element
195                         fn.apply( this[i], [i] );
196                 
197                 return this;
198         },
199         
200         /**
201          * Access a property on the first matched element.
202          * This method makes it easy to retreive a property value
203          * from the first matched element.
204          *
205          * @example $("img").attr("src");
206          * @before <img src="test.jpg"/>
207          * @result test.jpg
208          *
209          * @name attr
210          * @type Object
211          * @param String name The name of the property to access.
212          */
213          
214         /**
215          * Set a hash of key/value object properties to all matched elements.
216          * This serves as the best way to set a large number of properties
217          * on all matched elements.
218          *
219          * @example $("img").attr({ src: "test.jpg", alt: "Test Image" });
220          * @before <img/>
221          * @result <img src="test.jpg" alt="Test Image"/>
222          *
223          * @name attr
224          * @type jQuery
225          * @param Hash prop A set of key/value pairs to set as object properties.
226          */
227          
228         /**
229          * Set a single property to a value, on all matched elements.
230          *
231          * @example $("img").attr("src","test.jpg");
232          * @before <img/>
233          * @result <img src="test.jpg"/>
234          *
235          * @name attr
236          * @type jQuery
237          * @param String key The name of the property to set.
238          * @param Object value The value to set the property to.
239          */
240         attr: function( key, value, type ) {
241                 // Check to see if we're setting style values
242                 return key.constructor != String || value ?
243                         this.each(function(){
244                                 // See if we're setting a hash of styles
245                                 if ( value == undefined )
246                                         // Set all the styles
247                                         for ( var prop in key )
248                                                 jQuery.attr(
249                                                         type ? this.style : this,
250                                                         prop, key[prop]
251                                                 );
252                                 
253                                 // See if we're setting a single key/value style
254                                 else
255                                         jQuery.attr(
256                                                 type ? this.style : this,
257                                                 key, value
258                                         );
259                         }) :
260                         
261                         // Look for the case where we're accessing a style value
262                         jQuery[ type || "attr" ]( this[0], key );
263         },
264         
265         /**
266          * Access a style property on the first matched element.
267          * This method makes it easy to retreive a style property value
268          * from the first matched element.
269          *
270          * @example $("p").css("red");
271          * @before <p style="color:red;">Test Paragraph.</p>
272          * @result red
273          *
274          * @name css
275          * @type Object
276          * @param String name The name of the property to access.
277          */
278          
279         /**
280          * Set a hash of key/value style properties to all matched elements.
281          * This serves as the best way to set a large number of style properties
282          * on all matched elements.
283          *
284          * @example $("p").css({ color: "red", background: "blue" });
285          * @before <p>Test Paragraph.</p>
286          * @result <p style="color:red; background:blue;">Test Paragraph.</p>
287          *
288          * @name css
289          * @type jQuery
290          * @param Hash prop A set of key/value pairs to set as style properties.
291          */
292          
293         /**
294          * Set a single style property to a value, on all matched elements.
295          *
296          * @example $("p").css("color","red");
297          * @before <p>Test Paragraph.</p>
298          * @result <p style="color:red;">Test Paragraph.</p>
299          *
300          * @name css
301          * @type jQuery
302          * @param String key The name of the property to set.
303          * @param Object value The value to set the property to.
304          */
305         css: function( key, value ) {
306                 return this.attr( key, value, "css" );
307         },
308         
309         /**
310          * Retreive the text contents of all matched elements. The result is
311          * a string that contains the combined text contents of all matched
312          * elements. This method works on both HTML and XML documents.
313          *
314          * @example $("p").text();
315          * @before <p>Test Paragraph.</p>
316          * @result Test Paragraph.
317          *
318          * @name text
319          * @type String
320          */
321         text: function(e) {
322                 e = e || this;
323                 var t = "";
324                 for ( var j = 0; j < e.length; j++ ) {
325                         var r = e[j].childNodes;
326                         for ( var i = 0; i < r.length; i++ )
327                                 t += r[i].nodeType != 1 ?
328                                         r[i].nodeValue : jQuery.fn.text([ r[i] ]);
329                 }
330                 return t;
331         },
332         
333         /**
334          * Wrap all matched elements with a structure of other elements.
335          * This wrapping process is most useful for injecting additional
336          * stucture into a document, without ruining the original semantic
337          * qualities of a document.
338          *
339          * The way that is works is that it goes through the first element argument
340          * provided and finds the deepest element within the structure - it is that
341          * element that will en-wrap everything else.
342          *
343          * @example $("p").wrap("<div class='wrap'></div>");
344          * @before <p>Test Paragraph.</p>
345          * @result <div class='wrap'><p>Test Paragraph.</p></div>
346          *
347          * @name wrap
348          * @type jQuery
349          * @any String html A string of HTML, that will be created on the fly and wrapped around the target.
350          * @any Element elem A DOM element that will be wrapped.
351          * @any Array<Element> elems An array of elements, the first of which will be wrapped.
352          * @any Object obj Any object, converted to a string, then a text node.
353          */
354         wrap: function() {
355                 // The elements to wrap the target around
356                 var a = jQuery.clean(arguments);
357                 
358                 // Wrap each of the matched elements individually
359                 return this.each(function(){
360                         // Clone the structure that we're using to wrap
361                         var b = a[0].cloneNode(true);
362                         
363                         // Insert it before the element to be wrapped
364                         this.parentNode.insertBefore( b, this );
365                         
366                         // Find he deepest point in the wrap structure
367                         while ( b.firstChild )
368                                 b = b.firstChild;
369                         
370                         // Move the matched element to within the wrap structure
371                         b.appendChild( this );
372                 });
373         },
374         
375         /**
376          * Append any number of elements to the inside of all matched elements.
377          * This operation is similar to doing an <tt>appendChild</tt> to all the 
378          * specified elements, adding them into the document.
379          * 
380          * @example $("p").append("<b>Hello</b>");
381          * @before <p>I would like to say: </p>
382          * @result <p>I would like to say: <b>Hello</b></p>
383          *
384          * @name append
385          * @type jQuery
386          * @any String html A string of HTML, that will be created on the fly and appended to the target.
387          * @any Element elem A DOM element that will be appended.
388          * @any Array<Element> elems An array of elements, all of which will be appended.
389          * @any Object obj Any object, converted to a string, then a text node.
390          */
391         append: function() {
392                 return this.domManip(arguments, true, 1, function(a){
393                         this.appendChild( a );
394                 });
395         },
396         
397         /**
398          * Prepend any number of elements to the inside of all matched elements.
399          * This operation is the best way to insert a set of elements inside, at the 
400          * beginning, of all the matched element.
401          * 
402          * @example $("p").prepend("<b>Hello</b>");
403          * @before <p>, how are you?</p>
404          * @result <p><b>Hello</b>, how are you?</p>
405          *
406          * @name prepend
407          * @type jQuery
408          * @any String html A string of HTML, that will be created on the fly and prepended to the target.
409          * @any Element elem A DOM element that will be prepended.
410          * @any Array<Element> elems An array of elements, all of which will be prepended.
411          * @any Object obj Any object, converted to a string, then a text node.
412          */
413         prepend: function() {
414                 return this.domManip(arguments, true, -1, function(a){
415                         this.insertBefore( a, this.firstChild );
416                 });
417         },
418         
419         /**
420          * Insert any number of elements before each of the matched elements.
421          * 
422          * @example $("p").before("<b>Hello</b>");
423          * @before <p>how are you?</p>
424          * @result <b>Hello</b><p>how are you?</p>
425          *
426          * @name before
427          * @type jQuery
428          * @any String html A string of HTML, that will be created on the fly and inserted.
429          * @any Element elem A DOM element that will beinserted.
430          * @any Array<Element> elems An array of elements, all of which will be inserted.
431          * @any Object obj Any object, converted to a string, then a text node.
432          */
433         before: function() {
434                 return this.domManip(arguments, false, 1, function(a){
435                         this.parentNode.insertBefore( a, this );
436                 });
437         },
438         
439         /**
440          * Insert any number of elements after each of the matched elements.
441          * 
442          * @example $("p").after("<p>I'm doing fine.</p>");
443          * @before <p>How are you?</p>
444          * @result <p>How are you?</p><p>I'm doing fine.</p>
445          *
446          * @name after
447          * @type jQuery
448          * @any String html A string of HTML, that will be created on the fly and inserted.
449          * @any Element elem A DOM element that will beinserted.
450          * @any Array<Element> elems An array of elements, all of which will be inserted.
451          * @any Object obj Any object, converted to a string, then a text node.
452          */
453         after: function() {
454                 return this.domManip(arguments, false, -1, function(a){
455                         this.parentNode.insertBefore( a, this.nextSibling );
456                 });
457         },
458         
459         /**
460          * End all 'destructive' operations, reverting the list of matched elements.
461          * After an end operation, the list of matched elements will revert to the last
462          * state of matched elements.
463          *
464          * @example $("p").find("span").end();
465          * @before <p><span>Hello</span>, how are you?</p>
466          * @result $("p").find("span").end() == [ <p>...</p> ]
467          *
468          * @name end
469          * @type jQuery
470          */
471         end: function() {
472                 return this.get( this.stack.pop() );
473         },
474         
475         find: function(t) {
476                 return this.pushStack( jQuery.map( this, function(a){
477                         return jQuery.find(t,a);
478                 }), arguments );
479         },
480         
481         filter: function(t) {
482                 return t.constructor == Array ?
483                         // Multi Filtering
484                         this.pushStack( jQuery.map(this,function(a){
485                                 for ( var i = 0; i < t.length; i++ )
486                                         if ( jQuery.filter(t[i],[a]).r.length )
487                                                 return a;
488                         }), arguments ) :
489                         
490                         this.pushStack( jQuery.filter(t,this).r, arguments );
491         },
492         
493         not: function(t) {
494                 return this.pushStack( t.constructor == String ?
495                         jQuery.filter(t,this,false).r :
496                         jQuery.grep(this,function(a){ return a != t; }), arguments );
497         },
498         
499         add: function(t) {
500                 return this.pushStack( jQuery.merge( this, t.constructor == String ?
501                         jQuery.find(t) : t.constructor == Array ? t : [t] ), arguments );
502         },
503         
504         /**
505          * A wrapper function for each() to be used by append and prepend.
506          * Handles cases where you're trying to modify the inner contents of
507          * a table, when you actually need to work with the tbody.
508          *
509          * @member jQuery
510          * @param {String} expr The expression with which to filter
511          * @type Boolean
512          */
513         is: function(expr) {
514                 return jQuery.filter(expr,this).r.length > 0;
515         },
516         
517         /**
518          * :-P
519          *
520          * @private
521          * @name domManip
522          * @param Array args
523          * @param Boolean table
524          * @param Number int
525          * @param Function fn The function doing the DOM manipulation.
526          * @type jQuery
527          */
528         domManip: function(args, table, dir, fn){
529                 var clone = this.size() > 1;
530                 var a = jQuery.clean(args);
531                 
532                 return this.each(function(){
533                         var obj = this;
534                         
535                         if ( table && this.nodeName == "TABLE" ) {
536                                 var tbody = this.getElementsByTagName("tbody");
537
538                                 if ( !tbody.length ) {
539                                         obj = document.createElement("tbody");
540                                         this.appendChild( obj );
541                                 } else
542                                         obj = tbody[0];
543                         }
544         
545                         for ( var i = ( dir < 0 ? a.length - 1 : 0 );
546                                 i != ( dir < 0 ? dir : a.length ); i += dir )
547                                         fn.apply( obj, [ a[i] ] );
548                 });
549         },
550         
551         /**
552          * 
553          *
554          * @private
555          * @name pushStack
556          * @param Array a
557          * @param Array args
558          * @type jQuery
559          */
560         pushStack: function(a,args) {
561                 var fn = args && args[args.length-1];
562
563                 if ( !fn || fn.constructor != Function ) {
564                         if ( !this.stack ) this.stack = [];
565                         this.stack.push( this.get() );
566                         this.get( a );
567                 } else {
568                         var old = this.get();
569                         this.get( a );
570                         if ( fn.constructor == Function )
571                                 return this.each( fn );
572                         this.get( old );
573                 }
574
575                 return this;
576         },
577         
578         extend: function(obj,prop) {\r           if ( !prop ) {\r                 prop = obj;\r                    obj = this;\r            }\r      \r               for ( var i in prop )\r                  obj[i] = prop[i];\r      \r               return obj;\r    }
579 };
580
581 jQuery.extend = jQuery.fn.extend;
582
583 new function() {
584         var b = navigator.userAgent.toLowerCase();
585
586         // Figure out what browser is being used
587         jQuery.browser = {
588                 safari: /webkit/.test(b),
589                 opera: /opera/.test(b),
590                 msie: /msie/.test(b) && !/opera/.test(b),
591                 mozilla: /mozilla/.test(b) && !/compatible/.test(b)
592         };
593
594         // Check to see if the W3C box model is being used
595         jQuery.boxModel = !jQuery.browser.msie || document.compatMode == "CSS1Compat";
596
597         var axis = {
598                 parent: "a.parentNode",
599                 parents: jQuery.parents,
600                 ancestors: jQuery.parents,
601                 next: "a.nextSibling",
602                 prev: "a.previousSibling",
603                 siblings: jQuery.sibling
604         };
605         
606         for ( var i in axis ) new function(){
607                 var t = axis[i];
608                 jQuery.fn[ i ] = function(a) {
609                         var ret = jQuery.map(this,t);
610                         if ( a ) ret = jQuery.filter(a,ret).r;
611                         return this.pushStack( ret, arguments );
612                 };
613         }
614         
615         /*var to = ["append","prepend","before","after"];
616         
617         for ( var i = 0; i < to.length; i++ ) new function(){
618                 var n = to[i];
619                 jQuery.fn[ n + "To" ] = function(){
620                         var a = arguments;
621                         return this.each(function(){
622                                 for ( var i = 0; i < a.length; i++ )
623                                         $(a[i])[n]( this );
624                         });
625                 };
626         }*/
627         
628         var each = {
629                 show: function(){
630                         this.style.display = this.oldblock ? this.oldblock : "";
631                         if ( jQuery.css(this,"display") == "none" )
632                                 this.style.display = "block";
633                 },
634                 
635                 hide: function(){
636                         this.oldblock = jQuery.css(this,"display");
637                         if ( this.oldblock == "none" )
638                                 this.oldblock = "block";
639                         this.style.display = "none";
640                 },
641                 
642                 toggle: function(){
643                         var d = jQuery.css(this,"display");
644                         $(this)[ !d || d == "none" ? "show" : "hide" ]();
645                 },
646                 
647                 addClass: function(c){
648                         jQuery.className.add(this,c);
649                 },
650                 
651                 removeClass: function(c){
652                         jQuery.className.remove(this,c);
653                 },
654         
655                 toggleClass: function( c ){
656                         jQuery.className[ jQuery.className.has(this,a) ? "remove" : "add" ](this,c);
657                 },
658                 
659                 remove: function(a){
660                         if ( !a || jQuery.filter( [this], a ).r )
661                                 this.parentNode.removeChild( this );
662                 },
663         
664                 empty: function(){
665                         while ( this.firstChild )
666                                 this.removeChild( this.firstChild );
667                 },
668                 
669                 bind: function( type, fn ) {
670                         jQuery.event.add( this, type, fn );
671                 },
672                 
673                 unbind: function( type, fn ) {
674                         jQuery.event.remove( this, type, fn );
675                 },
676                 
677                 trigger: function( type ) {
678                         jQuery.event.trigger( this, type );
679                 }
680         };
681         
682         for ( var i in each ) new function() {
683                 var n = each[i];
684                 jQuery.fn[ i ] = function() {
685                         var args = arguments;
686                         return this.each(function(){
687                                 n.apply( this, args );
688                         });
689                 };
690         }
691         
692         var attr = {
693                 val: "value",
694                 html: "innerHTML",
695                 value: null,
696                 id: null,
697                 title: null,
698                 name: null,
699                 href: null,
700                 src: null,
701                 rel: null
702         };
703         
704         for ( var i in attr ) new function() {
705                 var n = attr[i];
706                 jQuery.fn[ i ] = function(h) {
707                         return h == undefined ?
708                                 this.length ? this[0][n] : null :
709                                 this.attr( n, h );
710                 };
711         }
712         
713         var css = "width,height,top,left,position,float,overflow,color,background".split(",");
714         
715         for ( var i in css ) new function() {
716                 var n = css[i];
717                 jQuery.fn[ i ] = function(h) {
718                         return h == undefined ?
719                                 this.length ? jQuery.css( this[0], n ) : null :
720                                 this.css( n, h );
721                 };
722         }
723
724 }
725
726 jQuery.extend({
727         className: {
728                 add: function(o,c){
729                         if (jQuery.className.has(o,c)) return;
730                         o.className += ( o.className ? " " : "" ) + c;
731                 },
732                 remove: function(o,c){
733                         o.className = !c ? "" :
734                                 o.className.replace(
735                                         new RegExp("(^|\\s*\\b[^-])"+c+"($|\\b(?=[^-]))", "g"), "");
736                 },
737                 has: function(e,a) {
738                         if ( e.className )
739                                 e = e.className;
740                         return new RegExp("(^|\\s)" + a + "(\\s|$)").test(e);
741                 }
742         },
743         
744         /**
745          * Swap in/out style options.
746          * @private
747          */
748         swap: function(e,o,f) {
749                 for ( var i in o ) {
750                         e.style["old"+i] = e.style[i];
751                         e.style[i] = o[i];
752                 }
753                 f.apply( e, [] );
754                 for ( var i in o )
755                         e.style[i] = e.style["old"+i];
756         },
757         
758         css: function(e,p) {
759                 if ( p == "height" || p == "width" ) {
760                         var old = {}, oHeight, oWidth, d = ["Top","Bottom","Right","Left"];
761         
762                         for ( var i in d ) {
763                                 old["padding" + d[i]] = 0;
764                                 old["border" + d[i] + "Width"] = 0;
765                         }
766         
767                         jQuery.swap( e, old, function() {
768                                 if (jQuery.css(e,"display") != "none") {
769                                         oHeight = e.offsetHeight;
770                                         oWidth = e.offsetWidth;
771                                 } else
772                                         jQuery.swap( e, { visibility: "hidden", position: "absolute", display: "" },
773                                                 function(){
774                                                         oHeight = e.clientHeight;
775                                                         oWidth = e.clientWidth;
776                                                 });
777                         });
778         
779                         return p == "height" ? oHeight : oWidth;
780                 }
781                 
782                 var r;
783         
784                 if (e.style[p])
785                         r = e.style[p];
786                 else if (e.currentStyle)
787                         r = e.currentStyle[p];
788                 else if (document.defaultView && document.defaultView.getComputedStyle) {
789                         p = p.replace(/([A-Z])/g,"-$1").toLowerCase();
790                         var s = document.defaultView.getComputedStyle(e,"");
791                         r = s ? s.getPropertyValue(p) : null;
792                 }
793                 
794                 return r;
795         },
796         
797         clean: function(a) {
798                 var r = [];
799                 for ( var i = 0; i < a.length; i++ ) {
800                         if ( a[i].constructor == String ) {
801         
802                                 if ( !a[i].indexOf("<tr") ) {
803                                         var tr = true;
804                                         a[i] = "<table>" + a[i] + "</table>";
805                                 } else if ( !a[i].indexOf("<td") || !a[i].indexOf("<th") ) {
806                                         var td = true;
807                                         a[i] = "<table><tbody><tr>" + a[i] + "</tr></tbody></table>";
808                                 }
809         
810                                 var div = document.createElement("div");
811                                 div.innerHTML = a[i];
812         
813                                 if ( tr || td ) {
814                                         div = div.firstChild.firstChild;
815                                         if ( td ) div = div.firstChild;
816                                 }
817         
818                                 for ( var j = 0; j < div.childNodes.length; j++ )
819                                         r.push( div.childNodes[j] );
820                         } else if ( a[i].jquery || a[i].length && !a[i].nodeType )
821                                 for ( var k = 0; k < a[i].length; k++ )
822                                         r.push( a[i][k] );
823                         else if ( a[i] !== null )
824                                 r.push( a[i].nodeType ? a[i] : document.createTextNode(a[i].toString()) );
825                 }
826                 return r;
827         },
828         
829         expr: {
830                 "": "m[2]== '*'||a.nodeName.toUpperCase()==m[2].toUpperCase()",
831                 "#": "a.getAttribute('id')&&a.getAttribute('id')==m[2]",
832                 ":": {
833                         // Position Checks
834                         lt: "i<m[3]-0",
835                         gt: "i>m[3]-0",
836                         nth: "m[3]-0==i",
837                         eq: "m[3]-0==i",
838                         first: "i==0",
839                         last: "i==r.length-1",
840                         even: "i%2==0",
841                         odd: "i%2",
842                         
843                         // Child Checks
844                         "first-child": "jQuery.sibling(a,0).cur",
845                         "last-child": "jQuery.sibling(a,0).last",
846                         "only-child": "jQuery.sibling(a).length==1",
847                         
848                         // Parent Checks
849                         parent: "a.childNodes.length",
850                         empty: "!a.childNodes.length",
851                         
852                         // Text Check
853                         contains: "(a.innerText||a.innerHTML).indexOf(m[3])>=0",
854                         
855                         // Visibility
856                         visible: "jQuery.css(a,'display')!='none'&&jQuery.css(a,'visibility')!='hidden'",
857                         hidden: "jQuery.css(a,'display')=='none'||jQuery.css(a,'visibility')=='hidden'",
858                         
859                         // Form elements
860                         enabled: "!a.disabled",
861                         disabled: "a.disabled",
862                         checked: "a.checked"
863                 },
864                 ".": "jQuery.className.has(a,m[2])",
865                 "@": {
866                         "=": "z==m[4]",
867                         "!=": "z!=m[4]",
868                         "^=": "!z.indexOf(m[4])",
869                         "$=": "z.substr(z.length - m[4].length,m[4].length)==m[4]",
870                         "*=": "z.indexOf(m[4])>=0",
871                         "": "z"
872                 },
873                 "[": "jQuery.find(m[2],a).length"
874         },
875         
876         token: [
877                 "\\.\\.|/\\.\\.", "a.parentNode",
878                 ">|/", "jQuery.sibling(a.firstChild)",
879                 "\\+", "jQuery.sibling(a).next",
880                 "~", function(a){
881                         var r = [];
882                         var s = jQuery.sibling(a);
883                         if ( s.n > 0 )
884                                 for ( var i = s.n; i < s.length; i++ )
885                                         r.push( s[i] );
886                         return r;
887                 }
888         ],
889         
890         find: function( t, context ) {
891                 // Make sure that the context is a DOM Element
892                 if ( context && context.getElementsByTagName == undefined )
893                         context = null;
894         
895                 // Set the correct context (if none is provided)
896                 context = context || jQuery.context || document;
897         
898                 if ( t.constructor != String ) return [t];
899         
900                 if ( !t.indexOf("//") ) {
901                         context = context.documentElement;
902                         t = t.substr(2,t.length);
903                 } else if ( !t.indexOf("/") ) {
904                         context = context.documentElement;
905                         t = t.substr(1,t.length);
906                         // FIX Assume the root element is right :(
907                         if ( t.indexOf("/") >= 1 )
908                                 t = t.substr(t.indexOf("/"),t.length);
909                 }
910         
911                 var ret = [context];
912                 var done = [];
913                 var last = null;
914         
915                 while ( t.length > 0 && last != t ) {
916                         var r = [];
917                         last = t;
918         
919                         t = jQuery.trim(t).replace( /^\/\//i, "" );
920                         
921                         var foundToken = false;
922                         
923                         for ( var i = 0; i < jQuery.token.length; i += 2 ) {
924                                 var re = new RegExp("^(" + jQuery.token[i] + ")");
925                                 var m = re.exec(t);
926                                 
927                                 if ( m ) {
928                                         r = ret = jQuery.map( ret, jQuery.token[i+1] );
929                                         t = jQuery.trim(t).replace( re, "" );
930                                         foundToken = true;
931                                 }
932                         }
933                         
934                         if ( !foundToken ) {
935                                 if ( !t.indexOf(",") || !t.indexOf("|") ) {
936                                         if ( ret[0] == context ) ret.shift();
937                                         done = jQuery.merge( done, ret );
938                                         r = ret = [context];
939                                         t = " " + t.substr(1,t.length);
940                                 } else {
941                                         var re2 = /^([#.]?)([a-z0-9\\*_-]*)/i;
942                                         var m = re2.exec(t);
943                 
944                                         if ( m[1] == "#" ) {
945                                                 // Ummm, should make this work in all XML docs
946                                                 var oid = document.getElementById(m[2]);
947                                                 r = ret = oid ? [oid] : [];
948                                                 t = t.replace( re2, "" );
949                                         } else {
950                                                 if ( !m[2] || m[1] == "." ) m[2] = "*";
951                 
952                                                 for ( var i = 0; i < ret.length; i++ )
953                                                         r = jQuery.merge( r,
954                                                                 m[2] == "*" ?
955                                                                         jQuery.getAll(ret[i]) :
956                                                                         ret[i].getElementsByTagName(m[2])
957                                                         );
958                                         }
959                                 }
960                         }
961         
962                         if ( t ) {
963                                 var val = jQuery.filter(t,r);
964                                 ret = r = val.r;
965                                 t = jQuery.trim(val.t);
966                         }
967                 }
968         
969                 if ( ret && ret[0] == context ) ret.shift();
970                 done = jQuery.merge( done, ret );
971         
972                 return done;
973         },
974         
975         getAll: function(o,r) {
976                 r = r || [];
977                 var s = o.childNodes;
978                 for ( var i = 0; i < s.length; i++ )
979                         if ( s[i].nodeType == 1 ) {
980                                 r.push( s[i] );
981                                 jQuery.getAll( s[i], r );
982                         }
983                 return r;
984         },
985         
986         attr: function(o,a,v){
987                 if ( a && a.constructor == String ) {
988                         var fix = {
989                                 "for": "htmlFor",
990                                 "class": "className",
991                                 "float": "cssFloat"
992                         };
993                         
994                         a = (fix[a] && fix[a].replace && fix[a] || a)
995                                 .replace(/-([a-z])/ig,function(z,b){
996                                         return b.toUpperCase();
997                                 });
998                         
999                         if ( v != undefined ) {
1000                                 o[a] = v;
1001                                 if ( o.setAttribute && a != "disabled" )
1002                                         o.setAttribute(a,v);
1003                         }
1004                         
1005                         return o[a] || o.getAttribute && o.getAttribute(a) || "";
1006                 } else
1007                         return "";
1008         },
1009         
1010         filter: function(t,r,not) {
1011                 // Figure out if we're doing regular, or inverse, filtering
1012                 var g = not !== false ? jQuery.grep :
1013                         function(a,f) {return jQuery.grep(a,f,true);};
1014                 
1015                 // Look for a string-like sequence
1016                 var str = "([a-zA-Z*_-][a-zA-Z0-9_-]*)";
1017                 
1018                 // Look for something (optionally) enclosed with quotes
1019                 var qstr = " *'?\"?([^'\"]*)'?\"? *";
1020         
1021                 while ( t && /^[a-zA-Z\[*:.#]/.test(t) ) {
1022                         // Handles:
1023                         // [@foo], [@foo=bar], etc.
1024                         var re = new RegExp("^\\[ *@" + str + " *([!*$^=]*) *" + qstr + "\\]");
1025                         var m = re.exec(t);
1026         
1027                         // Re-organize the match
1028                         if ( m ) m = ["", "@", m[2], m[1], m[3]];
1029                                 
1030                         // Handles:
1031                         // [div], [.foo]
1032                         if ( !m ) {
1033                                 re = new RegExp("^(\\[)" + qstr + "\\]");
1034                                 m = re.exec(t);
1035                         }
1036                         
1037                         // Handles:
1038                         // :contains(test), :not(.foo)
1039                         if ( !m ) {
1040                                 re = new RegExp("^(:)" + str + "\\(" + qstr + "\\)");
1041                                 m = re.exec(t);
1042                         }
1043                         
1044                         // Handles:
1045                         // :foo, .foo, #foo, foo
1046                         if ( !m ) {
1047                                 re = new RegExp("^([:.#]*)" + str);
1048                                 m = re.exec(t);
1049                         }
1050                         
1051                         // Remove what we just matched
1052                         t = t.replace( re, "" );
1053         
1054                         // :not() is a special case that can be optomized by
1055                         // keeping it out of the expression list
1056                         if ( m[1] == ":" && m[2] == "not" )
1057                                 r = jQuery.filter(m[3],r,false).r;
1058                         
1059                         // Otherwise, find the expression to execute
1060                         else {
1061                                 // Build a custom macro to enclose it
1062                                 eval("f = function(a,i){" + 
1063                                         ( m[1] == "@" ? "z=jQuery.attr(a,m[3]);" : "" ) + 
1064                                         "return " + jQuery.expr[m[1]] + "}");
1065                                 
1066                                 // Execute it against the current filter
1067                                 r = g( r, f );
1068                         }
1069                 }
1070         
1071                 // Return an array of filtered elements (r)
1072                 // and the modified expression string (t)
1073                 return { r: r, t: t };
1074         },
1075         
1076         /**
1077          * Remove the whitespace from the beginning and end of a string.
1078          *
1079          * @private
1080          * @name $.trim
1081          * @type String
1082          * @param String str The string to trim.
1083          */
1084         trim: function(t){
1085                 return t.replace(/^\s+|\s+$/g, "");
1086         },
1087         
1088         /**
1089          * All ancestors of a given element.
1090          *
1091          * @private
1092          * @name $.parents
1093          * @type Array<Element>
1094          * @param Element elem The element to find the ancestors of.
1095          */
1096         parents: function(a){
1097                 var b = [];
1098                 var c = a.parentNode;
1099                 while ( c && c != document ) {
1100                         b.push( c );
1101                         c = c.parentNode;
1102                 }
1103                 return b;
1104         },
1105         
1106         /**
1107          * All elements on a specified axis.
1108          *
1109          * @private
1110          * @name $.sibling
1111          * @type Array
1112          * @param Element elem The element to find all the siblings of (including itself).
1113          */
1114         sibling: function(a,n) {
1115                 var type = [];
1116                 var tmp = a.parentNode.childNodes;
1117                 for ( var i = 0; i < tmp.length; i++ ) {
1118                         if ( tmp[i].nodeType == 1 )
1119                                 type.push( tmp[i] );
1120                         if ( tmp[i] == a )
1121                                 type.n = type.length - 1;
1122                 }
1123                 type.last = type.n == type.length - 1;
1124                 type.cur =
1125                         n == "even" && type.n % 2 == 0 ||
1126                         n == "odd" && type.n % 2 ||
1127                         type[n] == a;
1128                 type.next = type[type.n + 1];
1129                 return type;
1130         },
1131         
1132         /**
1133          * Merge two arrays together, removing all duplicates.
1134          *
1135          * @private
1136          * @name $.merge
1137          * @type Array
1138          * @param Array a The first array to merge.
1139          * @param Array b The second array to merge.
1140          */
1141         merge: function(a,b) {
1142                 var d = [];
1143                 
1144                 // Move b over to the new array (this helps to avoid
1145                 // StaticNodeList instances)
1146                 for ( var k = 0; k < b.length; k++ )
1147                         d[k] = b[k];
1148         
1149                 // Now check for duplicates between a and b and only
1150                 // add the unique items
1151                 for ( var i = 0; i < a.length; i++ ) {
1152                         var c = true;
1153                         
1154                         // The collision-checking process
1155                         for ( var j = 0; j < b.length; j++ )
1156                                 if ( a[i] == b[j] )
1157                                         c = false;
1158                                 
1159                         // If the item is unique, add it
1160                         if ( c )
1161                                 d.push( a[i] );
1162                 }
1163         
1164                 return d;
1165         },
1166         
1167         /**
1168          * Remove items that aren't matched in an array. The function passed
1169          * in to this method will be passed two arguments: 'a' (which is the
1170          * array item) and 'i' (which is the index of the item in the array).
1171          *
1172          * @private
1173          * @name $.grep
1174          * @type Array
1175          * @param Array array The Array to find items in.
1176          * @param Function fn The function to process each item against.
1177          * @param Boolean inv Invert the selection - select the opposite of the function.
1178          */
1179         grep: function(a,f,s) {
1180                 // If a string is passed in for the function, make a function
1181                 // for it (a handy shortcut)
1182                 if ( f.constructor == String )
1183                         f = new Function("a","i","return " + f);
1184                         
1185                 var r = [];
1186                 
1187                 // Go through the array, only saving the items
1188                 // that pass the validator function
1189                 for ( var i = 0; i < a.length; i++ )
1190                         if ( !s && f(a[i],i) || s && !f(a[i],i) )
1191                                 r.push( a[i] );
1192                 
1193                 return r;
1194         },
1195         
1196         /**
1197          * Translate all items in array to another array of items. The translation function
1198          * that is provided to this method is passed one argument: 'a' (the item to be 
1199          * translated). If an array is returned, that array is mapped out and merged into
1200          * the full array. Additionally, returning 'null' or 'undefined' will delete the item
1201          * from the array. Both of these changes imply that the size of the array may not
1202          * be the same size upon completion, as it was when it started.
1203          *
1204          * @private
1205          * @name $.map
1206          * @type Array
1207          * @param Array array The Array to translate.
1208          * @param Function fn The function to process each item against.
1209          */
1210         map: function(a,f) {
1211                 // If a string is passed in for the function, make a function
1212                 // for it (a handy shortcut)
1213                 if ( f.constructor == String )
1214                         f = new Function("a","return " + f);
1215                 
1216                 var r = [];
1217                 
1218                 // Go through the array, translating each of the items to their
1219                 // new value (or values).
1220                 for ( var i = 0; i < a.length; i++ ) {
1221                         var t = f(a[i],i);
1222                         if ( t !== null && t != undefined ) {
1223                                 if ( t.constructor != Array ) t = [t];
1224                                 r = jQuery.merge( t, r );
1225                         }
1226                 }
1227                 return r;
1228         },
1229         
1230         /*
1231          * A number of helper functions used for managing events.
1232          * Many of the ideas behind this code orignated from Dean Edwards' addEvent library.
1233          */
1234         event: {
1235         
1236                 // Bind an event to an element
1237                 // Original by Dean Edwards
1238                 add: function(element, type, handler) {
1239                         // For whatever reason, IE has trouble passing the window object
1240                         // around, causing it to be cloned in the process
1241                         if ( jQuery.browser.msie && element.setInterval != undefined )
1242                                 element = window;
1243                 
1244                         // Make sure that the function being executed has a unique ID
1245                         if ( !handler.guid )
1246                                 handler.guid = this.guid++;
1247                                 
1248                         // Init the element's event structure
1249                         if (!element.events)
1250                                 element.events = {};
1251                         
1252                         // Get the current list of functions bound to this event
1253                         var handlers = element.events[type];
1254                         
1255                         // If it hasn't been initialized yet
1256                         if (!handlers) {
1257                                 // Init the event handler queue
1258                                 handlers = element.events[type] = {};
1259                                 
1260                                 // Remember an existing handler, if it's already there
1261                                 if (element["on" + type])
1262                                         handlers[0] = element["on" + type];
1263                         }
1264                         
1265                         // Add the function to the element's handler list
1266                         handlers[handler.guid] = handler;
1267                         
1268                         // And bind the global event handler to the element
1269                         element["on" + type] = this.handle;
1270         
1271                         // Remember the function in a global list (for triggering)
1272                         if (!this.global[type])
1273                                 this.global[type] = [];
1274                         this.global[type].push( element );
1275                 },
1276                 
1277                 guid: 1,
1278                 global: {},
1279                 
1280                 // Detach an event or set of events from an element
1281                 remove: function(element, type, handler) {
1282                         if (element.events)
1283                                 if (type && element.events[type])
1284                                         if ( handler )
1285                                                 delete element.events[type][handler.guid];
1286                                         else
1287                                                 for ( var i in element.events[type] )
1288                                                         delete element.events[type][i];
1289                                 else
1290                                         for ( var j in element.events )
1291                                                 this.remove( element, j );
1292                 },
1293                 
1294                 trigger: function(type,data,element) {
1295                         // Touch up the incoming data
1296                         data = data || [];
1297         
1298                         // Handle a global trigger
1299                         if ( !element ) {
1300                                 var g = this.global[type];
1301                                 if ( g )
1302                                         for ( var i = 0; i < g.length; i++ )
1303                                                 this.trigger( type, data, g[i] );
1304         
1305                         // Handle triggering a single element
1306                         } else if ( element["on" + type] ) {
1307                                 // Pass along a fake event
1308                                 data.unshift( this.fix({ type: type, target: element }) );
1309         
1310                                 // Trigger the event
1311                                 element["on" + type].apply( element, data );
1312                         }
1313                 },
1314                 
1315                 handle: function(event) {
1316                         event = event || jQuery.event.fix( window.event );
1317         
1318                         // If no correct event was found, fail
1319                         if ( !event ) return;
1320                 
1321                         var returnValue = true;
1322                 
1323                         for ( var j in this.events[event.type] ) {
1324                                 if (this.events[event.type][j](event) === false) {
1325                                         event.preventDefault();
1326                                         event.stopPropagation();
1327                                         returnValue = false;
1328                                 }
1329                         }
1330                         
1331                         return returnValue;
1332                 },
1333                 
1334                 fix: function(event) {
1335                         if ( event ) {
1336                                 event.preventDefault = function() {
1337                                         this.returnValue = false;
1338                                 };
1339                         
1340                                 event.stopPropagation = function() {
1341                                         this.cancelBubble = true;
1342                                 };
1343                         }
1344                         
1345                         return event;
1346                 }
1347         
1348         }
1349 });