Merge in data_nocollide branch. Fixes #6968, improves unit testing framework checks...
authorColin Snover <github.com@zetafleet.com>
Mon, 17 Jan 2011 21:31:43 +0000 (15:31 -0600)
committerColin Snover <github.com@zetafleet.com>
Mon, 17 Jan 2011 21:31:43 +0000 (15:31 -0600)
1  2 
src/event.js
src/manipulation.js
test/unit/ajax.js
test/unit/core.js
test/unit/css.js
test/unit/event.js
test/unit/manipulation.js

diff --combined src/event.js
@@@ -8,7 -8,8 +8,8 @@@ var rnamespaces = /\.(.*)$/
        fcleanup = function( nm ) {
                return nm.replace(rescape, "\\$&");
        },
-       focusCounts = { focusin: 0, focusout: 0 };
+       focusCounts = { focusin: 0, focusout: 0 },
+       eventKey = "events";
  
  /*
   * A number of helper functions used for managing events.
@@@ -50,7 -51,7 +51,7 @@@ jQuery.event = 
                }
  
                // Init the element's event structure
-               var elemData = jQuery.data( elem );
+               var elemData = jQuery._data( elem );
  
                // If no elemData is found then we must be trying to bind to one of the
                // banned noData elements
                        return;
                }
  
-               // Use a key less likely to result in collisions for plain JS objects.
-               // Fixes bug #7150.
-               var eventKey = elem.nodeType ? "events" : "__events__",
-                       events = elemData[ eventKey ],
+               var events = elemData[ eventKey ],
                        eventHandle = elemData.handle;
  
                if ( typeof events === "function" ) {
                }
  
                var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
-                       eventKey = elem.nodeType ? "events" : "__events__",
-                       elemData = jQuery.data( elem ),
+                       elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
                        events = elemData && elemData[ eventKey ];
  
                if ( !elemData || !events ) {
                        delete elemData.handle;
  
                        if ( typeof elemData === "function" ) {
-                               jQuery.removeData( elem, eventKey );
+                               jQuery.removeData( elem, eventKey, true );
  
                        } else if ( jQuery.isEmptyObject( elemData ) ) {
-                               jQuery.removeData( elem );
+                               jQuery.removeData( elem, undefined, true );
                        }
                }
        },
  
                                // Only trigger if we've ever bound an event for it
                                if ( jQuery.event.global[ type ] ) {
+                                       // XXX This code smells terrible. event.js should not be directly
+                                       // inspecting the data cache
                                        jQuery.each( jQuery.cache, function() {
-                                               if ( this.events && this.events[type] ) {
-                                                       jQuery.event.trigger( event, data, this.handle.elem );
+                                               // internalKey variable is just used to make it easier to find
+                                               // and potentially change this stuff later; currently it just
+                                               // points to jQuery.expando
+                                               var internalKey = jQuery.expando,
+                                                       internalCache = this[ internalKey ];
+                                               if ( internalCache && internalCache.events && internalCache.events[type] ) {
+                                                       jQuery.event.trigger( event, data, internalCache.handle.elem );
                                                }
                                        });
                                }
  
                // Trigger the event, it is assumed that "handle" is a function
                var handle = elem.nodeType ?
-                       jQuery.data( elem, "handle" ) :
-                       (jQuery.data( elem, "__events__" ) || {}).handle;
+                       jQuery._data( elem, "handle" ) :
+                       (jQuery._data( elem, eventKey ) || {}).handle;
  
                if ( handle ) {
                        handle.apply( elem, data );
  
                event.namespace = event.namespace || namespace_sort.join(".");
  
-               events = jQuery.data(this, this.nodeType ? "events" : "__events__");
+               events = jQuery._data(this, eventKey);
  
                if ( typeof events === "function" ) {
                        events = events.events;
@@@ -603,7 -607,7 +607,7 @@@ jQuery.Event = function( src ) 
  
                // Events bubbling up the document may have been marked as prevented
                // by a handler lower down the tree; reflect the correct value.
 -              this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
 +              this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false || 
                        src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;
  
        // Event type
@@@ -787,12 -791,12 +791,12 @@@ if ( !jQuery.support.changeBubbles ) 
                        return;
                }
  
-               data = jQuery.data( elem, "_change_data" );
+               data = jQuery._data( elem, "_change_data" );
                val = getVal(elem);
  
                // the current data will be also retrieved by beforeactivate
                if ( e.type !== "focusout" || elem.type !== "radio" ) {
-                       jQuery.data( elem, "_change_data", val );
+                       jQuery._data( elem, "_change_data", val );
                }
  
                if ( data === undefined || val === data ) {
                        // information
                        beforeactivate: function( e ) {
                                var elem = e.target;
-                               jQuery.data( elem, "_change_data", getVal(elem) );
+                               jQuery._data( elem, "_change_data", getVal(elem) );
                        }
                },
  
@@@ -986,8 -990,8 +990,8 @@@ jQuery.fn.extend(
  
                return this.click( jQuery.proxy( fn, function( event ) {
                        // Figure out which function to execute
-                       var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
-                       jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+                       var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+                       jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
  
                        // Make sure that clicks stop
                        event.preventDefault();
@@@ -1075,7 -1079,7 +1079,7 @@@ function liveHandler( event ) 
        var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
                elems = [],
                selectors = [],
-               events = jQuery.data( this, this.nodeType ? "events" : "__events__" );
+               events = jQuery._data( this, eventKey );
  
        if ( typeof events === "function" ) {
                events = events.events;
diff --combined src/manipulation.js
@@@ -346,7 -346,7 +346,7 @@@ jQuery.fn.extend(
                                                table ?
                                                        root(this[i], first) :
                                                        this[i],
-                                               i > 0 || results.cacheable || this.length > 1  ?
+                                               i > 0 || results.cacheable || (this.length > 1 && i > 0) ?
                                                        jQuery(fragment).clone(true)[0] :
                                                        fragment
                                        );
@@@ -381,17 -381,24 +381,24 @@@ function cloneCopyEvent(orig, ret) 
                        throw "Cloned data mismatch";
                }
  
-               var oldData = jQuery.data( orig[nodeIndex] ),
-                       curData = jQuery.data( this, oldData ),
-                       events = oldData && oldData.events;
+               var internalKey = jQuery.expando,
+                       oldData = jQuery.data( orig[nodeIndex] ),
+                       curData = jQuery.data( this, oldData );
  
-               if ( events ) {
-                       delete curData.handle;
-                       curData.events = {};
+               // Switch to use the internal data object, if it exists, for the next
+               // stage of data copying
+               if ( (oldData = oldData[ internalKey ]) ) {
+                       var events = oldData.events;
+                       curData = curData[ internalKey ] = jQuery.extend({}, oldData);
  
-                       for ( var type in events ) {
-                               for ( var i = 0, l = events[ type ].length; i < l; i++ ) {
-                                       jQuery.event.add( this, type, events[ type ][ i ], events[ type ][ i ].data );
+                       if ( events ) {
+                               delete curData.handle;
+                               curData.events = {};
+                               for ( var type in events ) {
+                                       for ( var i = 0, l = events[ type ].length; i < l; i++ ) {
+                                               jQuery.event.add( this, type, events[ type ][ i ], events[ type ][ i ].data );
+                                       }
                                }
                        }
                }
@@@ -420,29 -427,15 +427,29 @@@ function cloneFixAttributes(src, dest) 
        if ( nodeName === "object" ) {
                dest.outerHTML = src.outerHTML;
  
 -      // IE6-8 fails to persist the checked state of a cloned checkbox
 -      // or radio button
 -      } else if ( nodeName === "input" && src.checked ) {
 -              dest.defaultChecked = dest.checked = src.checked;
 +      } else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
 +              // IE6-8 fails to persist the checked state of a cloned checkbox
 +              // or radio button. Worse, IE6-7 fail to give the cloned element
 +              // a checked appearance if the defaultChecked value isn't also set
 +              if ( src.checked ) {
 +                      dest.defaultChecked = dest.checked = src.checked;
 +              }
 +
 +              // IE6-7 get confused and end up setting the value of a cloned
 +              // checkbox/radio button to an empty string instead of "on"
 +              if ( dest.value !== src.value ) {
 +                      dest.value = src.value;
 +              }
  
        // IE6-8 fails to return the selected option to the default selected
        // state when cloning options
        } else if ( nodeName === "option" ) {
                dest.selected = src.defaultSelected;
 +
 +      // IE6-8 fails to set the defaultValue to the correct value when
 +      // cloning other types of input fields
 +      } else if ( nodeName === "input" || nodeName === "textarea" ) {
 +              dest.defaultValue = src.defaultValue;
        }
  
        // Event data gets referenced instead of copied if the expando
@@@ -608,8 -601,7 +615,7 @@@ jQuery.extend(
        },
  
        cleanData: function( elems ) {
-               var data, id, cache = jQuery.cache,
-                       special = jQuery.event.special,
+               var data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special,
                        deleteExpando = jQuery.support.deleteExpando;
  
                for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
                        id = elem[ jQuery.expando ];
  
                        if ( id ) {
-                               data = cache[ id ];
+                               data = cache[ id ] && cache[ id ][ internalKey ];
  
                                if ( data && data.events ) {
                                        for ( var type in data.events ) {
                                                if ( special[ type ] ) {
                                                        jQuery.event.remove( elem, type );
  
+                                               // This is a shortcut to avoid jQuery.event.remove's overhead
                                                } else {
                                                        jQuery.removeEvent( elem, type, data.handle );
                                                }
                                        }
 +
 +                                      // Null the DOM reference to avoid IE6/7/8 leak (#7054)
 +                                      if ( data.handle ) {
 +                                              data.handle.elem = null;
 +                                      }
                                }
  
                                if ( deleteExpando ) {
diff --combined test/unit/ajax.js
@@@ -1,4 -1,4 +1,4 @@@
- module("ajax");
+ module("ajax", { teardown: moduleTeardown });
  
  // Safari 3 randomly crashes when running these tests,
  // but only in the full suite - you can run just the Ajax
@@@ -276,7 -276,7 +276,7 @@@ test(".ajax() - retry with jQuery.ajax
                                start();
                        }
                }
 -      })
 +      });
  
  });
  
@@@ -316,28 -316,6 +316,28 @@@ test(".ajax() - headers" , function() 
  
  });
  
 +test(".ajax() - Accept header" , function() {
 +
 +      expect( 1 );
 +
 +      stop();
 +
 +      jQuery.ajax(url("data/headers.php?keys=accept"), {
 +              headers: {
 +                      Accept: "very wrong accept value"
 +              },
 +              beforeSend: function( xhr ) {
 +                      xhr.setRequestHeader( "Accept", "*/*" );
 +              },
 +              success: function( data ) {
 +                      strictEqual( data , "accept: */*\n" , "Test Accept header is set to last value provided" );
 +                      start();
 +              },
 +              error: function(){ ok(false, "error"); }
 +      });
 +
 +});
 +
  test(".ajax() - contentType" , function() {
  
        expect( 2 );
@@@ -1047,18 -1025,6 +1047,18 @@@ test("load(String, Function) - check fi
        });
  });
  
 +test("load(String, Function) - dataFilter in ajaxSettings", function() {
 +      expect(2);
 +      stop();
 +      jQuery.ajaxSetup({ dataFilter: function() { return "Hello World"; } });
 +      var div = jQuery("<div/>").load(url("data/name.html"), function(responseText) {
 +              strictEqual( div.html(), "Hello World" , "Test div was filled with filtered data" );
 +              strictEqual( responseText, "Hello World" , "Test callback receives filtered data" );
 +              jQuery.ajaxSetup({ dataFilter: 0 });
 +              start();
 +      });
 +});
 +
  test("load(String, Object, Function)", function() {
        expect(2);
        stop();
@@@ -1114,249 -1080,233 +1114,249 @@@ test("jQuery.getScript(String, Function
        });
  });
  
 -test("jQuery.ajax() - JSONP, Local", function() {
 -      expect(10);
 -
 -      var count = 0;
 -      function plus(){ if ( ++count == 9 ) start(); }
 -
 -      stop();
 -
 -      jQuery.ajax({
 -              url: "data/jsonp.php",
 -              dataType: "jsonp",
 -              success: function(data){
 -                      ok( data.data, "JSON results returned (GET, no callback)" );
 -                      plus();
 -              },
 -              error: function(data){
 -                      ok( false, "Ajax error JSON (GET, no callback)" );
 -                      plus();
 -              }
 -      });
 +jQuery.each( [ "Same Domain", "Cross Domain" ] , function( crossDomain , label ) {
  
 -      jQuery.ajax({
 -              url: "data/jsonp.php?callback=?",
 -              dataType: "jsonp",
 -              success: function(data){
 -                      ok( data.data, "JSON results returned (GET, url callback)" );
 -                      plus();
 -              },
 -              error: function(data){
 -                      ok( false, "Ajax error JSON (GET, url callback)" );
 -                      plus();
 -              }
 -      });
 +      test("jQuery.ajax() - JSONP, " + label, function() {
 +              expect(17);
  
 -      jQuery.ajax({
 -              url: "data/jsonp.php",
 -              dataType: "jsonp",
 -              data: "callback=?",
 -              success: function(data){
 -                      ok( data.data, "JSON results returned (GET, data callback)" );
 -                      plus();
 -              },
 -              error: function(data){
 -                      ok( false, "Ajax error JSON (GET, data callback)" );
 -                      plus();
 -              }
 -      });
 +              var count = 0;
 +              function plus(){ if ( ++count == 17 ) start(); }
  
 -      jQuery.ajax({
 -              url: "data/jsonp.php",
 -              dataType: "jsonp",
 -              data: {
 -                      callback: "?"
 -              },
 -              success: function(data){
 -                      ok( data.data, "JSON results returned (GET, processed data callback)" );
 -                      plus();
 -              },
 -              error: function(data){
 -                      ok( false, "Ajax error JSON (GET, processed data callback)" );
 -                      plus();
 -              }
 -      });
 +              stop();
  
 -      jQuery.ajax({
 -              url: "data/jsonp.php",
 -              dataType: "jsonp",
 -              jsonp: "callback",
 -              success: function(data){
 -                      ok( data.data, "JSON results returned (GET, data obj callback)" );
 -                      plus();
 -              },
 -              error: function(data){
 -                      ok( false, "Ajax error JSON (GET, data obj callback)" );
 -                      plus();
 -              }
 -      });
 +              jQuery.ajax({
 +                      url: "data/jsonp.php",
 +                      dataType: "jsonp",
 +                      crossDomain: crossDomain,
 +                      success: function(data){
 +                              ok( data.data, "JSON results returned (GET, no callback)" );
 +                              plus();
 +                      },
 +                      error: function(data){
 +                              ok( false, "Ajax error JSON (GET, no callback)" );
 +                              plus();
 +                      }
 +              });
  
 -      jQuery.ajax({
 -              url: "data/jsonp.php",
 -              dataType: "jsonp",
 -              jsonpCallback: "jsonpResults",
 -              success: function(data){
 -                      ok( data.data, "JSON results returned (GET, custom callback name)" );
 -                      plus();
 -              },
 -              error: function(data){
 -                      ok( false, "Ajax error JSON (GET, custom callback name)" );
 -                      plus();
 -              }
 -      });
 +              jQuery.ajax({
 +                      url: "data/jsonp.php?callback=?",
 +                      dataType: "jsonp",
 +                      crossDomain: crossDomain,
 +                      success: function(data){
 +                              ok( data.data, "JSON results returned (GET, url callback)" );
 +                              plus();
 +                      },
 +                      error: function(data){
 +                              ok( false, "Ajax error JSON (GET, url callback)" );
 +                              plus();
 +                      }
 +              });
  
 -      jQuery.ajax({
 -              type: "POST",
 -              url: "data/jsonp.php",
 -              dataType: "jsonp",
 -              success: function(data){
 -                      ok( data.data, "JSON results returned (POST, no callback)" );
 -                      plus();
 -              },
 -              error: function(data){
 -                      ok( false, "Ajax error JSON (GET, data obj callback)" );
 -                      plus();
 -              }
 -      });
 +              jQuery.ajax({
 +                      url: "data/jsonp.php",
 +                      dataType: "jsonp",
 +                      crossDomain: crossDomain,
 +                      data: "callback=?",
 +                      success: function(data){
 +                              ok( data.data, "JSON results returned (GET, data callback)" );
 +                              plus();
 +                      },
 +                      error: function(data){
 +                              ok( false, "Ajax error JSON (GET, data callback)" );
 +                              plus();
 +                      }
 +              });
  
 -      jQuery.ajax({
 -              type: "POST",
 -              url: "data/jsonp.php",
 -              data: "callback=?",
 -              dataType: "jsonp",
 -              success: function(data){
 -                      ok( data.data, "JSON results returned (POST, data callback)" );
 -                      plus();
 -              },
 -              error: function(data){
 -                      ok( false, "Ajax error JSON (POST, data callback)" );
 -                      plus();
 -              }
 -      });
 +              jQuery.ajax({
 +                      url: "data/jsonp.php?callback=??",
 +                      dataType: "jsonp",
 +                      crossDomain: crossDomain,
 +                      success: function(data){
 +                              ok( data.data, "JSON results returned (GET, url context-free callback)" );
 +                              plus();
 +                      },
 +                      error: function(data){
 +                              ok( false, "Ajax error JSON (GET, url context-free callback)" );
 +                              plus();
 +                      }
 +              });
  
 -      jQuery.ajax({
 -              type: "POST",
 -              url: "data/jsonp.php",
 -              jsonp: "callback",
 -              dataType: "jsonp",
 -              success: function(data){
 -                      ok( data.data, "JSON results returned (POST, data obj callback)" );
 -                      plus();
 -              },
 -              error: function(data){
 -                      ok( false, "Ajax error JSON (POST, data obj callback)" );
 -                      plus();
 -              }
 -      });
 +              jQuery.ajax({
 +                      url: "data/jsonp.php",
 +                      dataType: "jsonp",
 +                      crossDomain: crossDomain,
 +                      data: "callback=??",
 +                      success: function(data){
 +                              ok( data.data, "JSON results returned (GET, data context-free callback)" );
 +                              plus();
 +                      },
 +                      error: function(data){
 +                              ok( false, "Ajax error JSON (GET, data context-free callback)" );
 +                              plus();
 +                      }
 +              });
  
 -      //#7578
 -      jQuery.ajax({
 -              url: "data/jsonp.php",
 -              dataType: "jsonp",
 -              beforeSend: function(){
 -                      strictEqual( this.cache, false, "cache must be false on JSON request" );
 -                      plus();
 -                      return false;
 -              }
 -      });
 -});
 +              jQuery.ajax({
 +                      url: "data/jsonp.php/??",
 +                      dataType: "jsonp",
 +                      crossDomain: crossDomain,
 +                      success: function(data){
 +                              ok( data.data, "JSON results returned (GET, REST-like)" );
 +                              plus();
 +                      },
 +                      error: function(data){
 +                              ok( false, "Ajax error JSON (GET, REST-like)" );
 +                              plus();
 +                      }
 +              });
  
 -test("jQuery.ajax() - JSONP - Custom JSONP Callback", function() {
 -      expect(1);
 -      stop();
 +              jQuery.ajax({
 +                      url: "data/jsonp.php/???json=1",
 +                      dataType: "jsonp",
 +                      crossDomain: crossDomain,
 +                      success: function(data){
 +                              strictEqual( jQuery.type(data), "array", "JSON results returned (GET, REST-like with param)" );
 +                              plus();
 +                      },
 +                      error: function(data){
 +                              ok( false, "Ajax error JSON (GET, REST-like with param)" );
 +                              plus();
 +                      }
 +              });
  
 -      window.jsonpResults = function(data) {
 -              ok( data.data, "JSON results returned (GET, custom callback function)" );
 -              window.jsonpResults = undefined;
 -              start();
 -      };
 +              jQuery.ajax({
 +                      url: "data/jsonp.php",
 +                      dataType: "jsonp",
 +                      crossDomain: crossDomain,
 +                      data: {
 +                              callback: "?"
 +                      },
 +                      success: function(data){
 +                              ok( data.data, "JSON results returned (GET, processed data callback)" );
 +                              plus();
 +                      },
 +                      error: function(data){
 +                              ok( false, "Ajax error JSON (GET, processed data callback)" );
 +                              plus();
 +                      }
 +              });
  
 -      jQuery.ajax({
 -              url: "data/jsonp.php",
 -              dataType: "jsonp",
 -              jsonpCallback: "jsonpResults"
 -      });
 -});
 +              jQuery.ajax({
 +                      url: "data/jsonp.php",
 +                      dataType: "jsonp",
 +                      crossDomain: crossDomain,
 +                      jsonp: "callback",
 +                      success: function(data){
 +                              ok( data.data, "JSON results returned (GET, data obj callback)" );
 +                              plus();
 +                      },
 +                      error: function(data){
 +                              ok( false, "Ajax error JSON (GET, data obj callback)" );
 +                              plus();
 +                      }
 +              });
  
 -test("jQuery.ajax() - JSONP, Remote", function() {
 -      expect(4);
 +              window.jsonpResults = function(data) {
 +                      ok( data.data, "JSON results returned (GET, custom callback function)" );
 +                      window.jsonpResults = undefined;
 +                      plus();
 +              };
  
 -      var count = 0;
 -      function plus(){ if ( ++count == 4 ) start(); }
 +              jQuery.ajax({
 +                      url: "data/jsonp.php",
 +                      dataType: "jsonp",
 +                      crossDomain: crossDomain,
 +                      jsonpCallback: "jsonpResults",
 +                      success: function(data){
 +                              ok( data.data, "JSON results returned (GET, custom callback name)" );
 +                              plus();
 +                      },
 +                      error: function(data){
 +                              ok( false, "Ajax error JSON (GET, custom callback name)" );
 +                              plus();
 +                      }
 +              });
  
 -      var base = window.location.href.replace(/[^\/]*$/, "");
 +              jQuery.ajax({
 +                      type: "POST",
 +                      url: "data/jsonp.php",
 +                      dataType: "jsonp",
 +                      crossDomain: crossDomain,
 +                      success: function(data){
 +                              ok( data.data, "JSON results returned (POST, no callback)" );
 +                              plus();
 +                      },
 +                      error: function(data){
 +                              ok( false, "Ajax error JSON (GET, data obj callback)" );
 +                              plus();
 +                      }
 +              });
  
 -      stop();
 +              jQuery.ajax({
 +                      type: "POST",
 +                      url: "data/jsonp.php",
 +                      data: "callback=?",
 +                      dataType: "jsonp",
 +                      crossDomain: crossDomain,
 +                      success: function(data){
 +                              ok( data.data, "JSON results returned (POST, data callback)" );
 +                              plus();
 +                      },
 +                      error: function(data){
 +                              ok( false, "Ajax error JSON (POST, data callback)" );
 +                              plus();
 +                      }
 +              });
  
 -      jQuery.ajax({
 -              url: base + "data/jsonp.php",
 -              dataType: "jsonp",
 -              success: function(data){
 -                      ok( data.data, "JSON results returned (GET, no callback)" );
 -                      plus();
 -              },
 -              error: function(data){
 -                      ok( false, "Ajax error JSON (GET, no callback)" );
 -                      plus();
 -              }
 -      });
 +              jQuery.ajax({
 +                      type: "POST",
 +                      url: "data/jsonp.php",
 +                      jsonp: "callback",
 +                      dataType: "jsonp",
 +                      crossDomain: crossDomain,
 +                      success: function(data){
 +                              ok( data.data, "JSON results returned (POST, data obj callback)" );
 +                              plus();
 +                      },
 +                      error: function(data){
 +                              ok( false, "Ajax error JSON (POST, data obj callback)" );
 +                              plus();
 +                      }
 +              });
  
 -      jQuery.ajax({
 -              url: base + "data/jsonp.php?callback=?",
 -              dataType: "jsonp",
 -              success: function(data){
 -                      ok( data.data, "JSON results returned (GET, url callback)" );
 -                      plus();
 -              },
 -              error: function(data){
 -                      ok( false, "Ajax error JSON (GET, url callback)" );
 -                      plus();
 -              }
 -      });
 +              //#7578
 +              jQuery.ajax({
 +                      url: "data/jsonp.php",
 +                      dataType: "jsonp",
 +                      crossDomain: crossDomain,
 +                      beforeSend: function(){
 +                              strictEqual( this.cache, false, "cache must be false on JSON request" );
 +                              plus();
 +                              return false;
 +                      }
 +              });
  
 -      jQuery.ajax({
 -              url: base + "data/jsonp.php",
 -              dataType: "jsonp",
 -              data: "callback=?",
 -              success: function(data){
 -                      ok( data.data, "JSON results returned (GET, data callback)" );
 -                      plus();
 -              },
 -              error: function(data){
 -                      ok( false, "Ajax error JSON (GET, data callback)" );
 -                      plus();
 -              }
 -      });
 +              jQuery.ajax({
 +                      url: "data/jsonp.php?callback=XXX",
 +                      dataType: "jsonp",
 +                      jsonp: false,
 +                      jsonpCallback: "XXX",
 +                      crossDomain: crossDomain,
 +                      beforeSend: function() {
 +                              ok( /^data\/jsonp.php\?callback=XXX&_=\d+$/.test( this.url ) ,
 +                                      "The URL wasn't messed with (GET, custom callback name with no url manipulation)" );
 +                              plus();
 +                      },
 +                      success: function(data){
 +                              ok( data.data, "JSON results returned (GET, custom callback name with no url manipulation)" );
 +                              plus();
 +                      },
 +                      error: function(data){
 +                              ok( false, "Ajax error JSON (GET, custom callback name with no url manipulation)" );
 +                              plus();
 +                      }
 +              });
  
 -      jQuery.ajax({
 -              url: base + "data/jsonp.php",
 -              dataType: "jsonp",
 -              jsonp: "callback",
 -              success: function(data){
 -                      ok( data.data, "JSON results returned (GET, data obj callback)" );
 -                      plus();
 -              },
 -              error: function(data){
 -                      ok( false, "Ajax error JSON (GET, data obj callback)" );
 -                      plus();
 -              }
        });
  });
  
@@@ -1828,19 -1778,25 +1828,19 @@@ test("jQuery ajax - failing cross-domai
  
        var i = 2;
  
 -      if ( jQuery.ajax({
 +      jQuery.ajax({
                url: 'http://somewebsitethatdoesnotexist-67864863574657654.com',
                success: function(){ ok( false , "success" ); },
                error: function(xhr,_,e){ ok( true , "file not found: " + xhr.status + " => " + e ); },
                complete: function() { if ( ! --i ) start(); }
 -      }) === false ) {
 -              ok( true , "no transport" );
 -              if ( ! --i ) start();
 -      }
 +      });
  
 -      if ( jQuery.ajax({
 +      jQuery.ajax({
                url: 'http://www.google.com',
                success: function(){ ok( false , "success" ); },
                error: function(xhr,_,e){ ok( true , "access denied: " + xhr.status + " => " + e ); },
                complete: function() { if ( ! --i ) start(); }
 -      }) === false ) {
 -              ok( true , "no transport" );
 -              if ( ! --i ) start();
 -      }
 +      });
  
  });
  
@@@ -1872,76 -1828,6 +1872,76 @@@ test( "jQuery.ajax - Location object a
        ok( success, "document.location did not generate exception" );
  });
  
 +test( "jQuery.ajax - statusCode" , function() {
 +
 +      var count = 10;
 +
 +      expect( 16 );
 +      stop();
 +
 +      function countComplete() {
 +              if ( ! --count ) {
 +                      start();
 +              }
 +      }
 +
 +      function createStatusCodes( name , isSuccess ) {
 +              name = "Test " + name + " " + ( isSuccess ? "success" : "error" );
 +              return {
 +                      200: function() {
 +                              ok( isSuccess , name );
 +                      },
 +                      404: function() {
 +                              ok( ! isSuccess , name );
 +                      }
 +              };
 +      }
 +
 +      jQuery.each( {
 +              "data/name.html": true,
 +              "data/someFileThatDoesNotExist.html": false
 +      } , function( uri , isSuccess ) {
 +
 +              jQuery.ajax( url( uri ) , {
 +                      statusCode: createStatusCodes( "in options" , isSuccess ),
 +                      complete: countComplete
 +              });
 +
 +              jQuery.ajax( url( uri ) , {
 +                      complete: countComplete
 +              }).statusCode( createStatusCodes( "immediately with method" , isSuccess ) );
 +
 +              jQuery.ajax( url( uri ) , {
 +                      complete: function(jXHR) {
 +                              jXHR.statusCode( createStatusCodes( "on complete" , isSuccess ) );
 +                              countComplete();
 +                      }
 +              });
 +
 +              jQuery.ajax( url( uri ) , {
 +                      complete: function(jXHR) {
 +                              setTimeout( function() {
 +                                      jXHR.statusCode( createStatusCodes( "very late binding" , isSuccess ) );
 +                                      countComplete();
 +                              } , 100 );
 +                      }
 +              });
 +
 +              jQuery.ajax( url( uri ) , {
 +                      statusCode: createStatusCodes( "all (options)" , isSuccess ),
 +                      complete: function(jXHR) {
 +                              jXHR.statusCode( createStatusCodes( "all (on complete)" , isSuccess ) );
 +                              setTimeout( function() {
 +                                      jXHR.statusCode( createStatusCodes( "all (very late binding)" , isSuccess ) );
 +                                      countComplete();
 +                              } , 100 );
 +                      }
 +              }).statusCode( createStatusCodes( "all (immediately with method)" , isSuccess ) );
 +
 +      });
 +
 +});
 +
  }
  
  //}
diff --combined test/unit/core.js
@@@ -1,4 -1,4 +1,4 @@@
- module("core");
+ module("core", { teardown: moduleTeardown });
  
  test("Basic requirements", function() {
        expect(7);
@@@ -12,7 -12,7 +12,7 @@@
  });
  
  test("jQuery()", function() {
 -      expect(23);
 +      expect(24);
  
        // Basic constructor's behavior
  
@@@ -21,7 -21,7 +21,7 @@@
        equals( jQuery(null).length, 0, "jQuery(null) === jQuery([])" );
        equals( jQuery("").length, 0, "jQuery('') === jQuery([])" );
  
 -      var obj = jQuery("div")
 +      var obj = jQuery("div");
        equals( jQuery(obj).selector, "div", "jQuery(jQueryObj) == jQueryObj" );
  
                // can actually yield more than one, when iframes are included, the window is an array as well
        exec = true;
        elem.click();
  
+       // manually clean up detached elements
+       elem.remove();
++
 +      for ( var i = 0; i < 3; ++i ) {
 +              elem = jQuery("<input type='text' value='TEST' />");
 +      }
 +      equals( elem[0].defaultValue, "TEST", "Ensure cached nodes are cloned properly (Bug #6655)" );
++
++      // manually clean up detached elements
++      elem.remove();
  });
  
  test("selector state", function() {
@@@ -1003,7 -1001,7 +1009,7 @@@ test("jQuery._Deferred()", function() 
  
  test("jQuery.Deferred()", function() {
  
 -      expect( 4 );
 +      expect( 10 );
  
        jQuery.Deferred( function( defer ) {
                strictEqual( this , defer , "Defer passed as this & first argument" );
        }, function() {
                ok( true , "Error on reject" );
        });
 +
 +      ( new jQuery.Deferred( function( defer ) {
 +              strictEqual( this , defer , "Defer passed as this & first argument (new)" );
 +              this.resolve( "done" );
 +      }) ).then( function( value ) {
 +              strictEqual( value , "done" , "Passed function executed (new)" );
 +      });
 +
 +      ( new jQuery.Deferred() ).resolve().then( function() {
 +              ok( true , "Success on resolve (new)" );
 +      }, function() {
 +              ok( false , "Error on resolve (new)" );
 +      });
 +
 +      ( new jQuery.Deferred() ).reject().then( function() {
 +              ok( false , "Success on reject (new)" );
 +      }, function() {
 +              ok( true , "Error on reject (new)" );
 +      });
 +
 +      var tmp = jQuery.Deferred();
 +
 +      strictEqual( tmp.promise() , tmp.promise() , "Test deferred always return same promise" );
 +      strictEqual( tmp.promise() , tmp.promise().promise() , "Test deferred's promise always return same promise as deferred" );
  });
  
  test("jQuery.when()", function() {
  
 -      expect( 21 );
 +      expect( 23 );
  
        // Some other objects
        jQuery.each( {
  
        } );
  
 +      ok( jQuery.isFunction( jQuery.when().then( function( resolveValue ) {
 +              strictEqual( resolveValue , undefined , "Test the promise was resolved with no parameter" );
 +      } ).promise ) , "Test calling when with no parameter triggers the creation of a new Promise" );
 +
        var cache, i;
  
        for( i = 1 ; i < 4 ; i++ ) {
                });
        }
  });
 +
 +test("jQuery.when() - joined", function() {
 +
 +      expect(8);
 +
 +      jQuery.when( 1, 2, 3 ).done( function( a, b, c ) {
 +              strictEqual( a , 1 , "Test first param is first resolved value - non-observables" );
 +              strictEqual( b , 2 , "Test second param is second resolved value - non-observables" );
 +              strictEqual( c , 3 , "Test third param is third resolved value - non-observables" );
 +      }).fail( function() {
 +              ok( false , "Test the created deferred was resolved - non-observables");
 +      });
 +
 +      var successDeferred = jQuery.Deferred().resolve( 1 , 2 , 3 ),
 +              errorDeferred = jQuery.Deferred().reject( "error" , "errorParam" );
 +
 +      jQuery.when( 1 , successDeferred , 3 ).done( function( a, b, c ) {
 +              strictEqual( a , 1 , "Test first param is first resolved value - resolved observable" );
 +              same( b , [ 1 , 2 , 3 ] , "Test second param is second resolved value - resolved observable" );
 +              strictEqual( c , 3 , "Test third param is third resolved value - resolved observable" );
 +      }).fail( function() {
 +              ok( false , "Test the created deferred was resolved - resolved observable");
 +      });
 +
 +      jQuery.when( 1 , errorDeferred , 3 ).done( function() {
 +              ok( false , "Test the created deferred was rejected - rejected observable");
 +      }).fail( function( error , errorParam ) {
 +              strictEqual( error , "error" , "Test first param is first rejected value - rejected observable" );
 +              strictEqual( errorParam , "errorParam" , "Test second param is second rejected value - rejected observable" );
 +      });
 +});
 +
 +test("jQuery.subclass", function(){
 +      expect(378);
 +
 +      var Subclass = jQuery.subclass(),
 +                      SubclassSubclass = Subclass.subclass(),
 +                      jQueryDocument = jQuery(document),
 +                      selectors, contexts, methods, method, arg, description;
 +
 +      jQueryDocument.toString = function(){ return 'jQueryDocument'; };
 +
 +      Subclass.fn.subclassMethod = function(){};
 +      SubclassSubclass.fn.subclassSubclassMethod = function(){};
 +
 +      selectors = [
 +              'body',
 +              'html, body',
 +              '<div></div>'
 +      ];
 +
 +      methods = [ // all methods that return a new jQuery instance
 +              ['eq', 1],
 +              ['add', document],
 +              ['end'],
 +              ['has'],
 +              ['closest', 'div'],
 +              ['filter', document],
 +              ['find', 'div']
 +      ];
 +
 +      contexts = [undefined, document, jQueryDocument];
 +
 +      jQuery.each(selectors, function(i, selector){
 +
 +              jQuery.each(methods, function(){
 +                      method = this[0];
 +                      arg = this[1];
 +
 +                      jQuery.each(contexts, function(i, context){
 +
 +                              description = '("'+selector+'", '+context+').'+method+'('+(arg||'')+')';
 +
 +                              same(
 +                                      jQuery(selector, context)[method](arg).subclassMethod, undefined,
 +                                      'jQuery'+description+' doesnt have Subclass methods'
 +                              );
 +                              same(
 +                                      jQuery(selector, context)[method](arg).subclassSubclassMethod, undefined,
 +                                      'jQuery'+description+' doesnt have SubclassSubclass methods'
 +                              );
 +                              same(
 +                                      Subclass(selector, context)[method](arg).subclassMethod, Subclass.fn.subclassMethod,
 +                                      'Subclass'+description+' has Subclass methods'
 +                              );
 +                              same(
 +                                      Subclass(selector, context)[method](arg).subclassSubclassMethod, undefined,
 +                                      'Subclass'+description+' doesnt have SubclassSubclass methods'
 +                              );
 +                              same(
 +                                      SubclassSubclass(selector, context)[method](arg).subclassMethod, Subclass.fn.subclassMethod,
 +                                      'SubclassSubclass'+description+' has Subclass methods'
 +                              );
 +                              same(
 +                                      SubclassSubclass(selector, context)[method](arg).subclassSubclassMethod, SubclassSubclass.fn.subclassSubclassMethod,
 +                                      'SubclassSubclass'+description+' has SubclassSubclass methods'
 +                              );
 +
 +                      });
 +              });
 +      });
 +
 +});
diff --combined test/unit/css.js
@@@ -1,4 -1,4 +1,4 @@@
- module("css");
+ module("css", { teardown: moduleTeardown });
  
  test("css(String|Hash)", function() {
        expect(41);
@@@ -320,25 -320,3 +320,25 @@@ test(":visible selector works properly 
        jQuery('#table').css('display', 'none').html('<tr><td>cell</td><td>cell</td></tr>');
        equals(jQuery('#table td:visible').length, 0, "hidden cell children not perceived as visible");
  });
 +
 +test("internal ref to elem.runtimeStyle (bug #7608)", function () {
 +      expect(1);
 +
 +      var result = true,
 +      val = 10;
 +      
 +      jQuery('<div id="bug7608" style="width:200px;border:solid 1px red;">' +
 +    '<div  id="test" style="width:0%; background:#000;">&nbsp;</div></div>').appendTo("#main");
 +
 +      try {
 +              // the bug is located within src/css.js
 +              jQuery("#bug7608 #test").animate( { width: val }, 1000);
 +
 +      } catch (e) {
 +              result = false;
 +      }
 +
 +      ok( result, "elem.runtimeStyle does not throw exception" );
 +  
 +      jQuery("#bug7608").remove();
 +});
diff --combined test/unit/event.js
@@@ -1,4 -1,4 +1,4 @@@
- module("event");
+ module("event", { teardown: moduleTeardown });
  
  test("null or undefined handler", function() {
        expect(2);
@@@ -28,7 -28,7 +28,7 @@@ test("bind(), with data", function() 
        };
        jQuery("#firstp").bind("click", {foo: "bar"}, handler).click().unbind("click", handler);
  
-       ok( !jQuery.data(jQuery("#firstp")[0], "events"), "Event handler unbound when using data." );
+       ok( !jQuery._data(jQuery("#firstp")[0], "events"), "Event handler unbound when using data." );
  });
  
  test("click(), with data", function() {
@@@ -39,7 -39,7 +39,7 @@@
        };
        jQuery("#firstp").click({foo: "bar"}, handler).click().unbind("click", handler);
  
-       ok( !jQuery.data(jQuery("#firstp")[0], "events"), "Event handler unbound when using data." );
+       ok( !jQuery._data(jQuery("#firstp")[0], "events"), "Event handler unbound when using data." );
  });
  
  test("bind(), with data, trigger with data", function() {
@@@ -80,6 -80,9 +80,9 @@@ test("bind(), multiple events at once a
        cur = "focusin";
        div.trigger("focusin.a");
  
+       // manually clean up detached elements
+       div.remove();
        div = jQuery("<div/>").bind("click mouseover", obj, function(e) {
                equals( e.type, cur, "Verify right multi event was fired." );
                equals( e.data, obj, "Make sure the data came in correctly." );
@@@ -91,6 -94,9 +94,9 @@@
        cur = "mouseover";
        div.trigger("mouseover");
  
+       // manually clean up detached elements
+       div.remove();
        div = jQuery("<div/>").bind("focusin.a focusout.b", function(e) {
                equals( e.type, cur, "Verify right multi event was fired." );
        });
  
        cur = "focusout";
        div.trigger("focusout.b");
+       // manually clean up detached elements
+       div.remove();
  });
  
  test("bind(), namespace with special add", function() {
@@@ -295,15 -304,15 +304,15 @@@ test("live/delegate immediate propagati
        $p.undelegate( "click" );
  });
  
 -test("bind/delegate bubbling, isDefaultPrevented (Bug #7793)", function() {
 +test("bind/delegate bubbling, isDefaultPrevented", function() {
        expect(2);
        var $anchor2 = jQuery( "#anchor2" ),
                $main = jQuery( "#main" ),
                fakeClick = function($jq) {
                        // Use a native click so we don't get jQuery simulated bubbling
                        if ( document.createEvent ) {
 -                              var e = document.createEvent( "MouseEvents" );
 -                              e.initEvent( "click", true, true );
 +                              var e = document.createEvent( 'MouseEvents' );
 +                              e.initEvent( "click", true, true ); 
                                $jq[0].dispatchEvent(e);
                        }
                        else if ( $jq[0].click ) {
                e.preventDefault();
        });
        $main.delegate("#foo", "click", function(e) {
 -              equals( e.isDefaultPrevented(), true, "isDefaultPrevented true passed to bubbled event" );
 +              var orig = e.originalEvent;
 +
 +              if ( typeof(orig.defaultPrevented) === "boolean" || typeof(orig.returnValue) === "boolean" || orig.getPreventDefault ) {
 +                      equals( e.isDefaultPrevented(), true, "isDefaultPrevented true passed to bubbled event" );
 +
 +              } else {
 +                      // Opera < 11 doesn't implement any interface we can use, so give it a pass
 +                      ok( true, "isDefaultPrevented not supported by this browser, test skipped" );
 +              }
        });
        fakeClick( $anchor2 );
        $anchor2.unbind( "click" );
@@@ -513,7 -514,7 +522,7 @@@ test("bind(), with different this objec
                .bind("click", jQuery.proxy(handler1, thisObject)).click().unbind("click", handler1)
                .bind("click", data, jQuery.proxy(handler2, thisObject)).click().unbind("click", handler2);
  
-       ok( !jQuery.data(jQuery("#firstp")[0], "events"), "Event handler unbound when using different this object and data." );
+       ok( !jQuery._data(jQuery("#firstp")[0], "events"), "Event handler unbound when using different this object and data." );
  });
  
  test("bind(name, false), unbind(name, false)", function() {
        jQuery("#ap").unbind("click", false);
        jQuery("#ap").trigger("click");
        equals( main, 1, "Verify that the trigger happened correctly." );
+       // manually clean up events from elements outside the fixture
+       jQuery("#main").unbind("click");
  });
  
  test("bind()/trigger()/unbind() on plain object", function() {
                }
        });
  
-       var events = jQuery(obj).data("__events__");
+       var events = jQuery._data(obj, "events");
        ok( events, "Object has events bound." );
        equals( obj.events, undefined, "Events object on plain objects is not events" );
        equals( typeof events, "function", "'events' expando is a function on plain objects." );
        // Make sure it doesn't complain when no events are found
        jQuery(obj).unbind("test");
  
-       equals( obj.__events__, undefined, "Make sure events object is removed" );
+       equals( obj && obj[ jQuery.expando ] &&
+                   obj[ jQuery.expando ][ jQuery.expando ] &&
+                       obj[ jQuery.expando ][ jQuery.expando ].events, undefined, "Make sure events object is removed" );
  });
  
  test("unbind(type)", function() {
@@@ -669,13 -675,18 +683,18 @@@ test("hover()", function() 
  
  test("trigger() shortcuts", function() {
        expect(6);
-       jQuery('<li><a href="#">Change location</a></li>').prependTo('#firstUL').find('a').bind('click', function() {
+       var elem = jQuery('<li><a href="#">Change location</a></li>').prependTo('#firstUL');
+       elem.find('a').bind('click', function() {
                var close = jQuery('spanx', this); // same with jQuery(this).find('span');
                equals( close.length, 0, "Context element does not exist, length must be zero" );
                ok( !close[0], "Context element does not exist, direct access to element must return undefined" );
                return false;
        }).click();
  
+       // manually clean up detached elements
+       elem.remove();
        jQuery("#check1").click(function() {
                ok( true, "click event handler for checkbox gets fired twice, see #815" );
        }).click();
        jQuery('#simon1').click();
        equals( clickCounter, 1, "Check that click, triggers onclick event handler on an a tag also" );
  
-       jQuery('<img />').load(function(){
+       elem = jQuery('<img />').load(function(){
                ok( true, "Trigger the load event, using the shortcut .load() (#2819)");
        }).load();
+       // manually clean up detached elements
+       elem.remove();
  });
  
  test("trigger() bubbling", function() {
        equals( body, 2, "ap bubble" );
        equals( main, 1, "ap bubble" );
        equals( ap, 1, "ap bubble" );
+       // manually clean up events from elements outside the fixture
+       jQuery(document).unbind("click");
+       jQuery("html, body, #main").unbind("click");
  });
  
  test("trigger(type, [data], [fn])", function() {
  
        pass = true;
        try {
-               jQuery('table:first').bind('test:test', function(){}).trigger('test:test');
+               jQuery('#main table:first').bind('test:test', function(){}).trigger('test:test');
        } catch (e) {
                pass = false;
        }
@@@ -955,9 -973,12 +981,12 @@@ test("toggle(Function, Function, ...)"
        equals( turn, 2, "Trying toggle with 3 functions, attempt 5 yields 2");
  
        $div.unbind('click',fns[0]);
-       var data = jQuery.data( $div[0], 'events' );
+       var data = jQuery._data( $div[0], 'events' );
        ok( !data, "Unbinding one function from toggle unbinds them all");
  
+       // manually clean up detached elements
+       $div.remove();
        // Test Multi-Toggles
        var a = [], b = [];
        $div = jQuery("<div/>");
        $div.click();
        same( a, [1,2,1], "Check that a click worked with a second toggle, second click." );
        same( b, [1,2], "Check that a click worked with a second toggle, second click." );
+       // manually clean up detached elements
+       $div.remove();
  });
  
  test(".live()/.die()", function() {
        equals( clicked, 2, "live with a context" );
  
        // Make sure the event is actually stored on the context
-       ok( jQuery.data(container, "events").live, "live with a context" );
+       ok( jQuery._data(container, "events").live, "live with a context" );
  
        // Test unbinding with a different context
        jQuery("#foo", container).die("click");
@@@ -1283,6 -1307,9 +1315,9 @@@ test("live with multiple events", funct
        div.trigger("submit");
  
        equals( count, 2, "Make sure both the click and submit were triggered." );
+       // manually clean up events from elements outside the fixture
+       div.die();
  });
  
  test("live with namespaces", function(){
@@@ -1586,7 -1613,7 +1621,7 @@@ test(".delegate()/.undelegate()", funct
        equals( clicked, 2, "delegate with a context" );
  
        // Make sure the event is actually stored on the context
-       ok( jQuery.data(container, "events").live, "delegate with a context" );
+       ok( jQuery._data(container, "events").live, "delegate with a context" );
  
        // Test unbinding with a different context
        jQuery("#main").undelegate("#foo", "click");
@@@ -1915,7 -1942,7 +1950,7 @@@ test("window resize", function() 
                ok( true, "Resize event fired." );
        }).resize().unbind("resize");
  
-       ok( !jQuery(window).data("__events__"), "Make sure all the events are gone." );
+       ok( !jQuery._data(window, "__events__"), "Make sure all the events are gone." );
  });
  
  test("focusin bubbles", function() {
@@@ -1,4 -1,4 +1,4 @@@
- module("manipulation");
+ module("manipulation", { teardown: moduleTeardown });
  
  // Ensure that an extended Array prototype doesn't break jQuery
  Array.prototype.arrayProtoFn = function(arg) { throw("arrayProtoFn should not be called"); };
@@@ -115,12 -115,19 +115,19 @@@ var testWrap = function(val) 
        // Wrap an element with a jQuery set and event
        result = jQuery("<div></div>").click(function(){
                ok(true, "Event triggered.");
+               // Remove handlers on detached elements
+               result.unbind();
+               jQuery(this).unbind();
        });
  
        j = jQuery("<span/>").wrap(result);
        equals( j[0].parentNode.nodeName.toLowerCase(), "div", "Wrapping works." );
  
        j.parent().trigger("click");
+       // clean up attached elements
+       QUnit.reset();
  }
  
  test("wrap(String|Element)", function() {
@@@ -395,7 -402,7 +402,7 @@@ test("append(Function) with incoming va
  });
  
  test("append the same fragment with events (Bug #6997, 5566)", function () {
 -      expect(4 + (document.fireEvent ? 1 : 0));
 +      expect(2 + (document.fireEvent ? 1 : 0));
        stop(1000);
  
        var element;
                        ok(true, "Event exists on original after being unbound on clone");
                        jQuery(this).unbind('click');
                });
-               element.clone(true).unbind('click')[0].fireEvent('onclick');
+               var clone = element.clone(true).unbind('click');
+               clone[0].fireEvent('onclick');
                element[0].fireEvent('onclick');
+               // manually clean up detached elements
+               clone.remove();
        }
  
        element = jQuery("<a class='test6997'></a>").click(function () {
  
        jQuery("#listWithTabIndex li").before(element);
        jQuery("#listWithTabIndex li.test6997").eq(1).click();
 -
 -      element = jQuery("<select><option>Foo</option><option selected>Bar</option></select>");
 -
 -      equals( element.clone().find("option:selected").val(), element.find("option:selected").val(), "Selected option cloned correctly" );
 -
 -      element = jQuery("<input type='checkbox'>").attr('checked', 'checked');
 -
 -      equals( element.clone().is(":checked"), element.is(":checked"), "Checked input cloned correctly" );
  });
  
  test("appendTo(String|Element|Array&lt;Element&gt;|jQuery)", function() {
@@@ -886,20 -905,36 +897,36 @@@ test("clone()", function() 
                ok( true, "Bound event still exists." );
        });
  
-       div = div.clone(true).clone(true);
+       clone = div.clone(true);
+       // manually clean up detached elements
+       div.remove();
+       div = clone.clone(true);
+       // manually clean up detached elements
+       clone.remove();
        equals( div.length, 1, "One element cloned" );
        equals( div[0].nodeName.toUpperCase(), "DIV", "DIV element cloned" );
        div.trigger("click");
  
+       // manually clean up detached elements
+       div.remove();
        div = jQuery("<div/>").append([ document.createElement("table"), document.createElement("table") ]);
        div.find("table").click(function(){
                ok( true, "Bound event still exists." );
        });
  
-       div = div.clone(true);
-       equals( div.length, 1, "One element cloned" );
-       equals( div[0].nodeName.toUpperCase(), "DIV", "DIV element cloned" );
-       div.find("table:last").trigger("click");
+       clone = div.clone(true);
+       equals( clone.length, 1, "One element cloned" );
+       equals( clone[0].nodeName.toUpperCase(), "DIV", "DIV element cloned" );
+       clone.find("table:last").trigger("click");
+       // manually clean up detached elements
+       div.remove();
+       clone.remove();
  
        // this is technically an invalid object, but because of the special
        // classid instantiation it is the only kind that IE has trouble with,
        equals( clone[0].nodeName.toUpperCase(), "DIV", "DIV element cloned" );
  
        div = jQuery("<div/>").data({ a: true });
-       var div2 = div.clone(true);
-       equals( div2.data("a"), true, "Data cloned." );
-       div2.data("a", false);
-       equals( div2.data("a"), false, "Ensure cloned element data object was correctly modified" );
+       clone = div.clone(true);
+       equals( clone.data("a"), true, "Data cloned." );
+       clone.data("a", false);
+       equals( clone.data("a"), false, "Ensure cloned element data object was correctly modified" );
        equals( div.data("a"), true, "Ensure cloned element data object is copied, not referenced" );
  
+       // manually clean up detached elements
+       div.remove();
+       clone.remove();
        var form = document.createElement("form");
        form.action = "/test/";
        var div = document.createElement("div");
        equal( jQuery("body").clone().children()[0].id, "qunit-header", "Make sure cloning body works" );
  });
  
 +test("clone(form element) (Bug #3879, #6655)", function() {
 +      expect(6);
 +      element = jQuery("<select><option>Foo</option><option selected>Bar</option></select>");
 +
 +      equals( element.clone().find("option:selected").val(), element.find("option:selected").val(), "Selected option cloned correctly" );
 +
 +      element = jQuery("<input type='checkbox' value='foo'>").attr('checked', 'checked');
 +      clone = element.clone();
 +
 +      equals( clone.is(":checked"), element.is(":checked"), "Checked input cloned correctly" );
 +      equals( clone[0].defaultValue, "foo", "Checked input defaultValue cloned correctly" );
 +      equals( clone[0].defaultChecked, !jQuery.support.noCloneEvent, "Checked input defaultChecked cloned correctly" );
 +
 +      element = jQuery("<input type='text' value='foo'>");
 +      clone = element.clone();
 +      equals( clone[0].defaultValue, "foo", "Text input defaultValue cloned correctly" );
 +
 +      element = jQuery("<textarea>foo</textarea>");
 +      clone = element.clone();
 +      equals( clone[0].defaultValue, "foo", "Textarea defaultValue cloned correctly" );
 +});
 +
  if (!isLocal) {
  test("clone() on XML nodes", function() {
        expect(2);
@@@ -1155,15 -1172,21 +1186,21 @@@ var testRemove = function(method) 
        jQuery("#nonnodes").contents()[method]();
        equals( jQuery("#nonnodes").contents().length, 0, "Check node,textnode,comment remove works" );
  
+       // manually clean up detached elements
+       if (method === "detach") {
+               first.remove();
+       }
        QUnit.reset();
  
        var count = 0;
        var first = jQuery("#ap").children(":first");
-       var cleanUp = first.click(function() { count++ })[method]().appendTo("body").click();
+       var cleanUp = first.click(function() { count++ })[method]().appendTo("#main").click();
  
        equals( method == "remove" ? 0 : 1, count );
  
-       cleanUp.detach();
+       // manually clean up detached elements
+       cleanUp.remove();
  };
  
  test("remove()", function() {