Backported wiki changes from http://docs.jquery.com/API/1.1.1/Core
[jquery.git] / src / jquery / jquery.js
index f756b67..64ade0a 100644 (file)
@@ -32,14 +32,13 @@ var jQuery = function(a,c) {
        
        // HANDLE: $(function)
        // Shortcut for document ready
-       // Safari reports typeof on DOM NodeLists as a function
-       if ( jQuery.isFunction(a) && !a.nodeType && a[0] == undefined )
+       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 = /^[^<]*(<.+>)[^>]*$/.exec(a);
+               var m = /^[^<]*(<(.|\s)+>)[^>]*$/.exec(a);
                if ( m )
                        a = jQuery.clean( [ m[1] ] );
                
@@ -77,8 +76,12 @@ var $ = jQuery;
  * (usually consisting of CSS or XPath), which then finds all matching
  * elements.
  *
- * By default, $() looks for DOM elements within the context of the
- * current HTML document.
+ * By default, if no context is specified, $() looks for DOM elements within the context of the
+ * current HTML document. If you do specify a context, such as a DOM
+ * element or jQuery object, the expression will be matched against
+ * the contents of that context.
+ *
+ * See [[DOM/Traversing/Selectors]] for the allowed CSS/XPath syntax for expressions.
  *
  * @example $("div > p")
  * @desc Finds all p elements that are children of a div element.
@@ -103,10 +106,10 @@ var $ = jQuery;
 /**
  * Create DOM elements on-the-fly from the provided String of raw HTML.
  *
- * @example $("<div><p>Hello</p></div>").appendTo("#body")
+ * @example $("<div><p>Hello</p></div>").appendTo("body")
  * @desc Creates a div element (and all of its contents) dynamically, 
- * and appends it to the element with the ID of body. Internally, an
- * element is created and it's innerHTML property set to the given markup.
+ * and appends it to the body element. Internally, an
+ * element is created and its innerHTML property set to the given markup.
  * It is therefore both quite flexible and limited. 
  *
  * @name $
@@ -122,7 +125,7 @@ var $ = jQuery;
  * This function also accepts XML Documents and Window objects
  * as valid arguments (even though they are not DOM Elements).
  *
- * @example $(document.body).background( "black" );
+ * @example $(document.body).css( "background", "black" );
  * @desc Sets the background color of the page to black.
  *
  * @example $( myForm.elements ).hide()
@@ -138,8 +141,10 @@ var $ = jQuery;
  * A shorthand for $(document).ready(), allowing you to bind a function
  * to be executed when the DOM document has finished loading. This function
  * behaves just like $(document).ready(), in that it should be used to wrap
- * all of the other $() operations on your page. While this function is,
- * technically, chainable - there really isn't much use for chaining against it.
+ * other $() operations on your page that depend on the DOM being ready to be
+ * operated on. While this function is, technically, chainable - there really
+ * isn't much use for chaining against it.
+ *
  * You can have as many $(document).ready events on your page as you like.
  *
  * See ready(Function) for details about the ready event. 
@@ -176,7 +181,7 @@ jQuery.fn = jQuery.prototype = {
        jquery: "@VERSION",
 
        /**
-        * The number of elements currently matched.
+        * The number of elements currently matched. The size function will return the same value.
         *
         * @example $("img").length;
         * @before <img src="test1.jpg"/> <img src="test2.jpg"/>
@@ -189,7 +194,8 @@ jQuery.fn = jQuery.prototype = {
         */
 
        /**
-        * The number of elements currently matched.
+        * Get the number of elements currently matched. This returns the same
+        * number as the 'length' property of the jQuery object.
         *
         * @example $("img").size();
         * @before <img src="test1.jpg"/> <img src="test2.jpg"/>
@@ -206,10 +212,12 @@ jQuery.fn = jQuery.prototype = {
        length: 0,
 
        /**
-        * Access all matched elements. This serves as a backwards-compatible
+        * Access all matched DOM elements. This serves as a backwards-compatible
         * way of accessing all matched elements (other than the jQuery object
         * itself, which is, in fact, an array of elements).
         *
+        * It is useful if you need to operate on the DOM elements themselves instead of using built-in jQuery functions.
+        *
         * @example $("img").get();
         * @before <img src="test1.jpg"/> <img src="test2.jpg"/>
         * @result [ <img src="test1.jpg"/> <img src="test2.jpg"/> ]
@@ -221,12 +229,13 @@ jQuery.fn = jQuery.prototype = {
         */
 
        /**
-        * Access a single matched element. num is used to access the
-        * Nth element matched.
+        * Access a single matched DOM element at a specified index in the matched set.
+        * This allows you to extract the actual DOM element and operate on it
+        * directly without necessarily using jQuery functionality on it.
         *
         * @example $("img").get(0);
         * @before <img src="test1.jpg"/> <img src="test2.jpg"/>
-        * @result [ <img src="test1.jpg"/> ]
+        * @result <img src="test1.jpg"/>
         * @desc Selects all images in the document and returns the first one
         *
         * @name get
@@ -258,9 +267,9 @@ jQuery.fn = jQuery.prototype = {
         * @cat Core
         */
        pushStack: function( a ) {
-               var ret = jQuery(this);
+               var ret = jQuery(a);
                ret.prevObject = this;
-               return ret.setArray( a );
+               return ret;
        },
        
        /**
@@ -287,11 +296,11 @@ jQuery.fn = jQuery.prototype = {
         * Execute a function within the context of every matched element.
         * This means that every time the passed-in function is executed
         * (which is once for every element matched) the 'this' keyword
-        * points to the specific element.
+        * points to the specific DOM element.
         *
         * Additionally, the function, when executed, is passed a single
         * argument representing the position of the element in the matched
-        * set.
+        * set (integer, zero-index).
         *
         * @example $("img").each(function(i){
         *   this.src = "test" + i + ".jpg";
@@ -429,7 +438,7 @@ jQuery.fn = jQuery.prototype = {
                // Look for the case where we're accessing a style value
                if ( key.constructor == String )
                        if ( value == undefined )
-                               return jQuery[ type || "attr" ]( this[0], key );
+                               return this.length && jQuery[ type || "attr" ]( this[0], key ) || undefined;
                        else {
                                obj = {};
                                obj[ key ] = value;
@@ -804,7 +813,7 @@ jQuery.fn = jQuery.prototype = {
        find: function(t) {
                return this.pushStack( jQuery.map( this, function(a){
                        return jQuery.find(t,a);
-               }) );
+               }), t );
        },
 
        /**
@@ -825,7 +834,9 @@ jQuery.fn = jQuery.prototype = {
         */
        clone: function(deep) {
                return this.pushStack( jQuery.map( this, function(a){
-                       return a.cloneNode( deep != undefined ? deep : true );
+                       var a = a.cloneNode( deep != undefined ? deep : true );
+                       a.$events = null; // drop $events expando to avoid firing incorrect events
+                       return a;
                }) );
        },
 
@@ -928,14 +939,14 @@ jQuery.fn = jQuery.prototype = {
        not: function(t) {
                return this.pushStack(
                        t.constructor == String &&
-                       jQuery.multiFilter(t,this,true) ||
-
-                       jQuery.grep(this,function(a){
-                                       if ( t.constructor == Array || t.jquery )
-                                               return jQuery.inArray( t, a ) < 0;
-                                       else
-                                               return a != t;
-                       }) );
+                       jQuery.multiFilter(t, this, true) ||
+
+                       jQuery.grep(this, function(a) {
+                               return ( t.constructor == Array || t.jquery )
+                                       ? jQuery.inArray( a, t ) < 0
+                                       : a != t;
+                       })
+               );
        },
 
        /**
@@ -985,7 +996,10 @@ jQuery.fn = jQuery.prototype = {
        add: function(t) {
                return this.pushStack( jQuery.merge(
                        this.get(),
-                       typeof t == "string" ? jQuery(t).get() : t.length ? t : [t] )
+                       t.constructor == String ?
+                               jQuery(t).get() :
+                               t.length != undefined && (!t.nodeName || t.nodeName == "FORM") ?
+                                       t : [t] )
                );
        },
 
@@ -1098,7 +1112,7 @@ jQuery.fn = jQuery.prototype = {
                return this.each(function(){
                        var obj = this;
 
-                       if ( table && this.nodeName.toUpperCase() == "TABLE" && a[0].nodeName.toUpperCase() == "TR" )
+                       if ( table && jQuery.nodeName(this, "table") && jQuery.nodeName(a[0], "tr") )
                                obj = this.getElementsByTagName("tbody")[0] || this.appendChild(document.createElement("tbody"));
 
                        jQuery.each( a, function(){
@@ -1111,7 +1125,7 @@ jQuery.fn = jQuery.prototype = {
 
 /**
  * Extends the jQuery object itself. Can be used to add functions into
- * the jQuery namespace and to add plugin methods (plugins).
+ * the jQuery namespace and to [[Plugins/Authoring|add plugin methods]] (plugins).
  * 
  * @example jQuery.fn.extend({
  *   check: function() {
@@ -1217,10 +1231,23 @@ jQuery.extend({
        noConflict: function() {
                if ( jQuery._$ )
                        $ = jQuery._$;
+               return jQuery;
        },
 
+       // This may seem like some crazy code, but trust me when I say that this
+       // is the only cross-browser way to do this. --John
        isFunction: function( fn ) {
-               return fn && typeof fn == "function";
+               return !!fn && typeof fn != "string" && !fn.nodeName && 
+                       typeof fn[0] == "undefined" && /function/i.test( fn + "" );
+       },
+       
+       // check if an element is in a XML document
+       isXMLDoc: function(elem) {
+               return elem.tagName && elem.ownerDocument && !elem.ownerDocument.body;
+       },
+
+       nodeName: function( elem, name ) {
+               return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
        },
 
        /**
@@ -1265,16 +1292,15 @@ jQuery.extend({
        prop: function(elem, value, type, index, prop){
                        // Handle executable functions
                        if ( jQuery.isFunction( value ) )
-                               return value.call( elem, [index] );
+                               value = value.call( elem, [index] );
                                
                        // exclude the following css properties to add px
-                       var exclude = /z-?index|font-?weight|opacity/i;
+                       var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i;
 
                        // Handle passing in a number to a CSS property
-                       if ( value.constructor == Number && type == "curCSS" && !exclude.test(prop) )
-                               return value + "px";
-
-                       return value;
+                       return value && value.constructor == Number && type == "curCSS" && !exclude.test(prop) ?
+                               value + "px" :
+                               value;
        },
 
        className: {
@@ -1297,6 +1323,8 @@ jQuery.extend({
                // internal only, use is(".class")
                has: function( t, c ) {
                        t = t.className || t;
+                       // escape regex characters
+                       c = c.replace(/([\.\\\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");
                        return t && new RegExp("(^|\\s)" + c + "(\\s|$)").test( t );
                }
        },
@@ -1445,7 +1473,7 @@ jQuery.extend({
                                                tb = div.childNodes;
 
                                        for ( var n = tb.length-1; n >= 0 ; --n )
-                                               if ( tb[n].nodeName.toUpperCase() == "TBODY" && !tb[n].childNodes.length )
+                                               if ( jQuery.nodeName(tb[n], "tbody") && !tb[n].childNodes.length )
                                                        tb[n].parentNode.removeChild(tb[n]);
                                        
                                }
@@ -1453,10 +1481,10 @@ jQuery.extend({
                                arg = div.childNodes;
                        }
 
-                       if ( arg.length === 0 )
+                       if ( arg.length === 0 && !jQuery.nodeName(arg, "form") )
                                return;
                        
-                       if ( arg[0] == undefined )
+                       if ( arg[0] == undefined || jQuery.nodeName(arg, "form") )
                                r.push( arg );
                        else
                                r = jQuery.merge( r, arg );
@@ -1467,7 +1495,7 @@ jQuery.extend({
        },
        
        attr: function(elem, name, value){
-               var fix = {
+               var fix = jQuery.isXMLDoc(elem) ? {} : {
                        "for": "htmlFor",
                        "class": "className",
                        "float": jQuery.browser.msie ? "styleFloat" : "cssFloat",
@@ -1498,20 +1526,24 @@ jQuery.extend({
                // Mozilla doesn't play well with opacity 1
                if ( name == "opacity" && jQuery.browser.mozilla && value == 1 )
                        value = 0.9999;
+                       
 
                // 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 ( value == undefined && jQuery.browser.msie && elem.nodeName && elem.nodeName.toUpperCase() == "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 ) {
                        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;