Skip to main content

Bug Tracker

Side navigation

Ticket #1731: 1731.2.diff
File 1731.2.diff, 6.5 KB (added by brandon, October 05, 2007 10:32PM UTC)

Fixes leaks in remove, html, empty and expands small variables

Index: src/core.js
===================================================================
--- src/core.js	(revision 3567)
+++ src/core.js	(working copy)
@@ -1246,17 +1246,20 @@
 
 	remove: function( selector ) {
 		if ( !selector || jQuery.filter( selector, [ this ] ).r.length ) {
-			jQuery.removeData( this );
+			// Prevent memory leaks
+			jQuery( "*", this ).add(this).each(function(){
+				jQuery.event.remove(this);
+				jQuery.removeData(this);
+			});
 			this.parentNode.removeChild( this );
 		}
 	},
 
 	empty: function() {
-		// Clean up the cache
-		jQuery( "*", this ).each(function(){
-			jQuery.removeData(this);
-		});
-
+		// Remove element nodes and prevent memory leaks
+		jQuery( ">*", this ).remove();
+		
+		// Remove any remaining nodes
 		while ( this.firstChild )
 			this.removeChild( this.firstChild );
 	}
Index: src/event.js
===================================================================
--- src/event.js	(revision 3567)
+++ src/event.js	(working copy)
@@ -43,7 +43,7 @@
 		// Init the element's event structure
 		var events = jQuery.data(element, "events") || jQuery.data(element, "events", {});
 		
-		var handle = jQuery.data(element, "handle", function(){
+		var handle = jQuery.data(element, "handle") || jQuery.data(element, "handle", function(){
 			// returned undefined or false
 			var val;
 
@@ -149,10 +149,10 @@
 		} else {
 			var val, ret, fn = jQuery.isFunction( element[ type ] || null ),
 				// Check to see if we need to provide a fake event, or not
-				evt = !data[0] || !data[0].preventDefault;
+				event = !data[0] || !data[0].preventDefault;
 			
 			// Pass along a fake event
-			if ( evt )
+			if ( event )
 				data.unshift( this.fix({ type: type, target: element }) );
 
 			// Enforce the right trigger type
@@ -167,7 +167,7 @@
 				val = false;
 
 			// Extra functions don't get the custom event object
-			if ( evt )
+			if ( event )
 				data.shift();
 
 			// Handle triggering of extra function
@@ -197,23 +197,24 @@
 		var parts = event.type.split(".");
 		event.type = parts[0];
 
-		var c = jQuery.data(this, "events") && jQuery.data(this, "events")[event.type], args = Array.prototype.slice.call( arguments, 1 );
+		var handlers = jQuery.data(this, "events") && jQuery.data(this, "events")[event.type], args = Array.prototype.slice.call( arguments, 1 );
 		args.unshift( event );
 
-		for ( var j in c ) {
+		for ( var j in handlers ) {
+			var handler = handlers[j];
 			// Pass in a reference to the handler function itself
 			// So that we can later remove it
-			args[0].handler = c[j];
-			args[0].data = c[j].data;
+			args[0].handler = handler;
+			args[0].data = handler.data;
 
 			// Filter the functions by class
-			if ( !parts[1] || c[j].type == parts[1] ) {
-				var tmp = c[j].apply( this, args );
+			if ( !parts[1] || handler.type == parts[1] ) {
+				var ret = handler.apply( this, args );
 
 				if ( val !== false )
-					val = tmp;
+					val = ret;
 
-				if ( tmp === false ) {
+				if ( ret === false ) {
 					event.preventDefault();
 					event.stopPropagation();
 				}
@@ -265,9 +266,9 @@
 
 		// Calculate pageX/Y if missing and clientX/Y available
 		if ( event.pageX == null && event.clientX != null ) {
-			var e = document.documentElement, b = document.body;
-			event.pageX = event.clientX + (e && e.scrollLeft || b && b.scrollLeft || 0);
-			event.pageY = event.clientY + (e && e.scrollTop || b && b.scrollTop || 0);
+			var doc = document.documentElement, body = document.body;
+			event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0);
+			event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0);
 		}
 			
 		// Add which for key events
@@ -322,54 +323,54 @@
 
 	toggle: function() {
 		// Save reference to arguments for access in closure
-		var a = arguments;
+		var args = arguments;
 
-		return this.click(function(e) {
+		return this.click(function(event) {
 			// Figure out which function to execute
 			this.lastToggle = 0 == this.lastToggle ? 1 : 0;
 			
 			// Make sure that clicks stop
-			e.preventDefault();
+			event.preventDefault();
 			
 			// and execute the function
-			return a[this.lastToggle].apply( this, [e] ) || false;
+			return args[this.lastToggle].apply( this, [event] ) || false;
 		});
 	},
 
-	hover: function(f,g) {
+	hover: function(fnOver, fnOut) {
 		
 		// A private function for handling mouse 'hovering'
-		function handleHover(e) {
+		function handleHover(event) {
 			// Check if mouse(over|out) are still within the same parent element
-			var p = e.relatedTarget;
+			var parent = event.relatedTarget;
 	
 			// Traverse up the tree
-			while ( p && p != this ) try { p = p.parentNode; } catch(e) { p = this; };
+			while ( parent && parent != this ) try { parent = parent.parentNode; } catch(error) { parent = this; };
 			
 			// If we actually just moused on to a sub-element, ignore it
-			if ( p == this ) return false;
+			if ( parent == this ) return false;
 			
 			// Execute the right function
-			return (e.type == "mouseover" ? f : g).apply(this, [e]);
+			return (event.type == "mouseover" ? fnOver : fnOut).apply(this, [event]);
 		}
 		
 		// Bind the function to the two event listeners
 		return this.mouseover(handleHover).mouseout(handleHover);
 	},
 	
-	ready: function(f) {
+	ready: function(fn) {
 		// Attach the listeners
 		bindReady();
 
 		// If the DOM is already ready
 		if ( jQuery.isReady )
 			// Execute the function immediately
-			f.apply( document, [jQuery] );
+			fn.apply( document, [jQuery] );
 			
 		// Otherwise, remember the function for later
 		else
 			// Add the function to the wait list
-			jQuery.readyList.push( function() { return f.apply(this, [jQuery]); } );
+			jQuery.readyList.push( function() { return fn.apply(this, [jQuery]); } );
 	
 		return this;
 	}
@@ -409,11 +410,11 @@
 
 jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +
 	"mousedown,mouseup,mousemove,mouseover,mouseout,change,select," + 
-	"submit,keydown,keypress,keyup,error").split(","), function(i,o){
+	"submit,keydown,keypress,keyup,error").split(","), function(i, name){
 	
 	// Handle event binding
-	jQuery.fn[o] = function(f){
-		return f ? this.bind(o, f) : this.trigger(o);
+	jQuery.fn[name] = function(fn){
+		return fn ? this.bind(name, fn) : this.trigger(name);
 	};
 });
 
@@ -451,3 +452,9 @@
 	// A fallback to window.onload, that will always work
 	jQuery.event.add( window, "load", jQuery.ready );
 }
+
+// Prevent memory leaks in IE
+if ( jQuery.browser.msie )
+	jQuery(window).bind("unload", function() {
+		$("*").add([document, window]).unbind();
+	});

Download in other formats:

Original Format