Added support for breaking in an object loop (Bug #2111).
[jquery.git] / src / core.js
index b3b0a9d..8bec2c7 100644 (file)
  */\r
 \r
 // Map over jQuery in case of overwrite\r
-if ( typeof jQuery != "undefined" )\r
-       var _jQuery = jQuery;\r
+if ( window.jQuery )\r
+       var _jQuery = window.jQuery;\r
 \r
 var jQuery = window.jQuery = function( selector, context ) {\r
-       // If the context is a namespace object, return a new object\r
-       return this instanceof jQuery ?\r
-               this.init( selector, context ) :\r
-               new jQuery( selector, context );\r
+       // The jQuery object is actually just the init constructor 'enhanced'\r
+       return new jQuery.prototype.init( selector, context );\r
 };\r
 \r
 // Map over the $ in case of overwrite\r
-if ( typeof $ != "undefined" )\r
-       var _$ = $;\r
+if ( window.$ )\r
+       var _$ = window.$;\r
        \r
 // Map the jQuery namespace to the '$' one\r
 window.$ = jQuery;\r
@@ -31,13 +29,22 @@ window.$ = jQuery;
 // (both of which we optimize for)\r
 var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/;\r
 \r
+// Is it a simple selector\r
+var isSimple = /^.[^:#\[\.]*$/;\r
+\r
 jQuery.fn = jQuery.prototype = {\r
        init: function( selector, context ) {\r
                // Make sure that a selection was provided\r
                selector = selector || document;\r
 \r
+               // Handle $(DOMElement)\r
+               if ( selector.nodeType ) {\r
+                       this[0] = selector;\r
+                       this.length = 1;\r
+                       return this;\r
+\r
                // Handle HTML strings\r
-               if ( typeof selector  == "string" ) {\r
+               } else if ( typeof selector == "string" ) {\r
                        // Are we dealing with HTML string or an ID?\r
                        var match = quickExpr.exec( selector );\r
 \r
@@ -188,12 +195,15 @@ jQuery.fn = jQuery.prototype = {
        },\r
 \r
        css: function( key, value ) {\r
+               // ignore negative width and height values\r
+               if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 )\r
+                       value = undefined;\r
                return this.attr( key, value, "curCSS" );\r
        },\r
 \r
        text: function( text ) {\r
                if ( typeof text != "object" && text != null )\r
-                       return this.empty().append( document.createTextNode( text ) );\r
+                       return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );\r
 \r
                var ret = "";\r
 \r
@@ -242,13 +252,15 @@ jQuery.fn = jQuery.prototype = {
 \r
        append: function() {\r
                return this.domManip(arguments, true, false, function(elem){\r
-                       this.appendChild( elem );\r
+                       if (this.nodeType == 1)\r
+                               this.appendChild( elem );\r
                });\r
        },\r
 \r
        prepend: function() {\r
                return this.domManip(arguments, true, true, function(elem){\r
-                       this.insertBefore( elem, this.firstChild );\r
+                       if (this.nodeType == 1)\r
+                               this.insertBefore( elem, this.firstChild );\r
                });\r
        },\r
        \r
@@ -281,9 +293,23 @@ jQuery.fn = jQuery.prototype = {
        clone: function( events ) {\r
                // Do the clone\r
                var ret = this.map(function(){\r
-                       return this.outerHTML ?\r
-                               jQuery( this.outerHTML )[0] :\r
-                               this.cloneNode( true );\r
+                       if ( jQuery.browser.msie && !jQuery.isXMLDoc(this) ) {\r
+                               // IE copies events bound via attachEvent when\r
+                               // using cloneNode. Calling detachEvent on the\r
+                               // clone will also remove the events from the orignal\r
+                               // In order to get around this, we use innerHTML.\r
+                               // Unfortunately, this means some modifications to \r
+                               // attributes in IE that are actually only stored \r
+                               // as properties will not be copied (such as the\r
+                               // the name attribute on an input).\r
+                               var clone = this.cloneNode(true),\r
+                                       container = document.createElement("div"),\r
+                                       container2 = document.createElement("div");\r
+                               container.appendChild(clone);\r
+                               container2.innerHTML = container.innerHTML;\r
+                               return container2.firstChild;\r
+                       } else\r
+                               return this.cloneNode(true);\r
                });\r
 \r
                // Need to set the expando to null on the cloned set if it exists\r
@@ -297,6 +323,8 @@ jQuery.fn = jQuery.prototype = {
                // Copy the events from the original to the clone\r
                if ( events === true )\r
                        this.find("*").andSelf().each(function(i){\r
+                               if (this.nodeType == 3)\r
+                                       return;\r
                                var events = jQuery.data( this, "events" );\r
 \r
                                for ( var type in events )\r
@@ -319,19 +347,21 @@ jQuery.fn = jQuery.prototype = {
        },\r
 \r
        not: function( selector ) {\r
-               return this.pushStack(\r
-                       selector.constructor == String &&\r
-                       jQuery.multiFilter( selector, this, true ) ||\r
-\r
-                       jQuery.grep(this, function(elem) {\r
-                               return selector.constructor == Array || selector.jquery ?\r
-                                       jQuery.inArray( elem, selector ) < 0 :\r
-                                       elem != selector;\r
-                       }) );\r
+               if ( selector.constructor == String )\r
+                       // test special case where just one selector is passed in\r
+                       if ( isSimple.test( selector ) )\r
+                               return this.pushStack( jQuery.multiFilter( selector, this, true ) );\r
+                       else\r
+                               selector = jQuery.multiFilter( selector, this );\r
+\r
+               var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType;\r
+               return this.filter(function() {\r
+                       return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector;\r
+               });\r
        },\r
 \r
        add: function( selector ) {\r
-               return this.pushStack( jQuery.merge( \r
+               return !selector ? this : this.pushStack( jQuery.merge( \r
                        this.get(),\r
                        selector.constructor == String ? \r
                                jQuery( selector ).get() :\r
@@ -354,7 +384,7 @@ jQuery.fn = jQuery.prototype = {
 \r
                        if ( this.length ) {\r
                                var elem = this[0];\r
-                       \r
+\r
                                // We need to handle select boxes special\r
                                if ( jQuery.nodeName( elem, "select" ) ) {\r
                                        var index = elem.selectedIndex,\r
@@ -387,32 +417,37 @@ jQuery.fn = jQuery.prototype = {
                                        \r
                                // Everything else, we just grab the value\r
                                } else\r
-                                       return this[0].value.replace(/\r/g, "");\r
+                                       return (this[0].value || "").replace(/\r/g, "");\r
 \r
                        }\r
 \r
-               } else\r
-                       return this.each(function(){\r
-                               if ( value.constructor == Array && /radio|checkbox/.test( this.type ) )\r
-                                       this.checked = (jQuery.inArray(this.value, value) >= 0 ||\r
-                                               jQuery.inArray(this.name, value) >= 0);\r
+                       return undefined;\r
+               }\r
 \r
-                               else if ( jQuery.nodeName( this, "select" ) ) {\r
-                                       var values = value.constructor == Array ?\r
-                                               value :\r
-                                               [ value ];\r
+               return this.each(function(){\r
+                       if ( this.nodeType != 1 )\r
+                               return;\r
 \r
-                                       jQuery( "option", this ).each(function(){\r
-                                               this.selected = (jQuery.inArray( this.value, values ) >= 0 ||\r
-                                                       jQuery.inArray( this.text, values ) >= 0);\r
-                                       });\r
+                       if ( value.constructor == Array && /radio|checkbox/.test( this.type ) )\r
+                               this.checked = (jQuery.inArray(this.value, value) >= 0 ||\r
+                                       jQuery.inArray(this.name, value) >= 0);\r
 \r
-                                       if ( !values.length )\r
-                                               this.selectedIndex = -1;\r
+                       else if ( jQuery.nodeName( this, "select" ) ) {\r
+                               var values = value.constructor == Array ?\r
+                                       value :\r
+                                       [ value ];\r
 \r
-                               } else\r
-                                       this.value = value;\r
-                       });\r
+                               jQuery( "option", this ).each(function(){\r
+                                       this.selected = (jQuery.inArray( this.value, values ) >= 0 ||\r
+                                               jQuery.inArray( this.text, values ) >= 0);\r
+                               });\r
+\r
+                               if ( !values.length )\r
+                                       this.selectedIndex = -1;\r
+\r
+                       } else\r
+                               this.value = value;\r
+               });\r
        },\r
        \r
        html: function( value ) {\r
@@ -459,41 +494,49 @@ jQuery.fn = jQuery.prototype = {
                        var obj = this;\r
 \r
                        if ( table && jQuery.nodeName( this, "table" ) && jQuery.nodeName( elems[0], "tr" ) )\r
-                               obj = this.getElementsByTagName("tbody")[0] || this.appendChild( document.createElement("tbody") );\r
+                               obj = this.getElementsByTagName("tbody")[0] || this.appendChild( this.ownerDocument.createElement("tbody") );\r
+\r
+                       var scripts = jQuery( [] );\r
 \r
                        jQuery.each(elems, function(){\r
                                var elem = clone ?\r
-                                       this.cloneNode( true ) :\r
+                                       jQuery( this ).clone( true )[0] :\r
                                        this;\r
 \r
-                               if ( !evalScript( 0, elem ) )\r
+                               // execute all scripts after the elements have been injected\r
+                               if ( jQuery.nodeName( elem, "script" ) ) {\r
+                                       scripts = scripts.add( elem );\r
+                               } else {\r
+                                       // Remove any inner scripts for later evaluation\r
+                                       if ( elem.nodeType == 1 )\r
+                                               scripts = scripts.add( jQuery( "script", elem ).remove() );\r
+\r
+                                       // Inject the elements into the document\r
                                        callback.call( obj, elem );\r
+                               }\r
                        });\r
+\r
+                       scripts.each( evalScript );\r
                });\r
        }\r
 };\r
 \r
-function evalScript( i, elem ) {\r
-       var script = jQuery.nodeName( elem, "script" );\r
-\r
-       if ( script ) {\r
-               if ( elem.src )\r
-                       jQuery.ajax({\r
-                               url: elem.src,\r
-                               async: false,\r
-                               dataType: "script"\r
-                       });\r
+// Give the init function the jQuery prototype for later instantiation\r
+jQuery.prototype.init.prototype = jQuery.prototype;\r
 \r
-               else\r
-                       jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );\r
-       \r
-               if ( elem.parentNode )\r
-                       elem.parentNode.removeChild( elem );\r
+function evalScript( i, elem ) {\r
+       if ( elem.src )\r
+               jQuery.ajax({\r
+                       url: elem.src,\r
+                       async: false,\r
+                       dataType: "script"\r
+               });\r
 \r
-       } else if ( elem.nodeType == 1 )\r
-               jQuery( "script", elem ).each( evalScript );\r
+       else\r
+               jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );\r
 \r
-       return script;\r
+       if ( elem.parentNode )\r
+               elem.parentNode.removeChild( elem );\r
 }\r
 \r
 jQuery.extend = jQuery.fn.extend = function() {\r
@@ -504,8 +547,14 @@ jQuery.extend = jQuery.fn.extend = function() {
        if ( target.constructor == Boolean ) {\r
                deep = target;\r
                target = arguments[1] || {};\r
+               // skip the boolean and the target\r
+               i = 2;\r
        }\r
 \r
+       // Handle case when target is a string or something (possible in deep copy)\r
+       if ( typeof target != "object" && typeof target != "function" )\r
+               target = {};\r
+\r
        // extend jQuery itself if only one argument is passed\r
        if ( length == 1 ) {\r
                target = this;\r
@@ -518,12 +567,12 @@ jQuery.extend = jQuery.fn.extend = function() {
                        // Extend the base object\r
                        for ( var name in options ) {\r
                                // Prevent never-ending loop\r
-                               if ( target == options[ name ] )\r
+                               if ( target === options[ name ] )\r
                                        continue;\r
 \r
                                // Recurse if we're merging object values\r
-                               if ( deep && typeof options[ name ] == "object" && target[ name ] )\r
-                                       jQuery.extend( target[ name ], options[ name ] );\r
+                               if ( deep && options[ name ] && typeof options[ name ] == "object" && target[ name ] && !options[ name ].nodeType )\r
+                                       target[ name ] = jQuery.extend( target[ name ], options[ name ] );\r
 \r
                                // Don't bring in undefined values\r
                                else if ( options[ name ] != undefined )\r
@@ -550,8 +599,7 @@ jQuery.extend({
                return jQuery;\r
        },\r
 \r
-       // This may seem like some crazy code, but trust me when I say that this\r
-       // is the only cross-browser way to do this. --John\r
+       // See test/unit/core.js for details concerning this function.\r
        isFunction: function( fn ) {\r
                return !!fn && typeof fn != "string" && !fn.nodeName && \r
                        fn.constructor != Array && /function/i.test( fn + "" );\r
@@ -564,7 +612,6 @@ jQuery.extend({
        },\r
 \r
        // Evalulates a script in a global context\r
-       // Evaluates Async. in Safari 2 :-(\r
        globalEval: function( data ) {\r
                data = jQuery.trim( data );\r
 \r
@@ -660,20 +707,22 @@ jQuery.extend({
        // args is for internal usage only\r
        each: function( object, callback, args ) {\r
                if ( args ) {\r
-                       if ( object.length == undefined )\r
+                       if ( object.length == undefined ) {\r
                                for ( var name in object )\r
-                                       callback.apply( object[ name ], args );\r
-                       else\r
+                                       if ( callback.apply( object[ name ], args ) === false )\r
+                                               break;\r
+                       } else\r
                                for ( var i = 0, length = object.length; i < length; i++ )\r
                                        if ( callback.apply( object[ i ], args ) === false )\r
                                                break;\r
 \r
                // A special, fast, case for the most common use of each\r
                } else {\r
-                       if ( object.length == undefined )\r
+                       if ( object.length == undefined ) {\r
                                for ( var name in object )\r
-                                       callback.call( object[ name ], name, object[ name ] );\r
-                       else\r
+                                       if ( callback.call( object[ name ], name, object[ name ] ) === false )\r
+                                               break;\r
+                       } else\r
                                for ( var i = 0, length = object.length, value = object[0]; \r
                                        i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}\r
                }\r
@@ -696,18 +745,19 @@ jQuery.extend({
                // internal only, use addClass("class")\r
                add: function( elem, classNames ) {\r
                        jQuery.each((classNames || "").split(/\s+/), function(i, className){\r
-                               if ( !jQuery.className.has( elem.className, className ) )\r
+                               if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) )\r
                                        elem.className += (elem.className ? " " : "") + className;\r
                        });\r
                },\r
 \r
                // internal only, use removeClass("class")\r
                remove: function( elem, classNames ) {\r
-                       elem.className = classNames != undefined ?\r
-                               jQuery.grep(elem.className.split(/\s+/), function(className){\r
-                                       return !jQuery.className.has( classNames, className );  \r
-                               }).join(" ") :\r
-                               "";\r
+                       if (elem.nodeType == 1)\r
+                               elem.className = classNames != undefined ?\r
+                                       jQuery.grep(elem.className.split(/\s+/), function(className){\r
+                                               return !jQuery.className.has( classNames, className );  \r
+                                       }).join(" ") :\r
+                                       "";\r
                },\r
 \r
                // internal only, use is(".class")\r
@@ -718,9 +768,10 @@ jQuery.extend({
 \r
        // A method for quickly swapping in/out CSS properties to get correct calculations\r
        swap: function( elem, options, callback ) {\r
+               var old = {};\r
                // Remember the old values, and insert the new ones\r
                for ( var name in options ) {\r
-                       elem.style[ "old" + name ] = elem.style[ name ];\r
+                       old[ name ] = elem.style[ name ];\r
                        elem.style[ name ] = options[ name ];\r
                }\r
 \r
@@ -728,60 +779,32 @@ jQuery.extend({
 \r
                // Revert the old values\r
                for ( var name in options )\r
-                       elem.style[ name ] = elem.style[ "old" + name ];\r
+                       elem.style[ name ] = old[ name ];\r
        },\r
 \r
-       css: function( elem, name ) {\r
-               if ( name == "height" || name == "width" ) {\r
-                       var old = {}, height, width;\r
-\r
-                       // Revert the padding and border widths to get the\r
-                       // correct height/width values\r
-                       jQuery.each([ "Top", "Bottom", "Right", "Left" ], function(){\r
-                               old[ "padding" + this ] = 0;\r
-                               old[ "border" + this + "Width" ] = 0;\r
-                       });\r
-\r
-                       // Swap out the padding/border values temporarily\r
-                       jQuery.swap( elem, old, function() {\r
-\r
-                               // If the element is visible, then the calculation is easy\r
-                               if ( jQuery( elem ).is(":visible") ) {\r
-                                       height = elem.offsetHeight;\r
-                                       width = elem.offsetWidth;\r
-\r
-                               // Otherwise, we need to flip out more values\r
-                               } else {\r
-                                       elem = jQuery( elem.cloneNode(true) )\r
-                                               .find(":radio").removeAttr("checked").end()\r
-                                               .css({\r
-                                                       visibility: "hidden",\r
-                                                       position: "absolute",\r
-                                                       display: "block",\r
-                                                       right: "0",\r
-                                                       left: "0"\r
-                                               }).appendTo( elem.parentNode )[0];\r
-\r
-                                       var position = jQuery.css( elem.parentNode, "position" ) || "static";\r
-                                       if ( position == "static" )\r
-                                               elem.parentNode.style.position = "relative";\r
-\r
-                                       height = elem.clientHeight;\r
-                                       width = elem.clientWidth;\r
-\r
-                                       if ( position == "static" )\r
-                                               elem.parentNode.style.position = "static";\r
-\r
-                                       elem.parentNode.removeChild( elem );\r
-                               }\r
-                       });\r
-\r
-                       return name == "height" ?\r
-                               height :\r
-                               width;\r
+       css: function( elem, name, force ) {\r
+               if ( name == "width" || name == "height" ) {\r
+                       var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];\r
+               \r
+                       function getWH() {\r
+                               val = name == "width" ? elem.offsetWidth : elem.offsetHeight;\r
+                               var padding = 0, border = 0;\r
+                               jQuery.each( which, function() {\r
+                                       padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;\r
+                                       border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;\r
+                               });\r
+                               val -= Math.round(padding + border);\r
+                       }\r
+               \r
+                       if ( jQuery(elem).is(":visible") )\r
+                               getWH();\r
+                       else\r
+                               jQuery.swap( elem, props, getWH );\r
+                       \r
+                       return Math.max(0, val);\r
                }\r
-\r
-               return jQuery.curCSS( elem, name );\r
+               \r
+               return jQuery.curCSS( elem, name, force );\r
        },\r
 \r
        curCSS: function( elem, name, force ) {\r
@@ -804,12 +827,18 @@ jQuery.extend({
                                "1" :\r
                                ret;\r
                }\r
+               // Opera sometimes will give the wrong display answer, this fixes it, see #2037\r
+               if ( jQuery.browser.opera && name == "display" ) {\r
+                       var save = elem.style.display;\r
+                       elem.style.display = "block";\r
+                       elem.style.display = save;\r
+               }\r
                \r
                // Make sure we're using the right name for getting the float value\r
                if ( name.match( /float/i ) )\r
                        name = styleFloat;\r
 \r
-               if ( !force && elem.style[ name ] )\r
+               if ( !force && elem.style && elem.style[ name ] )\r
                        ret = elem.style[ name ];\r
 \r
                else if ( document.defaultView && document.defaultView.getComputedStyle ) {\r
@@ -891,6 +920,9 @@ jQuery.extend({
        clean: function( elems, context ) {\r
                var ret = [];\r
                context = context || document;\r
+               // !context.createElement fails in IE with an error but returns typeof 'object'\r
+               if (typeof context.createElement == 'undefined') \r
+                       context = context.ownerDocument || context[0] && context[0].ownerDocument || document;\r
 \r
                jQuery.each(elems, function(i, elem){\r
                        if ( !elem )\r
@@ -903,7 +935,7 @@ jQuery.extend({
                        if ( typeof elem == "string" ) {\r
                                // Fix "XHTML"-style tags in all browsers\r
                                elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){\r
-                                       return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area)$/i) ?\r
+                                       return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?\r
                                                all :\r
                                                front + "></" + tag + ">";\r
                                });\r
@@ -914,7 +946,7 @@ jQuery.extend({
                                var wrap =\r
                                        // option or optgroup\r
                                        !tags.indexOf("<opt") &&\r
-                                       [ 1, "<select>", "</select>" ] ||\r
+                                       [ 1, "<select multiple='multiple'>", "</select>" ] ||\r
                                        \r
                                        !tags.indexOf("<leg") &&\r
                                        [ 1, "<fieldset>", "</fieldset>" ] ||\r
@@ -957,9 +989,9 @@ jQuery.extend({
                                                        div.childNodes :\r
                                                        [];\r
                                \r
-                                       for ( var i = tbody.length - 1; i >= 0 ; --i )\r
-                                               if ( jQuery.nodeName( tbody[ i ], "tbody" ) && !tbody[ i ].childNodes.length )\r
-                                                       tbody[ i ].parentNode.removeChild( tbody[ i ] );\r
+                                       for ( var j = tbody.length - 1; j >= 0 ; --j )\r
+                                               if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length )\r
+                                                       tbody[ j ].parentNode.removeChild( tbody[ j ] );\r
                                        \r
                                        // IE completely kills leading whitespace when innerHTML is used        \r
                                        if ( /^\s/.test( elem ) )       \r
@@ -985,6 +1017,10 @@ jQuery.extend({
        },\r
        \r
        attr: function( elem, name, value ) {\r
+               // don't set attributes on text and comment nodes\r
+               if (!elem || elem.nodeType == 3 || elem.nodeType == 8)\r
+                       return undefined;\r
+\r
                var fix = jQuery.isXMLDoc( elem ) ?\r
                        {} :\r
                        jQuery.props;\r
@@ -1015,7 +1051,8 @@ jQuery.extend({
                                if ( name == "type" && jQuery.nodeName( elem, "input" ) && elem.parentNode )\r
                                        throw "type property can't be changed";\r
 \r
-                               elem.setAttribute( name, value );\r
+                               // convert the value to a string (all browsers do this but IE) see #1070\r
+                               elem.setAttribute( name, "" + value );\r
                        }\r
 \r
                        if ( jQuery.browser.msie && /href|src/.test( name ) && !jQuery.isXMLDoc( elem ) ) \r
@@ -1037,7 +1074,7 @@ jQuery.extend({
                                                (parseFloat( value ).toString() == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")");\r
                                }\r
        \r
-                               return elem.filter ? \r
+                               return elem.filter && elem.filter.indexOf("opacity=") >= 0 ?\r
                                        (parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100).toString() :\r
                                        "";\r
                        }\r
@@ -1187,7 +1224,10 @@ jQuery.extend({
                readonly: "readOnly",\r
                selected: "selected",\r
                maxlength: "maxLength",\r
-               selectedIndex: "selectedIndex"\r
+               selectedIndex: "selectedIndex",\r
+               defaultValue: "defaultValue",\r
+               tagName: "tagName",\r
+               nodeName: "nodeName"\r
        }\r
 });\r
 \r
@@ -1234,7 +1274,8 @@ jQuery.each({
 jQuery.each({\r
        removeAttr: function( name ) {\r
                jQuery.attr( this, name, "" );\r
-               this.removeAttribute( name );\r
+               if (this.nodeType == 1) \r
+                       this.removeAttribute( name );\r
        },\r
 \r
        addClass: function( classNames ) {\r
@@ -1256,7 +1297,8 @@ jQuery.each({
                                jQuery.event.remove(this);\r
                                jQuery.removeData(this);\r
                        });\r
-                       this.parentNode.removeChild( this );\r
+                       if (this.parentNode)\r
+                               this.parentNode.removeChild( this );\r
                }\r
        },\r
 \r
@@ -1284,16 +1326,19 @@ jQuery.each([ "Height", "Width" ], function(i, name){
                        jQuery.browser.opera && document.body[ "client" + name ] || \r
                        \r
                        // Safari reports inner[Width/Height] just fine (Mozilla and Opera include scroll bar widths)\r
-                       jQuery.browser.safari && self[ "inner" + name ] ||\r
+                       jQuery.browser.safari && window[ "inner" + name ] ||\r
                        \r
                        // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode\r
                        document.compatMode == "CSS1Compat" && document.documentElement[ "client" + name ] || document.body[ "client" + name ] :\r
                \r
                        // Get document width or height\r
                        this[0] == document ?\r
-                               // Either scroll[Width/Height] or offset[Width/Height], whichever is greater (Mozilla reports scrollWidth the same as offsetWidth)\r
-                               Math.max( document.body[ "scroll" + name ], document.body[ "offset" + name ] ) :\r
-        \r
+                               // Either scroll[Width/Height] or offset[Width/Height], whichever is greater\r
+                               Math.max( \r
+                                       Math.max(document.body["scroll" + name], document.documentElement["scroll" + name]), \r
+                                       Math.max(document.body["offset" + name], document.documentElement["offset" + name]) \r
+                               ) :\r
+\r
                                // Get or set width or height on the element\r
                                size == undefined ?\r
                                        // Get width or height on the element\r