Index: tests/qunit/index.html
===================================================================
--- tests/qunit/index.html	(revision 25763)
+++ tests/qunit/index.html	(working copy)
@@ -13,9 +13,11 @@
   <!-- Tested files -->
   <script src="../../src/wp-includes/js/zxcvbn.min.js"></script>
   <script src="../../src/wp-admin/js/password-strength-meter.js"></script>
+  <script src="../../src/wp-admin/js/post.js"></script>
 
   <!-- Unit tests -->
   <script src="wp-admin/js/password-strength-meter.js"></script>
+  <script src="wp-admin/js/post.js"></script>
 
 </head>
 <body>
Index: src/wp-admin/includes/taxonomy.php
===================================================================
--- src/wp-admin/includes/taxonomy.php	(revision 25763)
+++ src/wp-admin/includes/taxonomy.php	(working copy)
@@ -229,8 +229,13 @@
 	if ( is_wp_error($tags) )
 		return $tags;
 
-	foreach ( $tags as $tag )
-		$tag_names[] = $tag->name;
+	foreach ( $tags as $tag ) {
+		if ( strpos( $tag->name, ',' ) !== false )
+			$tag_names[] = '"' . $tag->name . '"';
+		else
+			$tag_names[] = $tag->name;
+	}
+
 	$tags_to_edit = join( ',', $tag_names );
 	$tags_to_edit = esc_attr( $tags_to_edit );
 	$tags_to_edit = apply_filters( 'terms_to_edit', $tags_to_edit, $taxonomy );
Index: src/wp-admin/includes/meta-boxes.php
===================================================================
--- src/wp-admin/includes/meta-boxes.php	(revision 25763)
+++ src/wp-admin/includes/meta-boxes.php	(working copy)
@@ -364,7 +364,7 @@
 	<div class="jaxtag">
 	<div class="nojs-tags hide-if-js">
 	<p><?php echo $taxonomy->labels->add_or_remove_items; ?></p>
-	<textarea name="<?php echo "tax_input[$tax_name]"; ?>" rows="3" cols="20" class="the-tags" id="tax-input-<?php echo $tax_name; ?>" <?php disabled( ! $user_can_assign_terms ); ?>><?php echo str_replace( ',', $comma . ' ', get_terms_to_edit( $post->ID, $tax_name ) ); // textarea_escaped by esc_attr() ?></textarea></div>
+	<textarea name="<?php echo "tax_input[$tax_name]"; ?>" rows="3" cols="20" class="the-tags" id="tax-input-<?php echo $tax_name; ?>" <?php disabled( ! $user_can_assign_terms ); ?>><?php echo get_terms_to_edit( $post->ID, $tax_name ); // textarea_escaped by esc_attr() ?></textarea></div>
  	<?php if ( $user_can_assign_terms ) : ?>
 	<div class="ajaxtag hide-if-no-js">
 		<label class="screen-reader-text" for="new-tag-<?php echo $tax_name; ?>"><?php echo $box['title']; ?></label>
Index: src/wp-admin/js/post.js
===================================================================
--- src/wp-admin/js/post.js	(revision 25763)
+++ src/wp-admin/js/post.js	(working copy)
@@ -14,98 +14,89 @@
 (function($){
 
 tagBox = {
-	clean : function(tags) {
-		var comma = postL10n.comma;
-		if ( ',' !== comma )
-			tags = tags.replace(new RegExp(comma, 'g'), ',');
-		tags = tags.replace(/\s*,\s*/g, ',').replace(/,+/g, ',').replace(/[,\s]+$/, '').replace(/^[,\s]+/, '');
-		if ( ',' !== comma )
-			tags = tags.replace(/,/g, comma);
-		return tags;
-	},
 
-	parseTags : function(el) {
-		var id = el.id, num = id.split('-check-num-')[1], taxbox = $(el).closest('.tagsdiv'),
-			thetags = taxbox.find('.the-tags'), comma = postL10n.comma,
-			current_tags = thetags.val().split(comma), new_tags = [];
-		delete current_tags[num];
+	quickClicks : function(el) {
+		
+		var thetags = $('.the-tags', el);
+		var current_tags = this.getTagsFromString( thetags.val(), postL10n.comma );
 
-		$.each( current_tags, function(key, val) {
-			val = $.trim(val);
-			if ( val ) {
-				new_tags.push(val);
-			}
-		});
+		thetags.html('');
+		$(el).data( 'tags',[]);
 
-		thetags.val( this.clean( new_tags.join(comma) ) );
-
-		this.quickClicks(taxbox);
-		return false;
+		for (var i = current_tags.length - 1; i >= 0; i--) {
+			this.addTag( $(el), current_tags[i] );
+		}
 	},
 
-	quickClicks : function(el) {
-		var thetags = $('.the-tags', el),
-			tagchecklist = $('.tagchecklist', el),
-			id = $(el).attr('id'),
-			current_tags, disabled;
+	addTag: function( el, tag ) {
+		var span, xbutton, thetags = $('.the-tags', el), disabled, t = this;
 
-		if ( !thetags.length )
+		tag = $.trim(tag)
+		
+		if ( el.data( 'tags' ).indexOf( tag ) > -1 )
 			return;
 
+		el.data( 'tags' ).push( tag )
 		disabled = thetags.prop('disabled');
 
-		current_tags = thetags.val().split(postL10n.comma);
-		tagchecklist.empty();
+		// Create a new span, and ensure the text is properly escaped.
+		span = $('<span />').text( tag );
+		span.append( jQuery( '<input type="hidden" name="' + thetags.attr('name') + '[]" />' ).val( tag ) )
 
-		$.each( current_tags, function( key, val ) {
-			var span, xbutton;
+		// If tags editing isn't disabled, create the X button.
+		if ( ! disabled ) {
+			xbutton = $( '<a class="ntdelbutton">X</a>' );
+			xbutton.click( function() {
+				t.removeTag(el, tag);
+			});
 
-			val = $.trim( val );
+			span.prepend('&nbsp;').prepend( xbutton );
+		}
 
-			if ( ! val )
-				return;
+		el.find('.tagchecklist').append(span);
 
-			// Create a new span, and ensure the text is properly escaped.
-			span = $('<span />').text( val );
+	},
 
-			// If tags editing isn't disabled, create the X button.
-			if ( ! disabled ) {
-				xbutton = $( '<a id="' + id + '-check-num-' + key + '" class="ntdelbutton">X</a>' );
-				xbutton.click( function(){ tagBox.parseTags(this); });
-				span.prepend('&nbsp;').prepend( xbutton );
-			}
+	removeTag: function( el, tag ) {
 
-			// Append the span to the tag list.
-			tagchecklist.append( span );
-		});
+		el.find( '.tagchecklist input[value="' + tag + '"]').remove();
+		delete el.data('tags')[el.data('tags').indexOf(tag)];
 	},
 
-	flushTags : function(el, a, f) {
-		a = a || false;
-		var tags = $('.the-tags', el),
-			newtag = $('input.newtag', el),
-			comma = postL10n.comma,
-			newtags, text;
+	getTagsFromString: function(tags_string, comma) {
 
-		text = a ? $(a).text() : newtag.val();
-		tagsval = tags.val();
-		newtags = tagsval ? tagsval + comma + text : text;
+		// pull out all quoted strings
+		var quoted_tags = tags_string.match( /("|')(.+?)\1/g );
 
-		newtags = this.clean( newtags );
-		newtags = array_unique_noempty( newtags.split(comma) ).join(comma);
-		tags.val(newtags);
-		this.quickClicks(el);
+		if ( quoted_tags ) {
+			for (var i = quoted_tags.length - 1; i >= 0; i--) {
+				tags_string = tags_string.replace( quoted_tags[i], '' );
+				quoted_tags[i] = quoted_tags[i].substr( 1, quoted_tags[i].length - 2 );
+			};
+		}
 
-		if ( !a )
-			newtag.val('');
-		if ( 'undefined' == typeof(f) )
-			newtag.focus();
+		var tags = tags_string.split(comma);
 
-		return false;
+		if ( quoted_tags )
+			return array_unique_noempty( quoted_tags.concat(tags) );
+
+		return array_unique_noempty( tags );
 	},
 
+	submitAddTag: function(el) {
+
+		var newtag = $('input.newtag', el),
+			new_tags = this.getTagsFromString( newtag.val(), postL10n.comma )
+
+		newtag.val('');
+
+		for (var i = new_tags.length - 1; i >= 0; i--) {
+			this.addTag( $(el), new_tags[i] );
+		}
+	},
+
 	get : function(id) {
-		var tax = id.substr(id.indexOf('-')+1);
+		var tax = id.substr(id.indexOf('-')+1), t = this;
 
 		$.post(ajaxurl, {'action':'get-tagcloud', 'tax':tax}, function(r, stat) {
 			if ( 0 == r || 'success' != stat )
@@ -113,7 +104,7 @@
 
 			r = $('<p id="tagcloud-'+tax+'" class="the-tagcloud">'+r+'</p>');
 			$('a', r).click(function(){
-				tagBox.flushTags( $(this).closest('.inside').children('.tagsdiv'), this);
+				t.addTag( $(this).closest('.inside').children('.tagsdiv'), $(this).text() )
 				return false;
 			});
 
@@ -129,7 +120,7 @@
 		});
 
 		$('input.tagadd', ajaxtag).click(function(){
-			t.flushTags( $(this).closest('.tagsdiv') );
+			t.submitAddTag( $(this).closest('.tagsdiv') );
 		});
 
 		$('div.taghint', ajaxtag).click(function(){
@@ -143,7 +134,7 @@
 			$(this).parent().siblings('.taghint').css('visibility', 'hidden');
 		}).keyup(function(e){
 			if ( 13 == e.which ) {
-				tagBox.flushTags( $(this).closest('.tagsdiv') );
+				tagBox.submitAddTag( $(this).closest('.tagsdiv') );
 				return false;
 			}
 		}).keypress(function(e){
@@ -159,7 +150,7 @@
 		// save tags on post save/publish
 		$('#post').submit(function(){
 			$('div.tagsdiv').each( function() {
-				tagBox.flushTags(this, false, 1);
+				t.submitAddTag($(this));
 			});
 		});
 
@@ -353,6 +344,9 @@
 jQuery(document).ready( function($) {
 	var stamp, visibility, sticky = '', last = 0, co = $('#content');
 
+	if ( typeof postboxes == 'undefined' )
+		return
+	
 	postboxes.add_postbox_toggles(pagenow);
 
 	// Post locks: contain focus inside the dialog. If the dialog is shown, focus the first item.
Index: src/wp-includes/js/jquery/suggest.js
===================================================================
--- src/wp-includes/js/jquery/suggest.js	(revision 25763)
+++ src/wp-includes/js/jquery/suggest.js	(working copy)
@@ -244,7 +244,11 @@
 					} else {
 						$currentVal = "";
 					}
-					$input.val( $currentVal + $currentResult.text() + options.multipleSep);
+
+					if ( $currentResult.text().match( jQuery.trim( options.multipleSep ) ) )
+						$input.val( $currentVal + '"' + $currentResult.text() + '"' + options.multipleSep);
+					else
+						$input.val( $currentVal + $currentResult.text() + options.multipleSep);
 					$input.focus();
 				} else {
 					$input.val($currentResult.text());
