From 4afa60835146e71c0e57b492a1cca278eaf1ef9c Mon Sep 17 00:00:00 2001
From: Ariel Flesler <aflesler@gmail.com>
Date: Tue, 30 Dec 2008 02:31:26 +0000
Subject: [PATCH] jquery data: Closes #3539. Exposed jQuery.queue. Moved all
 the data and queue functions to their own module. Made the
 dequeue function more generic(designed to be used on
 functions). Closes #3748. Reverted a previous modification.

---
 Makefile          |    1 +
 src/core.js       |   98 +-------------------------------
 src/fx.js         |   48 ----------------
 test/index.html   |    1 +
 test/unit/core.js |   94 -------------------------------
 test/unit/data.js |  160 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 test/unit/fx.js   |   17 ------
 7 files changed, 164 insertions(+), 255 deletions(-)
 create mode 100644 test/unit/data.js

diff --git a/Makefile b/Makefile
index c3a16b9..36bd11c 100644
--- a/Makefile
+++ b/Makefile
@@ -9,6 +9,7 @@ SPEED_DIR = ${PREFIX}/speed
 PLUG_DIR = ../plugins
 
 BASE_FILES = ${SRC_DIR}/core.js\
+	${SRC_DIR}/data.js\
 	${SRC_DIR}/support.js\
 	${SRC_DIR}/selector.js\
 	${SRC_DIR}/event.js\
diff --git a/src/core.js b/src/core.js
index 09e6895..b5de145 100644
--- a/src/core.js
+++ b/src/core.js
@@ -483,31 +483,6 @@ jQuery.fn = jQuery.prototype = {
 		return this.add( this.prevObject );
 	},
 
-	data: function( key, value ){
-		var parts = key.split(".");
-		parts[1] = parts[1] ? "." + parts[1] : "";
-
-		if ( value === undefined ) {
-			var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
-
-			if ( data === undefined && this.length )
-				data = jQuery.data( this[0], key );
-
-			return data == null && parts[1] ?
-				this.data( parts[0] ) :
-				data;
-		} else
-			return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){
-				jQuery.data( this, key, value );
-			});
-	},
-
-	removeData: function( key ){
-		return this.each(function(){
-			jQuery.removeData( this, key );
-		});
-	},
-
 	domManip: function( args, table, callback ) {
 		if ( this[0] ) {
 			var fragment = this[0].ownerDocument.createDocumentFragment(),
@@ -606,9 +581,8 @@ jQuery.extend = jQuery.fn.extend = function() {
 	return target;
 };
 
-var expando = "jQuery" + now(), uuid = 0, windowData = {},
-	// exclude the following css properties to add px
-	exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
+// exclude the following css properties to add px
+var	exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
 	// cache defaultView
 	defaultView = document.defaultView || {},
 	toString = Object.prototype.toString;
@@ -667,74 +641,6 @@ jQuery.extend({
 		return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
 	},
 
-	cache: {},
-
-	data: function( elem, name, data ) {
-		elem = elem == window ?
-			windowData :
-			elem;
-
-		var id = elem[ expando ];
-
-		// Compute a unique ID for the element
-		if ( !id )
-			id = elem[ expando ] = ++uuid;
-
-		// Only generate the data cache if we're
-		// trying to access or manipulate it
-		if ( name && !jQuery.cache[ id ] )
-			jQuery.cache[ id ] = {};
-
-		// Prevent overriding the named cache with undefined values
-		if ( data !== undefined )
-			jQuery.cache[ id ][ name ] = data;
-
-		// Return the named cache data, or the ID for the element
-		return name ?
-			jQuery.cache[ id ][ name ] || null :
-			id;
-	},
-
-	removeData: function( elem, name ) {
-		elem = elem == window ?
-			windowData :
-			elem;
-
-		var id = elem[ expando ];
-
-		// If we want to remove a specific section of the element's data
-		if ( name ) {
-			if ( jQuery.cache[ id ] ) {
-				// Remove the section of cache data
-				delete jQuery.cache[ id ][ name ];
-
-				// If we've removed all the data, remove the element's cache
-				name = "";
-
-				for ( name in jQuery.cache[ id ] )
-					break;
-
-				if ( !name )
-					jQuery.removeData( elem );
-			}
-
-		// Otherwise, we want to remove all of the element's data
-		} else {
-			// Clean up the element expando
-			try {
-				delete elem[ expando ];
-			} catch(e){
-				// IE has trouble directly removing the expando
-				// but it's ok with using removeAttribute
-				if ( elem.removeAttribute )
-					elem.removeAttribute( expando );
-			}
-
-			// Completely remove the data cache
-			delete jQuery.cache[ id ];
-		}
-	},
-
 	// args is for internal usage only
 	each: function( object, callback, args ) {
 		var name, i = 0, length = object.length;
diff --git a/src/fx.js b/src/fx.js
index 794b96f..ae472ef 100644
--- a/src/fx.js
+++ b/src/fx.js
@@ -137,27 +137,6 @@ jQuery.fn.extend({
 		});
 	},
 
-	queue: function(type, fn){
-		if ( jQuery.isFunction(type) || jQuery.isArray(type) ) {
-			fn = type;
-			type = "fx";
-		}
-
-		if ( !type || (typeof type === "string" && !fn) )
-			return queue( this[0], type );
-
-		return this.each(function(){
-			if ( jQuery.isArray(fn) )
-				queue(this, type, fn);
-			else {
-				queue(this, type).push( fn );
-
-				if ( queue(this, type).length == 1 )
-					fn.call(this);
-			}
-		});
-	},
-
 	stop: function(clearQueue, gotoEnd){
 		var timers = jQuery.timers;
 
@@ -197,33 +176,6 @@ jQuery.each({
 	};
 });
 
-var queue = function( elem, type, array ) {
-	if ( elem ){
-
-		type = type || "fx";
-
-		var q = jQuery.data( elem, type + "queue" );
-
-		if ( !q || array )
-			q = jQuery.data( elem, type + "queue", jQuery.makeArray(array) );
-
-	}
-	return q;
-};
-
-jQuery.fn.dequeue = function(type){
-	type = type || "fx";
-
-	return this.each(function(){
-		var q = queue(this, type);
-
-		q.shift();
-
-		if ( q.length )
-			q[0].call( this );
-	});
-};
-
 jQuery.extend({
 
 	speed: function(speed, easing, fn) {
diff --git a/test/index.html b/test/index.html
index 6409ee1..9a0eccb 100644
--- a/test/index.html
+++ b/test/index.html
@@ -15,6 +15,7 @@
 	<script type="text/javascript" src="qunit/testrunner.js"></script>
 	<script type="text/javascript" src="data/testrunner.js"></script>
 	<script type="text/javascript" src="unit/core.js"></script>
+	<script type="text/javascript" src="unit/data.js"></script>
 	<script type="text/javascript" src="unit/dimensions.js"></script>
 	<script type="text/javascript" src="unit/selector.js"></script>
 	<script type="text/javascript" src="unit/event.js"></script>
diff --git a/test/unit/core.js b/test/unit/core.js
index 5d2f5f4..1f0850c 100644
--- a/test/unit/core.js
+++ b/test/unit/core.js
@@ -1578,100 +1578,6 @@ test("jQuery.className", function() {
 	ok( c.has(x, "bar"), "Check has2" );
 });
 
-test("jQuery.data", function() {
-	expect(5);
-	var div = jQuery("#foo")[0];
-	equals( jQuery.data(div, "test"), undefined, "Check for no data exists" );
-	jQuery.data(div, "test", "success");
-	equals( jQuery.data(div, "test"), "success", "Check for added data" );
-	jQuery.data(div, "test", "overwritten");
-	equals( jQuery.data(div, "test"), "overwritten", "Check for overwritten data" );
-	jQuery.data(div, "test", undefined);
-	equals( jQuery.data(div, "test"), "overwritten", "Check that data wasn't removed");
-	jQuery.data(div, "test", null);
-	ok( jQuery.data(div, "test") === null, "Check for null data");
-});
-
-test(".data()", function() {
-	expect(18);
-	var div = jQuery("#foo");
-	equals( div.data("test"), undefined, "Check for no data exists" );
-	div.data("test", "success");
-	equals( div.data("test"), "success", "Check for added data" );
-	div.data("test", "overwritten");
-	equals( div.data("test"), "overwritten", "Check for overwritten data" );
-	div.data("test", undefined);
-	equals( div.data("test"), "overwritten", "Check that data wasn't removed");
-	div.data("test", null);
-	ok( div.data("test") === null, "Check for null data");
-
-	div.data("test", "overwritten");
-	var hits = {test:0}, gets = {test:0};
-
-	div
-		.bind("setData",function(e,key,value){ hits[key] += value; })
-		.bind("setData.foo",function(e,key,value){ hits[key] += value; })
-		.bind("getData",function(e,key){ gets[key] += 1; })
-		.bind("getData.foo",function(e,key){ gets[key] += 3; });
-
-	div.data("test.foo", 2);
-	equals( div.data("test"), "overwritten", "Check for original data" );
-	equals( div.data("test.foo"), 2, "Check for namespaced data" );
-	equals( div.data("test.bar"), "overwritten", "Check for unmatched namespace" );
-	equals( hits.test, 2, "Check triggered setter functions" );
-	equals( gets.test, 5, "Check triggered getter functions" );
-
-	hits.test = 0;
-	gets.test = 0;
-
-	div.data("test", 1);
-	equals( div.data("test"), 1, "Check for original data" );
-	equals( div.data("test.foo"), 2, "Check for namespaced data" );
-	equals( div.data("test.bar"), 1, "Check for unmatched namespace" );
-	equals( hits.test, 1, "Check triggered setter functions" );
-	equals( gets.test, 5, "Check triggered getter functions" );
-
-	hits.test = 0;
-	gets.test = 0;
-
-	div
-		.bind("getData",function(e,key){ return key + "root"; })
-		.bind("getData.foo",function(e,key){ return key + "foo"; });
-
-	equals( div.data("test"), "testroot", "Check for original data" );
-	equals( div.data("test.foo"), "testfoo", "Check for namespaced data" );
-	equals( div.data("test.bar"), "testroot", "Check for unmatched namespace" );
-});
-
-test("jQuery.removeData", function() {
-	expect(1);
-	var div = jQuery("#foo")[0];
-	jQuery.data(div, "test", "testing");
-	jQuery.removeData(div, "test");
-	equals( jQuery.data(div, "test"), undefined, "Check removal of data" );
-});
-
-test(".removeData()", function() {
-	expect(6);
-	var div = jQuery("#foo");
-	div.data("test", "testing");
-	div.removeData("test");
-	equals( div.data("test"), undefined, "Check removal of data" );
-
-	div.data("test", "testing");
-	div.data("test.foo", "testing2");
-	div.removeData("test.bar");
-	equals( div.data("test.foo"), "testing2", "Make sure data is intact" );
-	equals( div.data("test"), "testing", "Make sure data is intact" );
-
-	div.removeData("test");
-	equals( div.data("test.foo"), "testing2", "Make sure data is intact" );
-	equals( div.data("test"), undefined, "Make sure data is intact" );
-
-	div.removeData("test.foo");
-	equals( div.data("test.foo"), undefined, "Make sure data is intact" );
-});
-
 test("remove()", function() {
 	expect(6);
 	jQuery("#ap").children().remove();
diff --git a/test/unit/data.js b/test/unit/data.js
new file mode 100644
index 0000000..fa56891
--- /dev/null
+++ b/test/unit/data.js
@@ -0,0 +1,160 @@
+module("data");
+
+test("jQuery.data", function() {
+	expect(5);
+	var div = jQuery("#foo")[0];
+	equals( jQuery.data(div, "test"), undefined, "Check for no data exists" );
+	jQuery.data(div, "test", "success");
+	equals( jQuery.data(div, "test"), "success", "Check for added data" );
+	jQuery.data(div, "test", "overwritten");
+	equals( jQuery.data(div, "test"), "overwritten", "Check for overwritten data" );
+	jQuery.data(div, "test", undefined);
+	equals( jQuery.data(div, "test"), "overwritten", "Check that data wasn't removed");
+	jQuery.data(div, "test", null);
+	ok( jQuery.data(div, "test") === null, "Check for null data");
+});
+
+test(".data()", function() {
+	expect(22);
+	var div = jQuery("#foo");
+	equals( div.data("test"), undefined, "Check for no data exists" );
+	div.data("test", "success");
+	equals( div.data("test"), "success", "Check for added data" );
+	div.data("test", "overwritten");
+	equals( div.data("test"), "overwritten", "Check for overwritten data" );
+	div.data("test", undefined);
+	equals( div.data("test"), "overwritten", "Check that data wasn't removed");
+	div.data("test", null);
+	ok( div.data("test") === null, "Check for null data");
+
+	div.data("test", "overwritten");
+	var hits = {test:0}, gets = {test:0};
+
+	div
+		.bind("setData",function(e,key,value){ hits[key] += value; })
+		.bind("setData.foo",function(e,key,value){ hits[key] += value; })
+		.bind("getData",function(e,key){ gets[key] += 1; })
+		.bind("getData.foo",function(e,key){ gets[key] += 3; });
+
+	div.data("test.foo", 2);
+	equals( div.data("test"), "overwritten", "Check for original data" );
+	equals( div.data("test.foo"), 2, "Check for namespaced data" );
+	equals( div.data("test.bar"), "overwritten", "Check for unmatched namespace" );
+	equals( hits.test, 2, "Check triggered setter functions" );
+	equals( gets.test, 5, "Check triggered getter functions" );
+
+	hits.test = 0;
+	gets.test = 0;
+
+	div.data("test", 1);
+	equals( div.data("test"), 1, "Check for original data" );
+	equals( div.data("test.foo"), 2, "Check for namespaced data" );
+	equals( div.data("test.bar"), 1, "Check for unmatched namespace" );
+	equals( hits.test, 1, "Check triggered setter functions" );
+	equals( gets.test, 5, "Check triggered getter functions" );
+
+	hits.test = 0;
+	gets.test = 0;
+
+	div
+		.bind("getData",function(e,key){ return key + "root"; })
+		.bind("getData.foo",function(e,key){ return key + "foo"; });
+
+	equals( div.data("test"), "testroot", "Check for original data" );
+	equals( div.data("test.foo"), "testfoo", "Check for namespaced data" );
+	equals( div.data("test.bar"), "testroot", "Check for unmatched namespace" );
+	
+	// #3748
+	var $elem = jQuery({});
+	equals( $elem.data('nothing'), undefined, "Non-existent data returns undefined");
+	equals( $elem.data('null',null).data('null'), null, "null's are preserved");
+	equals( $elem.data('emptyString','').data('emptyString'), '', "Empty strings are preserved");
+	equals( $elem.data('false',false).data('false'), false, "false's are preserved");
+	
+	// Clean up
+	$elem.removeData();
+});
+
+test("jQuery.removeData", function() {
+	expect(1);
+	var div = jQuery("#foo")[0];
+	jQuery.data(div, "test", "testing");
+	jQuery.removeData(div, "test");
+	equals( jQuery.data(div, "test"), undefined, "Check removal of data" );
+});
+
+test(".removeData()", function() {
+	expect(6);
+	var div = jQuery("#foo");
+	div.data("test", "testing");
+	div.removeData("test");
+	equals( div.data("test"), undefined, "Check removal of data" );
+
+	div.data("test", "testing");
+	div.data("test.foo", "testing2");
+	div.removeData("test.bar");
+	equals( div.data("test.foo"), "testing2", "Make sure data is intact" );
+	equals( div.data("test"), "testing", "Make sure data is intact" );
+
+	div.removeData("test");
+	equals( div.data("test.foo"), "testing2", "Make sure data is intact" );
+	equals( div.data("test"), undefined, "Make sure data is intact" );
+
+	div.removeData("test.foo");
+	equals( div.data("test.foo"), undefined, "Make sure data is intact" );
+});
+
+test("queue() defaults to 'fx' type", function () {
+	expect(2);
+	stop();
+
+	var $foo = jQuery("#foo");
+	$foo.queue("fx", [ "sample", "array" ]);
+	var arr = $foo.queue();
+	isSet(arr, [ "sample", "array" ], "queue() got an array set with type 'fx'");
+	$foo.queue([ "another", "one" ]);
+	var arr = $foo.queue("fx");
+	isSet(arr, [ "another", "one" ], "queue('fx') got an array set with no type");
+	// clean up after test
+	$foo.queue([]);
+
+	start();
+});
+
+test("queue() with other types",function() {
+	expect(9);
+	var counter = 0;
+	
+	var $div = jQuery({});
+	
+	$div
+		.queue('foo',function(){
+			equals( ++counter, 1, "Dequeuing" );
+			jQuery.dequeue(this,'foo');
+		})
+		.queue('foo',function(){
+			equals( ++counter, 2, "Dequeuing" );
+			jQuery(this).dequeue('foo');
+		})
+		.queue('foo',function(){
+			equals( ++counter, 3, "Dequeuing" );
+		})
+		.queue('foo',function(){
+			equals( ++counter, 4, "Dequeuing" );
+		});
+		
+	equals( $div.queue('foo').length, 4, "Testing queue length" );
+	
+	$div.dequeue('foo');
+	
+	equals( counter, 3, "Testing previous call to dequeue" );
+	equals( $div.queue('foo').length, 1, "Testing queue length" );
+	
+	$div.dequeue('foo');
+	
+	equals( counter, 4, "Testing previous call to dequeue" );
+	equals( $div.queue('foo').length, 0, "Testing queue length" );
+	
+	// Clean up
+	$div.removeData();
+})
diff --git a/test/unit/fx.js b/test/unit/fx.js
index 8af9297..2ee3d30 100644
--- a/test/unit/fx.js
+++ b/test/unit/fx.js
@@ -34,23 +34,6 @@ test("animate option (queue === false)", function () {
 	});
 });
 
-test("queue() defaults to 'fx' type", function () {
-	expect(2);
-	stop();
-
-	var $foo = jQuery("#foo");
-	$foo.queue("fx", [ "sample", "array" ]);
-	var arr = $foo.queue();
-	isSet(arr, [ "sample", "array" ], "queue() got an array set with type 'fx'");
-	$foo.queue([ "another", "one" ]);
-	var arr = $foo.queue("fx");
-	isSet(arr, [ "another", "one" ], "queue('fx') got an array set with no type");
-	// clean up after test
-	$foo.queue([]);
-
-	start();
-});
-
 test("stop()", function() {
 	expect(3);
 	stop();
-- 
1.7.10.4