Fixed #1039 and #1733 by going through the core API and making them text node and...
[jquery.git] / src / core.js
1 /*
2  * jQuery @VERSION - New Wave Javascript
3  *
4  * Copyright (c) 2007 John Resig (jquery.com)
5  * Dual licensed under the MIT (MIT-LICENSE.txt)
6  * and GPL (GPL-LICENSE.txt) licenses.
7  *
8  * $Date$
9  * $Rev$
10  */
11
12 // Map over jQuery in case of overwrite
13 if ( window.jQuery )
14         var _jQuery = window.jQuery;
15
16 var jQuery = window.jQuery = function( selector, context ) {
17         // If the context is a namespace object, return a new object
18         return this instanceof jQuery ?
19                 this.init( selector, context ) :
20                 new jQuery( selector, context );
21 };
22
23 // Map over the $ in case of overwrite
24 if ( window.$ )
25         var _$ = window.$;
26         
27 // Map the jQuery namespace to the '$' one
28 window.$ = jQuery;
29
30 // A simple way to check for HTML strings or ID strings
31 // (both of which we optimize for)
32 var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/;
33
34 jQuery.fn = jQuery.prototype = {
35         init: function( selector, context ) {
36                 // Make sure that a selection was provided
37                 selector = selector || document;
38
39                 // Handle $(DOMElement)
40                 if ( selector.nodeType ) {
41                         this[0] = selector;
42                         this.length = 1;
43                         return this;
44
45                 // Handle HTML strings
46                 } else if ( typeof selector == "string" ) {
47                         // Are we dealing with HTML string or an ID?
48                         var match = quickExpr.exec( selector );
49
50                         // Verify a match, and that no context was specified for #id
51                         if ( match && (match[1] || !context) ) {
52
53                                 // HANDLE: $(html) -> $(array)
54                                 if ( match[1] )
55                                         selector = jQuery.clean( [ match[1] ], context );
56
57                                 // HANDLE: $("#id")
58                                 else {
59                                         var elem = document.getElementById( match[3] );
60
61                                         // Make sure an element was located
62                                         if ( elem )
63                                                 // Handle the case where IE and Opera return items
64                                                 // by name instead of ID
65                                                 if ( elem.id != match[3] )
66                                                         return jQuery().find( selector );
67
68                                                 // Otherwise, we inject the element directly into the jQuery object
69                                                 else {
70                                                         this[0] = elem;
71                                                         this.length = 1;
72                                                         return this;
73                                                 }
74
75                                         else
76                                                 selector = [];
77                                 }
78
79                         // HANDLE: $(expr, [context])
80                         // (which is just equivalent to: $(content).find(expr)
81                         } else
82                                 return new jQuery( context ).find( selector );
83
84                 // HANDLE: $(function)
85                 // Shortcut for document ready
86                 } else if ( jQuery.isFunction( selector ) )
87                         return new jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector );
88
89                 return this.setArray(
90                         // HANDLE: $(array)
91                         selector.constructor == Array && selector ||
92
93                         // HANDLE: $(arraylike)
94                         // Watch for when an array-like object, contains DOM nodes, is passed in as the selector
95                         (selector.jquery || selector.length && selector != window && !selector.nodeType && selector[0] != undefined && selector[0].nodeType) && jQuery.makeArray( selector ) ||
96
97                         // HANDLE: $(*)
98                         [ selector ] );
99         },
100         
101         // The current version of jQuery being used
102         jquery: "@VERSION",
103
104         // The number of elements contained in the matched element set
105         size: function() {
106                 return this.length;
107         },
108         
109         // The number of elements contained in the matched element set
110         length: 0,
111
112         // Get the Nth element in the matched element set OR
113         // Get the whole matched element set as a clean array
114         get: function( num ) {
115                 return num == undefined ?
116
117                         // Return a 'clean' array
118                         jQuery.makeArray( this ) :
119
120                         // Return just the object
121                         this[ num ];
122         },
123         
124         // Take an array of elements and push it onto the stack
125         // (returning the new matched element set)
126         pushStack: function( elems ) {
127                 // Build a new jQuery matched element set
128                 var ret = jQuery( elems );
129
130                 // Add the old object onto the stack (as a reference)
131                 ret.prevObject = this;
132
133                 // Return the newly-formed element set
134                 return ret;
135         },
136         
137         // Force the current matched set of elements to become
138         // the specified array of elements (destroying the stack in the process)
139         // You should use pushStack() in order to do this, but maintain the stack
140         setArray: function( elems ) {
141                 // Resetting the length to 0, then using the native Array push
142                 // is a super-fast way to populate an object with array-like properties
143                 this.length = 0;
144                 Array.prototype.push.apply( this, elems );
145                 
146                 return this;
147         },
148
149         // Execute a callback for every element in the matched set.
150         // (You can seed the arguments with an array of args, but this is
151         // only used internally.)
152         each: function( callback, args ) {
153                 return jQuery.each( this, callback, args );
154         },
155
156         // Determine the position of an element within 
157         // the matched set of elements
158         index: function( elem ) {
159                 var ret = -1;
160
161                 // Locate the position of the desired element
162                 this.each(function(i){
163                         if ( this == elem )
164                                 ret = i;
165                 });
166
167                 return ret;
168         },
169
170         attr: function( name, value, type ) {
171                 var options = name;
172                 
173                 // Look for the case where we're accessing a style value
174                 if ( name.constructor == String )
175                         if ( value == undefined )
176                                 return this.length && jQuery[ type || "attr" ]( this[0], name ) || undefined;
177
178                         else {
179                                 options = {};
180                                 options[ name ] = value;
181                         }
182                 
183                 // Check to see if we're setting style values
184                 return this.each(function(i){
185                         // Set all the styles
186                         for ( name in options )
187                                 jQuery.attr(
188                                         type ?
189                                                 this.style :
190                                                 this,
191                                         name, jQuery.prop( this, options[ name ], type, i, name )
192                                 );
193                 });
194         },
195
196         css: function( key, value ) {
197                 // ignore negative width and height values
198                 if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 )
199                         value = undefined;
200                 return this.attr( key, value, "curCSS" );
201         },
202
203         text: function( text ) {
204                 if ( typeof text != "object" && text != null )
205                         return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
206
207                 var ret = "";
208
209                 jQuery.each( text || this, function(){
210                         jQuery.each( this.childNodes, function(){
211                                 if ( this.nodeType != 8 )
212                                         ret += this.nodeType != 1 ?
213                                                 this.nodeValue :
214                                                 jQuery.fn.text( [ this ] );
215                         });
216                 });
217
218                 return ret;
219         },
220
221         wrapAll: function( html ) {
222                 if ( this[0] )
223                         // The elements to wrap the target around
224                         jQuery( html, this[0].ownerDocument )
225                                 .clone()
226                                 .insertBefore( this[0] )
227                                 .map(function(){
228                                         var elem = this;
229
230                                         while ( elem.firstChild )
231                                                 elem = elem.firstChild;
232
233                                         return elem;
234                                 })
235                                 .append(this);
236
237                 return this;
238         },
239
240         wrapInner: function( html ) {
241                 return this.each(function(){
242                         jQuery( this ).contents().wrapAll( html );
243                 });
244         },
245
246         wrap: function( html ) {
247                 return this.each(function(){
248                         jQuery( this ).wrapAll( html );
249                 });
250         },
251
252         append: function() {
253                 return this.domManip(arguments, true, false, function(elem){
254                         if (this.nodeType == 1)
255                                 this.appendChild( elem );
256                 });
257         },
258
259         prepend: function() {
260                 return this.domManip(arguments, true, true, function(elem){
261                         if (this.nodeType == 1)
262                                 this.insertBefore( elem, this.firstChild );
263                 });
264         },
265         
266         before: function() {
267                 return this.domManip(arguments, false, false, function(elem){
268                         this.parentNode.insertBefore( elem, this );
269                 });
270         },
271
272         after: function() {
273                 return this.domManip(arguments, false, true, function(elem){
274                         this.parentNode.insertBefore( elem, this.nextSibling );
275                 });
276         },
277
278         end: function() {
279                 return this.prevObject || jQuery( [] );
280         },
281
282         find: function( selector ) {
283                 var elems = jQuery.map(this, function(elem){
284                         return jQuery.find( selector, elem );
285                 });
286
287                 return this.pushStack( /[^+>] [^+>]/.test( selector ) || selector.indexOf("..") > -1 ?
288                         jQuery.unique( elems ) :
289                         elems );
290         },
291
292         clone: function( events ) {
293                 // Do the clone
294                 var ret = this.map(function(){
295                         return this.outerHTML ?
296                                 jQuery( this.outerHTML )[0] :
297                                 this.cloneNode( true );
298                 });
299
300                 // Need to set the expando to null on the cloned set if it exists
301                 // removeData doesn't work here, IE removes it from the original as well
302                 // this is primarily for IE but the data expando shouldn't be copied over in any browser
303                 var clone = ret.find("*").andSelf().each(function(){
304                         if ( this[ expando ] != undefined )
305                                 this[ expando ] = null;
306                 });
307                 
308                 // Copy the events from the original to the clone
309                 if ( events === true )
310                         this.find("*").andSelf().each(function(i){
311                                 var events = jQuery.data( this, "events" );
312
313                                 for ( var type in events )
314                                         for ( var handler in events[ type ] )
315                                                 jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data );
316                         });
317
318                 // Return the cloned set
319                 return ret;
320         },
321
322         filter: function( selector ) {
323                 return this.pushStack(
324                         jQuery.isFunction( selector ) &&
325                         jQuery.grep(this, function(elem, i){
326                                 return selector.call( elem, i );
327                         }) ||
328
329                         jQuery.multiFilter( selector, this ) );
330         },
331
332         not: function( selector ) {
333                 return this.pushStack(
334                         selector.constructor == String &&
335                         jQuery.multiFilter( selector, this, true ) ||
336
337                         jQuery.grep(this, function(elem) {
338                                 return selector.constructor == Array || selector.jquery ?
339                                         jQuery.inArray( elem, selector ) < 0 :
340                                         elem != selector;
341                         }) );
342         },
343
344         add: function( selector ) {
345                 return !selector ? this : this.pushStack( jQuery.merge( 
346                         this.get(),
347                         selector.constructor == String ? 
348                                 jQuery( selector ).get() :
349                                 selector.length != undefined && (!selector.nodeName || jQuery.nodeName(selector, "form")) ?
350                                         selector : [selector] ) );
351         },
352
353         is: function( selector ) {
354                 return selector ?
355                         jQuery.multiFilter( selector, this ).length > 0 :
356                         false;
357         },
358
359         hasClass: function( selector ) {
360                 return this.is( "." + selector );
361         },
362         
363         val: function( value ) {
364                 if ( value == undefined ) {
365
366                         if ( this.length ) {
367                                 var elem = this[0];
368
369                                 // We need to handle select boxes special
370                                 if ( jQuery.nodeName( elem, "select" ) ) {
371                                         var index = elem.selectedIndex,
372                                                 values = [],
373                                                 options = elem.options,
374                                                 one = elem.type == "select-one";
375                                         
376                                         // Nothing was selected
377                                         if ( index < 0 )
378                                                 return null;
379
380                                         // Loop through all the selected options
381                                         for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
382                                                 var option = options[ i ];
383
384                                                 if ( option.selected ) {
385                                                         // Get the specifc value for the option
386                                                         value = jQuery.browser.msie && !option.attributes.value.specified ? option.text : option.value;
387                                                         
388                                                         // We don't need an array for one selects
389                                                         if ( one )
390                                                                 return value;
391                                                         
392                                                         // Multi-Selects return an array
393                                                         values.push( value );
394                                                 }
395                                         }
396                                         
397                                         return values;
398                                         
399                                 // Everything else, we just grab the value
400                                 } else
401                                         return (this[0].value || "").replace(/\r/g, "");
402
403                         }
404
405                 } else
406                         return this.each(function(){
407                                 if ( this.nodeType != 1 )
408                                         return;
409
410                                 if ( value.constructor == Array && /radio|checkbox/.test( this.type ) )
411                                         this.checked = (jQuery.inArray(this.value, value) >= 0 ||
412                                                 jQuery.inArray(this.name, value) >= 0);
413
414                                 else if ( jQuery.nodeName( this, "select" ) ) {
415                                         var values = value.constructor == Array ?
416                                                 value :
417                                                 [ value ];
418
419                                         jQuery( "option", this ).each(function(){
420                                                 this.selected = (jQuery.inArray( this.value, values ) >= 0 ||
421                                                         jQuery.inArray( this.text, values ) >= 0);
422                                         });
423
424                                         if ( !values.length )
425                                                 this.selectedIndex = -1;
426
427                                 } else
428                                         this.value = value;
429                         });
430         },
431         
432         html: function( value ) {
433                 return value == undefined ?
434                         (this.length ?
435                                 this[0].innerHTML :
436                                 null) :
437                         this.empty().append( value );
438         },
439
440         replaceWith: function( value ) {
441                 return this.after( value ).remove();
442         },
443
444         eq: function( i ) {
445                 return this.slice( i, i + 1 );
446         },
447
448         slice: function() {
449                 return this.pushStack( Array.prototype.slice.apply( this, arguments ) );
450         },
451
452         map: function( callback ) {
453                 return this.pushStack( jQuery.map(this, function(elem, i){
454                         return callback.call( elem, i, elem );
455                 }));
456         },
457
458         andSelf: function() {
459                 return this.add( this.prevObject );
460         },
461         
462         domManip: function( args, table, reverse, callback ) {
463                 var clone = this.length > 1, elems; 
464
465                 return this.each(function(){
466                         if ( !elems ) {
467                                 elems = jQuery.clean( args, this.ownerDocument );
468
469                                 if ( reverse )
470                                         elems.reverse();
471                         }
472
473                         var obj = this;
474
475                         if ( table && jQuery.nodeName( this, "table" ) && jQuery.nodeName( elems[0], "tr" ) )
476                                 obj = this.getElementsByTagName("tbody")[0] || this.appendChild( this.ownerDocument.createElement("tbody") );
477
478                         var scripts = jQuery( [] );
479
480                         jQuery.each(elems, function(){
481                                 var elem = clone ?
482                                         this.cloneNode( true ) :
483                                         this;
484
485                                 if ( jQuery.nodeName( elem, "script" ) ) {
486
487                                         // If scripts are waiting to be executed, wait on this script as well
488                                         if ( scripts.length )
489                                                 scripts = scripts.add( elem );
490
491                                         // If nothing is waiting to be executed, run immediately
492                                         else
493                                                 evalScript( 0, elem );
494
495                                 } else {
496                                         // Remove any inner scripts for later evaluation
497                                         if ( elem.nodeType == 1 )
498                                                 scripts = scripts.add( jQuery( "script", elem ).remove() );
499
500                                         // Inject the elements into the document
501                                         callback.call( obj, elem );
502                                 }
503                         });
504
505                         scripts.each( evalScript );
506                 });
507         }
508 };
509
510 function evalScript( i, elem ) {
511         if ( elem.src )
512                 jQuery.ajax({
513                         url: elem.src,
514                         async: false,
515                         dataType: "script"
516                 });
517
518         else
519                 jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
520
521         if ( elem.parentNode )
522                 elem.parentNode.removeChild( elem );
523 }
524
525 jQuery.extend = jQuery.fn.extend = function() {
526         // copy reference to target object
527         var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
528
529         // Handle a deep copy situation
530         if ( target.constructor == Boolean ) {
531                 deep = target;
532                 target = arguments[1] || {};
533                 // skip the boolean and the target
534                 i = 2;
535         }
536
537         // Handle case when target is a string or something (possible in deep copy)
538         if ( typeof target != "object" && typeof target != "function" )
539                 target = {};
540
541         // extend jQuery itself if only one argument is passed
542         if ( length == 1 ) {
543                 target = this;
544                 i = 0;
545         }
546
547         for ( ; i < length; i++ )
548                 // Only deal with non-null/undefined values
549                 if ( (options = arguments[ i ]) != null )
550                         // Extend the base object
551                         for ( var name in options ) {
552                                 // Prevent never-ending loop
553                                 if ( target === options[ name ] )
554                                         continue;
555
556                                 // Recurse if we're merging object values
557                                 if ( deep && options[ name ] && typeof options[ name ] == "object" && target[ name ] && !options[ name ].nodeType )
558                                         target[ name ] = jQuery.extend( target[ name ], options[ name ] );
559
560                                 // Don't bring in undefined values
561                                 else if ( options[ name ] != undefined )
562                                         target[ name ] = options[ name ];
563
564                         }
565
566         // Return the modified object
567         return target;
568 };
569
570 var expando = "jQuery" + (new Date()).getTime(), uuid = 0, windowData = {};
571
572 // exclude the following css properties to add px
573 var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i;
574
575 jQuery.extend({
576         noConflict: function( deep ) {
577                 window.$ = _$;
578
579                 if ( deep )
580                         window.jQuery = _jQuery;
581
582                 return jQuery;
583         },
584
585         // This may seem like some crazy code, but trust me when I say that this
586         // is the only cross-browser way to do this. --John
587         isFunction: function( fn ) {
588                 return !!fn && typeof fn != "string" && !fn.nodeName && 
589                         fn.constructor != Array && /function/i.test( fn + "" );
590         },
591         
592         // check if an element is in a (or is an) XML document
593         isXMLDoc: function( elem ) {
594                 return elem.documentElement && !elem.body ||
595                         elem.tagName && elem.ownerDocument && !elem.ownerDocument.body;
596         },
597
598         // Evalulates a script in a global context
599         globalEval: function( data ) {
600                 data = jQuery.trim( data );
601
602                 if ( data ) {
603                         // Inspired by code by Andrea Giammarchi
604                         // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
605                         var head = document.getElementsByTagName("head")[0] || document.documentElement,
606                                 script = document.createElement("script");
607
608                         script.type = "text/javascript";
609                         if ( jQuery.browser.msie )
610                                 script.text = data;
611                         else
612                                 script.appendChild( document.createTextNode( data ) );
613
614                         head.appendChild( script );
615                         head.removeChild( script );
616                 }
617         },
618
619         nodeName: function( elem, name ) {
620                 return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
621         },
622         
623         cache: {},
624         
625         data: function( elem, name, data ) {
626                 elem = elem == window ?
627                         windowData :
628                         elem;
629
630                 var id = elem[ expando ];
631
632                 // Compute a unique ID for the element
633                 if ( !id ) 
634                         id = elem[ expando ] = ++uuid;
635
636                 // Only generate the data cache if we're
637                 // trying to access or manipulate it
638                 if ( name && !jQuery.cache[ id ] )
639                         jQuery.cache[ id ] = {};
640                 
641                 // Prevent overriding the named cache with undefined values
642                 if ( data != undefined )
643                         jQuery.cache[ id ][ name ] = data;
644                 
645                 // Return the named cache data, or the ID for the element       
646                 return name ?
647                         jQuery.cache[ id ][ name ] :
648                         id;
649         },
650         
651         removeData: function( elem, name ) {
652                 elem = elem == window ?
653                         windowData :
654                         elem;
655
656                 var id = elem[ expando ];
657
658                 // If we want to remove a specific section of the element's data
659                 if ( name ) {
660                         if ( jQuery.cache[ id ] ) {
661                                 // Remove the section of cache data
662                                 delete jQuery.cache[ id ][ name ];
663
664                                 // If we've removed all the data, remove the element's cache
665                                 name = "";
666
667                                 for ( name in jQuery.cache[ id ] )
668                                         break;
669
670                                 if ( !name )
671                                         jQuery.removeData( elem );
672                         }
673
674                 // Otherwise, we want to remove all of the element's data
675                 } else {
676                         // Clean up the element expando
677                         try {
678                                 delete elem[ expando ];
679                         } catch(e){
680                                 // IE has trouble directly removing the expando
681                                 // but it's ok with using removeAttribute
682                                 if ( elem.removeAttribute )
683                                         elem.removeAttribute( expando );
684                         }
685
686                         // Completely remove the data cache
687                         delete jQuery.cache[ id ];
688                 }
689         },
690
691         // args is for internal usage only
692         each: function( object, callback, args ) {
693                 if ( args ) {
694                         if ( object.length == undefined )
695                                 for ( var name in object )
696                                         callback.apply( object[ name ], args );
697                         else
698                                 for ( var i = 0, length = object.length; i < length; i++ )
699                                         if ( callback.apply( object[ i ], args ) === false )
700                                                 break;
701
702                 // A special, fast, case for the most common use of each
703                 } else {
704                         if ( object.length == undefined )
705                                 for ( var name in object )
706                                         callback.call( object[ name ], name, object[ name ] );
707                         else
708                                 for ( var i = 0, length = object.length, value = object[0]; 
709                                         i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
710                 }
711
712                 return object;
713         },
714         
715         prop: function( elem, value, type, i, name ) {
716                         // Handle executable functions
717                         if ( jQuery.isFunction( value ) )
718                                 value = value.call( elem, i );
719                                 
720                         // Handle passing in a number to a CSS property
721                         return value && value.constructor == Number && type == "curCSS" && !exclude.test( name ) ?
722                                 value + "px" :
723                                 value;
724         },
725
726         className: {
727                 // internal only, use addClass("class")
728                 add: function( elem, classNames ) {
729                         jQuery.each((classNames || "").split(/\s+/), function(i, className){
730                                 if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) )
731                                         elem.className += (elem.className ? " " : "") + className;
732                         });
733                 },
734
735                 // internal only, use removeClass("class")
736                 remove: function( elem, classNames ) {
737                         if (elem.nodeType == 1)
738                                 elem.className = classNames != undefined ?
739                                         jQuery.grep(elem.className.split(/\s+/), function(className){
740                                                 return !jQuery.className.has( classNames, className );  
741                                         }).join(" ") :
742                                         "";
743                 },
744
745                 // internal only, use is(".class")
746                 has: function( elem, className ) {
747                         return jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1;
748                 }
749         },
750
751         // A method for quickly swapping in/out CSS properties to get correct calculations
752         swap: function( elem, options, callback ) {
753                 // Remember the old values, and insert the new ones
754                 for ( var name in options ) {
755                         elem.style[ "old" + name ] = elem.style[ name ];
756                         elem.style[ name ] = options[ name ];
757                 }
758
759                 callback.call( elem );
760
761                 // Revert the old values
762                 for ( var name in options )
763                         elem.style[ name ] = elem.style[ "old" + name ];
764         },
765
766         css: function( elem, name, force ) {
767                 if ( name == "height" || name == "width" ) {
768                         var old = {}, height, width;
769
770                         // Revert the padding and border widths to get the
771                         // correct height/width values
772                         jQuery.each([ "Top", "Bottom", "Right", "Left" ], function(){
773                                 old[ "padding" + this ] = 0;
774                                 old[ "border" + this + "Width" ] = 0;
775                         });
776
777                         // Swap out the padding/border values temporarily
778                         jQuery.swap( elem, old, function() {
779
780                                 // If the element is visible, then the calculation is easy
781                                 if ( jQuery( elem ).is(":visible") ) {
782                                         height = elem.offsetHeight;
783                                         width = elem.offsetWidth;
784
785                                 // Otherwise, we need to flip out more values
786                                 } else {
787                                         elem = jQuery( elem.cloneNode(true) )
788                                                 .find(":radio").removeAttr("checked").removeAttr("defaultChecked").end()
789                                                 .css({
790                                                         visibility: "hidden",
791                                                         position: "absolute",
792                                                         display: "block",
793                                                         right: "0",
794                                                         left: "0"
795                                                 }).appendTo( elem.parentNode )[0];
796
797                                         var position = jQuery.css( elem.parentNode, "position" ) || "static";
798                                         if ( position == "static" )
799                                                 elem.parentNode.style.position = "relative";
800
801                                         height = elem.clientHeight;
802                                         width = elem.clientWidth;
803
804                                         if ( position == "static" )
805                                                 elem.parentNode.style.position = "static";
806
807                                         elem.parentNode.removeChild( elem );
808                                 }
809                         });
810
811                         return name == "height" ?
812                                 height :
813                                 width;
814                 }
815
816                 return jQuery.curCSS( elem, name, force );
817         },
818
819         curCSS: function( elem, name, force ) {
820                 var ret;
821
822                 // A helper method for determining if an element's values are broken
823                 function color( elem ) {
824                         if ( !jQuery.browser.safari )
825                                 return false;
826
827                         var ret = document.defaultView.getComputedStyle( elem, null );
828                         return !ret || ret.getPropertyValue("color") == "";
829                 }
830
831                 // We need to handle opacity special in IE
832                 if ( name == "opacity" && jQuery.browser.msie ) {
833                         ret = jQuery.attr( elem.style, "opacity" );
834
835                         return ret == "" ?
836                                 "1" :
837                                 ret;
838                 }
839                 
840                 // Make sure we're using the right name for getting the float value
841                 if ( name.match( /float/i ) )
842                         name = styleFloat;
843
844                 if ( !force && elem.style[ name ] )
845                         ret = elem.style[ name ];
846
847                 else if ( document.defaultView && document.defaultView.getComputedStyle ) {
848
849                         // Only "float" is needed here
850                         if ( name.match( /float/i ) )
851                                 name = "float";
852
853                         name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
854
855                         var getComputedStyle = document.defaultView.getComputedStyle( elem, null );
856
857                         if ( getComputedStyle && !color( elem ) )
858                                 ret = getComputedStyle.getPropertyValue( name );
859
860                         // If the element isn't reporting its values properly in Safari
861                         // then some display: none elements are involved
862                         else {
863                                 var swap = [], stack = [];
864
865                                 // Locate all of the parent display: none elements
866                                 for ( var a = elem; a && color(a); a = a.parentNode )
867                                         stack.unshift(a);
868
869                                 // Go through and make them visible, but in reverse
870                                 // (It would be better if we knew the exact display type that they had)
871                                 for ( var i = 0; i < stack.length; i++ )
872                                         if ( color( stack[ i ] ) ) {
873                                                 swap[ i ] = stack[ i ].style.display;
874                                                 stack[ i ].style.display = "block";
875                                         }
876
877                                 // Since we flip the display style, we have to handle that
878                                 // one special, otherwise get the value
879                                 ret = name == "display" && swap[ stack.length - 1 ] != null ?
880                                         "none" :
881                                         ( getComputedStyle && getComputedStyle.getPropertyValue( name ) ) || "";
882
883                                 // Finally, revert the display styles back
884                                 for ( var i = 0; i < swap.length; i++ )
885                                         if ( swap[ i ] != null )
886                                                 stack[ i ].style.display = swap[ i ];
887                         }
888
889                         // We should always get a number back from opacity
890                         if ( name == "opacity" && ret == "" )
891                                 ret = "1";
892
893                 } else if ( elem.currentStyle ) {
894                         var camelCase = name.replace(/\-(\w)/g, function(all, letter){
895                                 return letter.toUpperCase();
896                         });
897
898                         ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
899
900                         // From the awesome hack by Dean Edwards
901                         // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
902
903                         // If we're not dealing with a regular pixel number
904                         // but a number that has a weird ending, we need to convert it to pixels
905                         if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
906                                 // Remember the original values
907                                 var style = elem.style.left, runtimeStyle = elem.runtimeStyle.left;
908
909                                 // Put in the new values to get a computed value out
910                                 elem.runtimeStyle.left = elem.currentStyle.left;
911                                 elem.style.left = ret || 0;
912                                 ret = elem.style.pixelLeft + "px";
913
914                                 // Revert the changed values
915                                 elem.style.left = style;
916                                 elem.runtimeStyle.left = runtimeStyle;
917                         }
918                 }
919
920                 return ret;
921         },
922         
923         clean: function( elems, context ) {
924                 var ret = [];
925                 context = context || document;
926                 // !context.createElement fails in IE with an error but returns typeof 'object'
927                 if (typeof context.createElement == 'undefined') 
928                         context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
929
930                 jQuery.each(elems, function(i, elem){
931                         if ( !elem )
932                                 return;
933
934                         if ( elem.constructor == Number )
935                                 elem = elem.toString();
936                         
937                         // Convert html string into DOM nodes
938                         if ( typeof elem == "string" ) {
939                                 // Fix "XHTML"-style tags in all browsers
940                                 elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
941                                         return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area)$/i) ?
942                                                 all :
943                                                 front + "></" + tag + ">";
944                                 });
945
946                                 // Trim whitespace, otherwise indexOf won't work as expected
947                                 var tags = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div");
948
949                                 var wrap =
950                                         // option or optgroup
951                                         !tags.indexOf("<opt") &&
952                                         [ 1, "<select multiple='multiple'>", "</select>" ] ||
953                                         
954                                         !tags.indexOf("<leg") &&
955                                         [ 1, "<fieldset>", "</fieldset>" ] ||
956                                         
957                                         tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
958                                         [ 1, "<table>", "</table>" ] ||
959                                         
960                                         !tags.indexOf("<tr") &&
961                                         [ 2, "<table><tbody>", "</tbody></table>" ] ||
962                                         
963                                         // <thead> matched above
964                                         (!tags.indexOf("<td") || !tags.indexOf("<th")) &&
965                                         [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] ||
966                                         
967                                         !tags.indexOf("<col") &&
968                                         [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] ||
969
970                                         // IE can't serialize <link> and <script> tags normally
971                                         jQuery.browser.msie &&
972                                         [ 1, "div<div>", "</div>" ] ||
973                                         
974                                         [ 0, "", "" ];
975
976                                 // Go to html and back, then peel off extra wrappers
977                                 div.innerHTML = wrap[1] + elem + wrap[2];
978                                 
979                                 // Move to the right depth
980                                 while ( wrap[0]-- )
981                                         div = div.lastChild;
982                                 
983                                 // Remove IE's autoinserted <tbody> from table fragments
984                                 if ( jQuery.browser.msie ) {
985                                         
986                                         // String was a <table>, *may* have spurious <tbody>
987                                         var tbody = !tags.indexOf("<table") && tags.indexOf("<tbody") < 0 ?
988                                                 div.firstChild && div.firstChild.childNodes :
989                                                 
990                                                 // String was a bare <thead> or <tfoot>
991                                                 wrap[1] == "<table>" && tags.indexOf("<tbody") < 0 ?
992                                                         div.childNodes :
993                                                         [];
994                                 
995                                         for ( var i = tbody.length - 1; i >= 0 ; --i )
996                                                 if ( jQuery.nodeName( tbody[ i ], "tbody" ) && !tbody[ i ].childNodes.length )
997                                                         tbody[ i ].parentNode.removeChild( tbody[ i ] );
998                                         
999                                         // IE completely kills leading whitespace when innerHTML is used        
1000                                         if ( /^\s/.test( elem ) )       
1001                                                 div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );
1002                                 
1003                                 }
1004                                 
1005                                 elem = jQuery.makeArray( div.childNodes );
1006                         }
1007
1008                         if ( elem.length === 0 && (!jQuery.nodeName( elem, "form" ) && !jQuery.nodeName( elem, "select" )) )
1009                                 return;
1010
1011                         if ( elem[0] == undefined || jQuery.nodeName( elem, "form" ) || elem.options )
1012                                 ret.push( elem );
1013
1014                         else
1015                                 ret = jQuery.merge( ret, elem );
1016
1017                 });
1018
1019                 return ret;
1020         },
1021         
1022         attr: function( elem, name, value ) {
1023                 // don't set attributes on text and comment nodes
1024                 if (!elem || elem.nodeType == 3 || elem.nodeType == 8)
1025                         return undefined;
1026
1027                 var fix = jQuery.isXMLDoc( elem ) ?
1028                         {} :
1029                         jQuery.props;
1030
1031                 // Safari mis-reports the default selected property of a hidden option
1032                 // Accessing the parent's selectedIndex property fixes it
1033                 if ( name == "selected" && jQuery.browser.safari )
1034                         elem.parentNode.selectedIndex;
1035                 
1036                 // Certain attributes only work when accessed via the old DOM 0 way
1037                 if ( fix[ name ] ) {
1038                         if ( value != undefined )
1039                                 elem[ fix[ name ] ] = value;
1040
1041                         return elem[ fix[ name ] ];
1042
1043                 } else if ( jQuery.browser.msie && name == "style" )
1044                         return jQuery.attr( elem.style, "cssText", value );
1045
1046                 else if ( value == undefined && jQuery.browser.msie && jQuery.nodeName( elem, "form" ) && (name == "action" || name == "method") )
1047                         return elem.getAttributeNode( name ).nodeValue;
1048
1049                 // IE elem.getAttribute passes even for style
1050                 else if ( elem.tagName ) {
1051
1052                         if ( value != undefined ) {
1053                                 // We can't allow the type property to be changed (since it causes problems in IE)
1054                                 if ( name == "type" && jQuery.nodeName( elem, "input" ) && elem.parentNode )
1055                                         throw "type property can't be changed";
1056
1057                                 // convert the value to a string (all browsers do this but IE) see #1070
1058                                 elem.setAttribute( name, "" + value );
1059                         }
1060
1061                         if ( jQuery.browser.msie && /href|src/.test( name ) && !jQuery.isXMLDoc( elem ) ) 
1062                                 return elem.getAttribute( name, 2 );
1063
1064                         return elem.getAttribute( name );
1065
1066                 // elem is actually elem.style ... set the style
1067                 } else {
1068                         // IE actually uses filters for opacity
1069                         if ( name == "opacity" && jQuery.browser.msie ) {
1070                                 if ( value != undefined ) {
1071                                         // IE has trouble with opacity if it does not have layout
1072                                         // Force it by setting the zoom level
1073                                         elem.zoom = 1; 
1074         
1075                                         // Set the alpha filter to set the opacity
1076                                         elem.filter = (elem.filter || "").replace( /alpha\([^)]*\)/, "" ) +
1077                                                 (parseFloat( value ).toString() == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")");
1078                                 }
1079         
1080                                 return elem.filter && elem.filter.indexOf("opacity=") >= 0 ?
1081                                         (parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100).toString() :
1082                                         "";
1083                         }
1084
1085                         name = name.replace(/-([a-z])/ig, function(all, letter){
1086                                 return letter.toUpperCase();
1087                         });
1088
1089                         if ( value != undefined )
1090                                 elem[ name ] = value;
1091
1092                         return elem[ name ];
1093                 }
1094         },
1095         
1096         trim: function( text ) {
1097                 return (text || "").replace( /^\s+|\s+$/g, "" );
1098         },
1099
1100         makeArray: function( array ) {
1101                 var ret = [];
1102
1103                 // Need to use typeof to fight Safari childNodes crashes
1104                 if ( typeof array != "array" )
1105                         for ( var i = 0, length = array.length; i < length; i++ )
1106                                 ret.push( array[ i ] );
1107                 else
1108                         ret = array.slice( 0 );
1109
1110                 return ret;
1111         },
1112
1113         inArray: function( elem, array ) {
1114                 for ( var i = 0, length = array.length; i < length; i++ )
1115                         if ( array[ i ] == elem )
1116                                 return i;
1117
1118                 return -1;
1119         },
1120
1121         merge: function( first, second ) {
1122                 // We have to loop this way because IE & Opera overwrite the length
1123                 // expando of getElementsByTagName
1124
1125                 // Also, we need to make sure that the correct elements are being returned
1126                 // (IE returns comment nodes in a '*' query)
1127                 if ( jQuery.browser.msie ) {
1128                         for ( var i = 0; second[ i ]; i++ )
1129                                 if ( second[ i ].nodeType != 8 )
1130                                         first.push( second[ i ] );
1131
1132                 } else
1133                         for ( var i = 0; second[ i ]; i++ )
1134                                 first.push( second[ i ] );
1135
1136                 return first;
1137         },
1138
1139         unique: function( array ) {
1140                 var ret = [], done = {};
1141
1142                 try {
1143
1144                         for ( var i = 0, length = array.length; i < length; i++ ) {
1145                                 var id = jQuery.data( array[ i ] );
1146
1147                                 if ( !done[ id ] ) {
1148                                         done[ id ] = true;
1149                                         ret.push( array[ i ] );
1150                                 }
1151                         }
1152
1153                 } catch( e ) {
1154                         ret = array;
1155                 }
1156
1157                 return ret;
1158         },
1159
1160         grep: function( elems, callback, inv ) {
1161                 // If a string is passed in for the function, make a function
1162                 // for it (a handy shortcut)
1163                 if ( typeof callback == "string" )
1164                         callback = eval("false||function(a,i){return " + callback + "}");
1165
1166                 var ret = [];
1167
1168                 // Go through the array, only saving the items
1169                 // that pass the validator function
1170                 for ( var i = 0, length = elems.length; i < length; i++ )
1171                         if ( !inv && callback( elems[ i ], i ) || inv && !callback( elems[ i ], i ) )
1172                                 ret.push( elems[ i ] );
1173
1174                 return ret;
1175         },
1176
1177         map: function( elems, callback ) {
1178                 var ret = [];
1179
1180                 // Go through the array, translating each of the items to their
1181                 // new value (or values).
1182                 for ( var i = 0, length = elems.length; i < length; i++ ) {
1183                         var value = callback( elems[ i ], i );
1184
1185                         if ( value !== null && value != undefined ) {
1186                                 if ( value.constructor != Array )
1187                                         value = [ value ];
1188
1189                                 ret = ret.concat( value );
1190                         }
1191                 }
1192
1193                 return ret;
1194         }
1195 });
1196
1197 var userAgent = navigator.userAgent.toLowerCase();
1198
1199 // Figure out what browser is being used
1200 jQuery.browser = {
1201         version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
1202         safari: /webkit/.test( userAgent ),
1203         opera: /opera/.test( userAgent ),
1204         msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
1205         mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
1206 };
1207
1208 var styleFloat = jQuery.browser.msie ?
1209         "styleFloat" :
1210         "cssFloat";
1211         
1212 jQuery.extend({
1213         // Check to see if the W3C box model is being used
1214         boxModel: !jQuery.browser.msie || document.compatMode == "CSS1Compat",
1215         
1216         props: {
1217                 "for": "htmlFor",
1218                 "class": "className",
1219                 "float": styleFloat,
1220                 cssFloat: styleFloat,
1221                 styleFloat: styleFloat,
1222                 innerHTML: "innerHTML",
1223                 className: "className",
1224                 value: "value",
1225                 disabled: "disabled",
1226                 checked: "checked",
1227                 readonly: "readOnly",
1228                 selected: "selected",
1229                 maxlength: "maxLength",
1230                 selectedIndex: "selectedIndex",
1231                 defaultValue: "defaultValue",
1232                 tagName: "tagName",
1233                 nodeName: "nodeName"
1234         }
1235 });
1236
1237 jQuery.each({
1238         parent: "elem.parentNode",
1239         parents: "jQuery.dir(elem,'parentNode')",
1240         next: "jQuery.nth(elem,2,'nextSibling')",
1241         prev: "jQuery.nth(elem,2,'previousSibling')",
1242         nextAll: "jQuery.dir(elem,'nextSibling')",
1243         prevAll: "jQuery.dir(elem,'previousSibling')",
1244         siblings: "jQuery.sibling(elem.parentNode.firstChild,elem)",
1245         children: "jQuery.sibling(elem.firstChild)",
1246         contents: "jQuery.nodeName(elem,'iframe')?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes)"
1247 }, function(name, fn){
1248         fn = eval("false||function(elem){return " + fn + "}");
1249
1250         jQuery.fn[ name ] = function( selector ) {
1251                 var ret = jQuery.map( this, fn );
1252
1253                 if ( selector && typeof selector == "string" )
1254                         ret = jQuery.multiFilter( selector, ret );
1255
1256                 return this.pushStack( jQuery.unique( ret ) );
1257         };
1258 });
1259
1260 jQuery.each({
1261         appendTo: "append",
1262         prependTo: "prepend",
1263         insertBefore: "before",
1264         insertAfter: "after",
1265         replaceAll: "replaceWith"
1266 }, function(name, original){
1267         jQuery.fn[ name ] = function() {
1268                 var args = arguments;
1269
1270                 return this.each(function(){
1271                         for ( var i = 0, length = args.length; i < length; i++ )
1272                                 jQuery( args[ i ] )[ original ]( this );
1273                 });
1274         };
1275 });
1276
1277 jQuery.each({
1278         removeAttr: function( name ) {
1279                 jQuery.attr( this, name, "" );
1280                 if (this.nodeType == 1) 
1281                         this.removeAttribute( name );
1282         },
1283
1284         addClass: function( classNames ) {
1285                 jQuery.className.add( this, classNames );
1286         },
1287
1288         removeClass: function( classNames ) {
1289                 jQuery.className.remove( this, classNames );
1290         },
1291
1292         toggleClass: function( classNames ) {
1293                 jQuery.className[ jQuery.className.has( this, classNames ) ? "remove" : "add" ]( this, classNames );
1294         },
1295
1296         remove: function( selector ) {
1297                 if ( !selector || jQuery.filter( selector, [ this ] ).r.length ) {
1298                         // Prevent memory leaks
1299                         jQuery( "*", this ).add(this).each(function(){
1300                                 jQuery.event.remove(this);
1301                                 jQuery.removeData(this);
1302                         });
1303                         if (this.parentNode)
1304                                 this.parentNode.removeChild( this );
1305                 }
1306         },
1307
1308         empty: function() {
1309                 // Remove element nodes and prevent memory leaks
1310                 jQuery( ">*", this ).remove();
1311                 
1312                 // Remove any remaining nodes
1313                 while ( this.firstChild )
1314                         this.removeChild( this.firstChild );
1315         }
1316 }, function(name, fn){
1317         jQuery.fn[ name ] = function(){
1318                 return this.each( fn, arguments );
1319         };
1320 });
1321
1322 jQuery.each([ "Height", "Width" ], function(i, name){
1323         var type = name.toLowerCase();
1324         
1325         jQuery.fn[ type ] = function( size ) {
1326                 // Get window width or height
1327                 return this[0] == window ?
1328                         // Opera reports document.body.client[Width/Height] properly in both quirks and standards
1329                         jQuery.browser.opera && document.body[ "client" + name ] || 
1330                         
1331                         // Safari reports inner[Width/Height] just fine (Mozilla and Opera include scroll bar widths)
1332                         jQuery.browser.safari && window[ "inner" + name ] ||
1333                         
1334                         // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
1335                         document.compatMode == "CSS1Compat" && document.documentElement[ "client" + name ] || document.body[ "client" + name ] :
1336                 
1337                         // Get document width or height
1338                         this[0] == document ?
1339                                 // Either scroll[Width/Height] or offset[Width/Height], whichever is greater (Mozilla reports scrollWidth the same as offsetWidth)
1340                                 Math.max( document.body[ "scroll" + name ], document.body[ "offset" + name ] ) :
1341
1342                                 // Get or set width or height on the element
1343                                 size == undefined ?
1344                                         // Get width or height on the element
1345                                         (this.length ? jQuery.css( this[0], type ) : null) :
1346
1347                                         // Set the width or height on the element (default to pixels if value is unitless)
1348                                         this.css( type, size.constructor == String ? size : size + "px" );
1349         };
1350 });