Marked all the appropriate methods as being deprecated for the 1.1.4 release (in...
[jquery.git] / src / jquery / jquery.js
index 5940df3..4c5941b 100644 (file)
@@ -9,9 +9,6 @@
  * $Rev$
  */
 
-// Global undefined variable
-window.undefined = window.undefined;
-
 /**
  * Create a new jQuery Object
  *
@@ -22,7 +19,12 @@ window.undefined = window.undefined;
  * @param jQuery|Element|Array<Element> c context
  * @cat Core
  */
-var jQuery = function(a,c) {
+
+// Map over jQuery in case of overwrite
+if ( typeof jQuery != "undefined" )
+       var _jQuery = jQuery;
+
+var jQuery = window.jQuery = function(a,c) {
        // If the context is global, return a new object
        if ( window == this || !this.init )
                return new jQuery(a,c);
@@ -32,10 +34,12 @@ var jQuery = function(a,c) {
 
 // Map over the $ in case of overwrite
 if ( typeof $ != "undefined" )
-       jQuery._$ = $;
+       var _$ = $;
        
 // Map the jQuery namespace to the '$' one
-var $ = jQuery;
+window.$ = jQuery;
+
+var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/;
 
 /**
  * This function accepts a string containing a CSS or
@@ -153,22 +157,39 @@ jQuery.fn = jQuery.prototype = {
                // Make sure that a selection was provided
                a = a || document;
 
-               // HANDLE: $(function)
-               // Shortcut for document ready
-               if ( jQuery.isFunction(a) )
-                       return new jQuery(document)[ jQuery.fn.ready ? "ready" : "load" ]( a );
-
                // Handle HTML strings
                if ( typeof a  == "string" ) {
-                       // HANDLE: $(html) -> $(array)
-                       var m = /^[^<]*(<(.|\s)+>)[^>]*$/.exec(a);
-                       if ( m )
-                               a = jQuery.clean( [ m[1] ] );
+                       var m = quickExpr.exec(a);
+                       if ( m && (m[1] || !c) ) {
+                               // HANDLE: $(html) -> $(array)
+                               if ( m[1] )
+                                       a = jQuery.clean( [ m[1] ] );
+
+                               // HANDLE: $("#id")
+                               else {
+                                       var tmp = document.getElementById( m[3] );
+                                       if ( tmp )
+                                               // Handle the case where IE and Opera return items
+                                               // by name instead of ID
+                                               if ( tmp.id != m[3] )
+                                                       return jQuery().find( a );
+                                               else {
+                                                       this[0] = tmp;
+                                                       this.length = 1;
+                                                       return this;
+                                               }
+                                       else
+                                               a = [];
+                               }
 
                        // HANDLE: $(expr)
-                       else
+                       } else
                                return new jQuery( c ).find( a );
-               }
+
+               // HANDLE: $(function)
+               // Shortcut for document ready
+               } else if ( jQuery.isFunction(a) )
+                       return new jQuery(document)[ jQuery.fn.ready ? "ready" : "load" ]( a );
 
                return this.setArray(
                        // HANDLE: $(array)
@@ -301,7 +322,7 @@ jQuery.fn = jQuery.prototype = {
         */
        setArray: function( a ) {
                this.length = 0;
-               [].push.apply( this, a );
+               Array.prototype.push.apply( this, a );
                return this;
        },
 
@@ -565,7 +586,7 @@ jQuery.fn = jQuery.prototype = {
         * @cat DOM/Attributes
         */
        text: function(e) {
-               if ( typeof e == "string" )
+               if ( typeof e != "object" && e != null )
                        return this.empty().append( document.createTextNode( e ) );
 
                var t = "";
@@ -811,7 +832,7 @@ jQuery.fn = jQuery.prototype = {
 
        /**
         * Searches for all elements that match the specified expression.
-        
+        * 
         * This method is a good way to find additional descendant
         * elements with which to process.
         *
@@ -852,27 +873,43 @@ jQuery.fn = jQuery.prototype = {
         * @cat DOM/Manipulation
         */
        clone: function(deep) {
-               // Need to remove events on the element and its descendants
+               deep = deep != undefined ? deep : true;
                var $this = this.add(this.find("*"));
-               $this.each(function() {
-                       this._$events = {};
-                       for (var type in this.$events)
-                               this._$events[type] = jQuery.extend({},this.$events[type]);
-               }).unbind();
+               if (jQuery.browser.msie) {
+                       // Need to remove events on the element and its descendants
+                       $this.each(function() {
+                               this._$events = {};
+                               for (var type in this.$events)
+                                       this._$events[type] = jQuery.extend({},this.$events[type]);
+                       }).unbind();
+               }
 
                // Do the clone
                var r = this.pushStack( jQuery.map( this, function(a){
-                       return a.cloneNode( deep != undefined ? deep : true );
+                       return a.cloneNode( deep );
                }) );
 
-               // Add the events back to the original and its descendants
-               $this.each(function() {
-                       var events = this._$events;
-                       for (var type in events)
-                               for (var handler in events[type])
-                                       jQuery.event.add(this, type, events[type][handler], events[type][handler].data);
-                       this._$events = null;
-               });
+               if (jQuery.browser.msie) {
+                       $this.each(function() {
+                               // Add the events back to the original and its descendants
+                               var events = this._$events;
+                               for (var type in events)
+                                       for (var handler in events[type])
+                                               jQuery.event.add(this, type, events[type][handler], events[type][handler].data);
+                               this._$events = null;
+                       });
+               }
+
+               // copy form values over
+               if (deep) {
+                       var inputs = r.add(r.find('*')).filter('select,input[@type=checkbox]');
+                       $this.filter('select,input[@type=checkbox]').each(function(i) {
+                               if (this.selectedIndex)
+                                       inputs[i].selectedIndex = this.selectedIndex;
+                               if (this.checked)
+                                       inputs[i].checked = true;
+                       });
+               }
 
                // Return the cloned set
                return r;
@@ -922,7 +959,7 @@ jQuery.fn = jQuery.prototype = {
                return this.pushStack(
                        jQuery.isFunction( t ) &&
                        jQuery.grep(this, function(el, index){
-                               return t.apply(el, [index])
+                               return t.apply(el, [index]);
                        }) ||
 
                        jQuery.multiFilter(t,this) );
@@ -1144,6 +1181,10 @@ jQuery.fn = jQuery.prototype = {
                        ( this.length ? this[0].innerHTML : null ) :
                        this.empty().append( val );
        },
+
+       slice: function() {
+               return this.pushStack( Array.prototype.slice.apply( this, arguments ) );
+       },
        
        /**
         * @private
@@ -1171,9 +1212,14 @@ jQuery.fn = jQuery.prototype = {
                                obj = this.getElementsByTagName("tbody")[0] || this.appendChild(document.createElement("tbody"));
 
                        jQuery.each( a, function(){
-                               fn.apply( obj, [ clone ? this.cloneNode(true) : this ] );
+                               if ( jQuery.nodeName(this, "script") ) {
+                                       if ( this.src )
+                                               jQuery.ajax({ url: this.src, async: false, dataType: "script" });
+                                       else
+                                               jQuery.globalEval( this.text || this.textContent || this.innerHTML || "" );
+                               } else
+                                       fn.apply( obj, [ clone ? this.cloneNode(true) : this ] );
                        });
-
                });
        }
 };
@@ -1231,17 +1277,39 @@ jQuery.fn = jQuery.prototype = {
  */
 jQuery.extend = jQuery.fn.extend = function() {
        // copy reference to target object
-       var target = arguments[0], a = 1;
+       var target = arguments[0] || {}, a = 1, al = arguments.length, deep = false;
+
+       // Handle a deep copy situation
+       if ( target.constructor == Boolean ) {
+               deep = target;
+               target = arguments[1] || {};
+       }
 
        // extend jQuery itself if only one argument is passed
-       if ( arguments.length == 1 ) {
+       if ( al == 1 ) {
                target = this;
                a = 0;
        }
+
        var prop;
-       while ( (prop = arguments[a++]) != null )
-               // Extend the base object
-               for ( var i in prop ) target[i] = prop[i];
+
+       for ( ; a < al; a++ )
+               // Only deal with non-null/undefined values
+               if ( (prop = arguments[a]) != null )
+                       // Extend the base object
+                       for ( var i in prop ) {
+                               // Prevent never-ending loop
+                               if ( target == prop[i] )
+                                       continue;
+
+                               // Recurse if we're merging object values
+                               if ( deep && typeof prop[i] == 'object' && target[i] )
+                                       jQuery.extend( target[i], prop[i] );
+
+                               // Don't bring in undefined values
+                               else if ( prop[i] != undefined )
+                                       target[i] = prop[i];
+                       }
 
        // Return the modified object
        return target;
@@ -1282,9 +1350,10 @@ jQuery.extend({
         * @type undefined
         * @cat Core 
         */
-       noConflict: function() {
-               if ( jQuery._$ )
-                       $ = jQuery._$;
+       noConflict: function(deep) {
+               window.$ = _$;
+               if ( deep )
+                       window.jQuery = _jQuery;
                return jQuery;
        },
 
@@ -1297,7 +1366,23 @@ jQuery.extend({
        
        // check if an element is in a XML document
        isXMLDoc: function(elem) {
-               return elem.tagName && elem.ownerDocument && !elem.ownerDocument.body;
+               return elem.documentElement && !elem.body ||
+                       elem.tagName && elem.ownerDocument && !elem.ownerDocument.body;
+       },
+
+       // Evalulates a script in a global context
+       // Evaluates Async. in Safari 2 :-(
+       globalEval: function( data ) {
+               data = jQuery.trim( data );
+               if ( data ) {
+                       if ( window.execScript )
+                               window.execScript( data );
+                       else if ( jQuery.browser.safari )
+                               // safari doesn't provide a synchronous global eval
+                               window.setTimeout( data, 0 );
+                       else
+                               eval.call( window, data );
+               }
        },
 
        nodeName: function( elem, name ) {
@@ -1334,12 +1419,24 @@ jQuery.extend({
         */
        // args is for internal usage only
        each: function( obj, fn, args ) {
-               if ( obj.length == undefined )
-                       for ( var i in obj )
-                               fn.apply( obj[i], args || [i, obj[i]] );
-               else
-                       for ( var i = 0, ol = obj.length; i < ol; i++ )
-                               if ( fn.apply( obj[i], args || [i, obj[i]] ) === false ) break;
+               if ( args ) {
+                       if ( obj.length == undefined )
+                               for ( var i in obj )
+                                       fn.apply( obj[i], args );
+                       else
+                               for ( var i = 0, ol = obj.length; i < ol; i++ )
+                                       if ( fn.apply( obj[i], args ) === false ) break;
+
+               // A special, fast, case for the most common use of each
+               } else {
+                       if ( obj.length == undefined )
+                               for ( var i in obj )
+                                       fn.call( obj[i], i, obj[i] );
+                       else
+                               for ( var i = 0, ol = obj.length, val = obj[0]; 
+                                       i < ol && fn.call(val,i,val) !== false; val = obj[++i] ){}
+               }
+
                return obj;
        },
        
@@ -1360,7 +1457,7 @@ jQuery.extend({
        className: {
                // internal only, use addClass("class")
                add: function( elem, c ){
-                       jQuery.each( c.split(/\s+/), function(i, cur){
+                       jQuery.each( (c || "").split(/\s+/), function(i, cur){
                                if ( !jQuery.className.has( elem.className, cur ) )
                                        elem.className += ( elem.className ? " " : "" ) + cur;
                        });
@@ -1435,7 +1532,16 @@ jQuery.extend({
        },
 
        curCSS: function(elem, prop, force) {
-               var ret;
+               var ret, stack = [], swap = [];
+
+               // A helper method for determining if an element's values are broken
+               function color(a){
+                       if ( !jQuery.browser.safari )
+                               return false;
+
+                       var ret = document.defaultView.getComputedStyle(a,null);
+                       return !ret || ret.getPropertyValue("color") == "";
+               }
 
                if (prop == "opacity" && jQuery.browser.msie) {
                        ret = jQuery.attr(elem.style, "opacity");
@@ -1443,7 +1549,7 @@ jQuery.extend({
                }
                
                if (prop.match(/float/i))
-                       prop = jQuery.browser.msie ? "styleFloat" : "cssFloat";
+                       prop = styleFloat;
 
                if (!force && elem.style[prop])
                        ret = elem.style[prop];
@@ -1456,15 +1562,38 @@ jQuery.extend({
                        prop = prop.replace(/([A-Z])/g,"-$1").toLowerCase();
                        var cur = document.defaultView.getComputedStyle(elem, null);
 
-                       if ( cur )
+                       if ( cur && !color(elem) )
                                ret = cur.getPropertyValue(prop);
-                       else if ( prop == "display" )
-                               ret = "none";
-                       else
-                               jQuery.swap(elem, { display: "block" }, function() {
-                                   var c = document.defaultView.getComputedStyle(this, "");
-                                   ret = c && c.getPropertyValue(prop) || "";
-                               });
+
+                       // If the element isn't reporting its values properly in Safari
+                       // then some display: none elements are involved
+                       else {
+                               // Locate all of the parent display: none elements
+                               for ( var a = elem; a && color(a); a = a.parentNode )
+                                       stack.unshift(a);
+
+                               // Go through and make them visible, but in reverse
+                               // (It would be better if we knew the exact display type that they had)
+                               for ( a = 0; a < stack.length; a++ )
+                                       if ( color(stack[a]) ) {
+                                               swap[a] = stack[a].style.display;
+                                               stack[a].style.display = "block";
+                                       }
+
+                               // Since we flip the display style, we have to handle that
+                               // one special, otherwise get the value
+                               ret = prop == "display" && swap[stack.length-1] != null ?
+                                       "none" :
+                                       document.defaultView.getComputedStyle(elem,null).getPropertyValue(prop) || "";
+
+                               // Finally, revert the display styles back
+                               for ( a = 0; a < swap.length; a++ )
+                                       if ( swap[a] != null )
+                                               stack[a].style.display = swap[a];
+                       }
+
+                       if ( prop == "opacity" && ret == "" )
+                               ret = "1";
 
                } else if (elem.currentStyle) {
                        var newProp = prop.replace(/\-(\w)/g,function(m,c){return c.toUpperCase();});
@@ -1497,7 +1626,7 @@ jQuery.extend({
                                        !s.indexOf("<leg") &&
                                        [1, "<fieldset>", "</fieldset>"] ||
                                        
-                                       (!s.indexOf("<thead") || !s.indexOf("<tbody") || !s.indexOf("<tfoot") || !s.indexOf("<colg")) &&
+                                       s.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
                                        [1, "<table>", "</table>"] ||
                                        
                                        !s.indexOf("<tr") &&
@@ -1508,7 +1637,11 @@ jQuery.extend({
                                        [3, "<table><tbody><tr>", "</tr></tbody></table>"] ||
                                        
                                        !s.indexOf("<col") &&
-                                       [2, "<table><colgroup>", "</colgroup></table>"] ||
+                                       [2, "<table><tbody></tbody><colgroup>", "</colgroup></table>"] ||
+
+                                       // IE can't serialize <link> and <script> tags normally
+                                       jQuery.browser.msie &&
+                                       [1, "div<div>", "</div>"] ||
                                        
                                        [0,"",""];
 
@@ -1517,7 +1650,7 @@ jQuery.extend({
                                
                                // Move to the right depth
                                while ( wrap[0]-- )
-                                       div = div.firstChild;
+                                       div = div.lastChild;
                                
                                // Remove IE's autoinserted <tbody> from table fragments
                                if ( jQuery.browser.msie ) {
@@ -1533,7 +1666,11 @@ jQuery.extend({
                                        for ( var n = tb.length-1; n >= 0 ; --n )
                                                if ( jQuery.nodeName(tb[n], "tbody") && !tb[n].childNodes.length )
                                                        tb[n].parentNode.removeChild(tb[n]);
-                                       
+       
+                                       // IE completely kills leading whitespace when innerHTML is used        
+                                       if ( /^\s/.test(arg) )  
+                                               div.insertBefore( doc.createTextNode( arg.match(/^\s*/)[0] ), div.firstChild );
+
                                }
                                
                                arg = jQuery.makeArray( div.childNodes );
@@ -1554,18 +1691,33 @@ jQuery.extend({
        
        attr: function(elem, name, value){
                var fix = jQuery.isXMLDoc(elem) ? {} : jQuery.props;
+
+               // Safari mis-reports the default selected property of a hidden option
+               // Accessing the parent's selectedIndex property fixes it
+               if ( name == "selected" && jQuery.browser.safari )
+                       elem.parentNode.selectedIndex;
                
                // Certain attributes only work when accessed via the old DOM 0 way
                if ( fix[name] ) {
                        if ( value != undefined ) elem[fix[name]] = value;
                        return elem[fix[name]];
+               } else if ( jQuery.browser.msie && name == "style" )
+                       return jQuery.attr( elem.style, "cssText", value );
 
-               } else if ( value == undefined && jQuery.browser.msie && jQuery.nodeName(elem, "form") && (name == "action" || name == "method") )
+               else if ( value == undefined && jQuery.browser.msie && jQuery.nodeName(elem, "form") && (name == "action" || name == "method") )
                        return elem.getAttributeNode(name).nodeValue;
 
                // IE elem.getAttribute passes even for style
                else if ( elem.tagName ) {
-                       // IE actually uses filters for opacity ... elem is actually elem.style
+
+                       if ( value != undefined ) elem.setAttribute( name, value );
+                       if ( jQuery.browser.msie && /href|src/.test(name) && !jQuery.isXMLDoc(elem) ) 
+                               return elem.getAttribute( name, 2 );
+                       return elem.getAttribute( name );
+
+               // elem is actually elem.style ... set the style
+               } else {
+                       // IE actually uses filters for opacity
                        if ( name == "opacity" && jQuery.browser.msie ) {
                                if ( value != undefined ) {
                                        // IE has trouble with opacity if it does not have layout
@@ -1580,14 +1732,6 @@ jQuery.extend({
                                return elem.filter ? 
                                        (parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100).toString() : "";
                        }
-
-                       if ( value != undefined ) elem.setAttribute( name, value );
-                       if ( jQuery.browser.msie && /href|src/.test(name) && !jQuery.isXMLDoc(elem) ) 
-                               return elem.getAttribute( name, 2 );
-                       return elem.getAttribute( name );
-
-               // elem is actually elem.style ... set the style
-               } else {
                        name = name.replace(/-([a-z])/ig,function(z,b){return b.toUpperCase();});
                        if ( value != undefined ) elem[name] = value;
                        return elem[name];
@@ -1606,7 +1750,7 @@ jQuery.extend({
         * @cat JavaScript
         */
        trim: function(t){
-               return t.replace(/^\s+|\s+$/g, "");
+               return (t||"").replace(/^\s+|\s+$/g, "");
        },
 
        makeArray: function( a ) {
@@ -1645,8 +1789,17 @@ jQuery.extend({
        merge: function(first, second) {
                // We have to loop this way because IE & Opera overwrite the length
                // expando of getElementsByTagName
-               for ( var i = 0; second[i]; i++ )
-                       first.push(second[i]);
+
+               // Also, we need to make sure that the correct elements are being returned
+               // (IE returns comment nodes in a '*' query)
+               if ( jQuery.browser.msie ) {
+                       for ( var i = 0; second[i]; i++ )
+                               if ( second[i].nodeType != 8 )
+                                       first.push(second[i]);
+               } else
+                       for ( var i = 0; second[i]; i++ )
+                               first.push(second[i]);
+
                return first;
        },
 
@@ -1665,11 +1818,15 @@ jQuery.extend({
        unique: function(first) {
                var r = [], num = jQuery.mergeNum++;
 
-               for ( var i = 0, fl = first.length; i < fl; i++ )
-                       if ( num != first[i].mergeNum ) {
-                               first[i].mergeNum = num;
-                               r.push(first[i]);
-                       }
+               try {
+                       for ( var i = 0, fl = first.length; i < fl; i++ )
+                               if ( num != first[i].mergeNum ) {
+                                       first[i].mergeNum = num;
+                                       r.push(first[i]);
+                               }
+               } catch(e) {
+                       r = first;
+               }
 
                return r;
        },
@@ -1700,7 +1857,7 @@ jQuery.extend({
                // If a string is passed in for the function, make a function
                // for it (a handy shortcut)
                if ( typeof fn == "string" )
-                       fn = new Function("a","i","return " + fn);
+                       fn = eval("false||function(a,i){return " + fn + "}");
 
                var result = [];
 
@@ -1754,7 +1911,7 @@ jQuery.extend({
                // If a string is passed in for the function, make a function
                // for it (a handy shortcut)
                if ( typeof fn == "string" )
-                       fn = new Function("a","return " + fn);
+                       fn = eval("false||function(a){return " + fn + "}");
 
                var result = [];
 
@@ -1805,27 +1962,31 @@ jQuery.extend({
  * @type Boolean
  * @cat JavaScript
  */
-new function() {
-       var b = navigator.userAgent.toLowerCase();
-
-       // Figure out what browser is being used
-       jQuery.browser = {
-               version: b.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)[1],
-               safari: /webkit/.test(b),
-               opera: /opera/.test(b),
-               msie: /msie/.test(b) && !/opera/.test(b),
-               mozilla: /mozilla/.test(b) && !/(compatible|webkit)/.test(b)
-       };
+var userAgent = navigator.userAgent.toLowerCase();
+
+// Figure out what browser is being used
+jQuery.browser = {
+       version: (userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [])[1],
+       safari: /webkit/.test(userAgent),
+       opera: /opera/.test(userAgent),
+       msie: /msie/.test(userAgent) && !/opera/.test(userAgent),
+       mozilla: /mozilla/.test(userAgent) && !/(compatible|webkit)/.test(userAgent)
+};
 
+var styleFloat = jQuery.browser.msie ? "styleFloat" : "cssFloat";
+       
+jQuery.extend({
        // Check to see if the W3C box model is being used
-       jQuery.boxModel = !jQuery.browser.msie || document.compatMode == "CSS1Compat";
-
-       jQuery.props = {
+       boxModel: !jQuery.browser.msie || document.compatMode == "CSS1Compat",
+       
+       styleFloat: jQuery.browser.msie ? "styleFloat" : "cssFloat",
+       
+       props: {
                "for": "htmlFor",
                "class": "className",
-               "float": jQuery.browser.msie ? "styleFloat" : "cssFloat",
-               cssFloat: jQuery.browser.msie ? "styleFloat" : "cssFloat",
-               styleFloat: jQuery.browser.msie ? "styleFloat" : "cssFloat",
+               "float": styleFloat,
+               cssFloat: styleFloat,
+               styleFloat: styleFloat,
                innerHTML: "innerHTML",
                className: "className",
                value: "value",
@@ -1834,8 +1995,8 @@ new function() {
                readonly: "readOnly",
                selected: "selected",
                maxlength: "maxLength"
-       };
-};
+       }
+});
 
 /**
  * Get a set of elements containing the unique parents of the matched
@@ -1986,7 +2147,7 @@ jQuery.each({
                var ret = jQuery.map(this,n);
                if ( a && typeof a == "string" )
                        ret = jQuery.multiFilter(a,ret);
-               return this.pushStack( ret );
+               return this.pushStack( jQuery.unique(ret) );
        };
 });
 
@@ -2261,6 +2422,7 @@ jQuery.each( {
  * @param String str The string that will be contained within the text of an element.
  * @cat DOM/Traversing
  */
+// DEPRECATED
 jQuery.each( [ "eq", "lt", "gt", "contains" ], function(i,n){
        jQuery.fn[ n ] = function(num,fn) {
                return this.filter( ":" + n + "(" + num + ")", fn );