Index: wp-includes/js/wp-lists.js
===================================================================
--- wp-includes/js/wp-lists.js	(revision 6301)
+++ wp-includes/js/wp-lists.js	(working copy)
@@ -13,11 +13,20 @@
 		}
 		return r;
 	},
-	parseAjaxResponse: function( x, r ) { // 1 = good, 0 = strange (bad data?), -1 = you lack permission
+	parseAjaxResponse: function( x, r, e ) { // 1 = good, 0 = strange (bad data?), -1 = you lack permission
 		var re = $('#' + r).html('');
 		if ( x && typeof x == 'object' && x.getElementsByTagName('wp_ajax') ) {
-			if ( $('wp_error', x).each( function() { re.append('<p>' + this.firstChild.nodeValue + '</p>'); } ).size() ) {
-				return !re.wrap( '<div class="error"></div>' );
+			var errs = $('wp_error', x);
+			if ( errs.size() ) {
+				var err = '';
+				errs.each( function() {
+					var code = $(this).attr('code');
+					if ( formField = $('wp_error_data[@code="' + code + '"] form-field', x).text() )
+						code = formField;
+					wpAjax.invalidateForm( $('#' + e + ' :input[@name="' + code + '"]' ).parents('.form-field:first') );
+					err += '<p>' + this.firstChild.nodeValue + '</p>';
+				} );
+				return !re.html( '<div class="error">' + err + '</div>' );
 			}
 			return true;
 		}
@@ -26,6 +35,9 @@
 		if ( -1 == x ) { return !re.html('<div class="error"><p>You do not have permission to do that.</p></div>'); }
 		else if ( 0 === x ) { return !re.html('<div class="error"><p>AJAX is teh b0rked.</p></div>'); }
 		return true;
+	},
+	invalidateForm: function( jQ ) {
+		jQ.addClass( 'form-invalid' ).change( function() { $(this).removeClass( 'form-invalid' ); } );
 	}
 };
 
@@ -91,6 +103,12 @@
 		s.nonce = wpList.nonce(e,s);
 
 		var es = $('#' + s.element + ' :input').not('[@name=_ajax_nonce], [@name=_wpnonce], [@name=action]');
+		var required = $('#' + s.element + ' .form-required:has(:input[@value=""]), #' + s.element + ' .form-required:input[@value=""]');
+		if ( required.size() ) {
+			wpAjax.invalidateForm( required );
+			return false;
+		}
+
 		s.data = $.param( $.extend( { _ajax_nonce: s.nonce, action: s.action }, wpAjax.unserialize( cls[4] || '' ) ) );
 		var formData = $.isFunction(es.fieldSerialize) ? es.fieldSerialize() : es.serialize();
 		if ( formData ) { s.data += '&' + formData; }
@@ -102,7 +120,7 @@
 		if ( !s.data.match(/_ajax_nonce=[a-f0-9]+/) ) { return true; }
 
 		s.success = function(r) {
-			if ( !wpAjax.parseAjaxResponse(r, s.response) ) { return false; }
+			if ( !wpAjax.parseAjaxResponse(r, s.response, s.element) ) { return false; }
 
 			$(s.what + ' response_data', r).each( function() {
 				var t = $(this);
@@ -164,7 +182,7 @@
 		}
 
 		s.success = function(r) {
-			if ( !wpAjax.parseAjaxResponse(r, s.response) ) {
+			if ( !wpAjax.parseAjaxResponse(r, s.response, s.element) ) {
 				clearTimeout(hideTO);
 				func = function() { $('#' + s.element).css( 'background-color', '#FF3333' ).show(); list.wpList.recolor(); };
 				func(); setTimeout(func, 705); // In case it's still fading
@@ -218,7 +236,7 @@
 		var dimTO = setTimeout( function() { $('#' + s.element).css( 'background-color', '' ); }, 705 );
 
 		s.success = function(r) {
-			if ( !wpAjax.parseAjaxResponse(r, s.response) ) {
+			if ( !wpAjax.parseAjaxResponse(r, s.response, s.element) ) {
 				clearTimeout(dimTO);
 				func = function() { $('#' + s.element).css( 'background-color', '#FF3333' )[isClass?'removeClass':'addClass'](s.dimClass); };
 				func(); setTimeout(func, 705);
Index: wp-includes/classes.php
===================================================================
--- wp-includes/classes.php	(revision 6301)
+++ wp-includes/classes.php	(working copy)
@@ -710,11 +710,31 @@
 		}
 
 		$response = '';
-		if ( is_wp_error($data) )
-			foreach ( $data->get_error_codes() as $code )
+		if ( is_wp_error($data) ) {
+			foreach ( $data->get_error_codes() as $code ) { 
 				$response .= "<wp_error code='$code'><![CDATA[" . $data->get_error_message($code) . "]]></wp_error>";
-		else
+				if ( !$error_data = $data->get_error_data($code) )
+					continue;
+				$class = '';
+				if ( is_object($error_data) ) {
+					$class = ' class="' . get_class($error_data) . '"';
+					$error_data = get_object_vars($error_data);
+				}
+
+				$response .= "<wp_error_data code='$code'$class>";
+
+				if ( is_scalar($error_data) ) {
+					$response .= "<![CDATA[$v]]>";
+				} elseif ( is_array($error_data) ) {
+					foreach ( $error_data as $k => $v )
+						$response .= "<$k><![CDATA[$v]]></$k>";
+				}
+
+				$response .= "</wp_error_data>";
+			}
+		} else {
 			$response = "<response_data><![CDATA[$data]]></response_data>";
+		}
 
 		$s = '';
 		if ( (array) $supplemental )
Index: wp-includes/script-loader.php
===================================================================
--- wp-includes/script-loader.php	(revision 6301)
+++ wp-includes/script-loader.php	(working copy)
@@ -61,7 +61,7 @@
 			'delText' => __('Are you sure you want to delete this %thing%?')
 		) );
 
-		$this->add( 'wp-lists', '/wp-includes/js/wp-lists.js', array('jquery'), '20071023' );
+		$this->add( 'wp-lists', '/wp-includes/js/wp-lists.js', array('jquery'), '20071101' );
 		$this->localize( 'wp-lists', 'wpListL10n', array(
 			'url' => get_option( 'siteurl' ) . '/wp-admin/admin-ajax.php'
 		) );
@@ -110,7 +110,7 @@
 					'toggleKey' => __(', or press the enter key to %toggle% it'),
 				) );
 			}
-			$this->add( 'ajaxcat', '/wp-admin/js/cat.js', array( 'wp-lists' ), '20070823' );
+			$this->add( 'ajaxcat', '/wp-admin/js/cat.js', array( 'wp-lists' ), '20071101' );
 			$this->localize( 'ajaxcat', 'catL10n', array(
 				'add' => attribute_escape(__('Add')),
 				'how' => __('Separate multiple categories with commas.')
Index: wp-admin/users.php
===================================================================
--- wp-admin/users.php	(revision 6301)
+++ wp-admin/users.php	(working copy)
@@ -454,34 +454,34 @@
 	if ( get_option('users_can_register') )
 		echo '<p>' . sprintf(__('Users can <a href="%1$s">register themselves</a> or you can manually create users here.'), get_option('siteurl').'/wp-register.php') . '</p>';
 	else
-        echo '<p>' . sprintf(__('Users cannot currently <a href="%1$s">register themselves</a>, but you can manually create users here.'), get_option('siteurl').'/wp-admin/options-general.php#users_can_register') . '</p>';
+	        echo '<p>' . sprintf(__('Users cannot currently <a href="%1$s">register themselves</a>, but you can manually create users here.'), get_option('siteurl').'/wp-admin/options-general.php#users_can_register') . '</p>';
 ?>
 <form action="#add-new-user" method="post" name="adduser" id="adduser" class="add:user-list:">
 <?php wp_nonce_field('add-user') ?>
 <table class="editform" width="100%" cellspacing="2" cellpadding="5">
-	<tr>
+	<tr class="form-field form-required">
 		<th scope="row" width="33%"><?php _e('Username (required)') ?><input name="action" type="hidden" id="action" value="adduser" /></th>
 		<td width="66%"><input name="user_login" type="text" id="user_login" value="<?php echo $new_user_login; ?>" /></td>
 	</tr>
-	<tr>
+	<tr class="form-field">
 		<th scope="row"><?php _e('First Name') ?> </th>
 		<td><input name="first_name" type="text" id="first_name" value="<?php echo $new_user_firstname; ?>" /></td>
 	</tr>
-	<tr>
+	<tr class="form-field">
 		<th scope="row"><?php _e('Last Name') ?> </th>
 		<td><input name="last_name" type="text" id="last_name" value="<?php echo $new_user_lastname; ?>" /></td>
 	</tr>
-	<tr>
+	<tr class="form-field form-required">
 		<th scope="row"><?php _e('E-mail (required)') ?></th>
 		<td><input name="email" type="text" id="email" value="<?php echo $new_user_email; ?>" /></td>
 	</tr>
-	<tr>
+	<tr class="form-field">
 		<th scope="row"><?php _e('Website') ?></th>
 		<td><input name="url" type="text" id="url" value="<?php echo $new_user_uri; ?>" /></td>
 	</tr>
 
 <?php if ( apply_filters('show_password_fields', true) ) : ?>
-	<tr>
+	<tr class="form-field form-required">
 		<th scope="row"><?php _e('Password (twice)') ?> </th>
 		<td><input name="pass1" type="password" id="pass1" />
 		<br />
@@ -489,7 +489,7 @@
 	</tr>
 <?php endif; ?>
 
-	<tr>
+	<tr class="form-field">
 		<th scope="row"><?php _e('Role'); ?></th>
 		<td><select name="role" id="role">
 			<?php
Index: wp-admin/admin-ajax.php
===================================================================
--- wp-admin/admin-ajax.php	(revision 6301)
+++ wp-admin/admin-ajax.php	(working copy)
@@ -147,10 +147,10 @@
 	$x = new WP_Ajax_Response();
 	foreach ( $names as $cat_name ) {
 		$cat_name = trim($cat_name);
-		if ( !$category_nicename = sanitize_title($cat_name) )
-			die('0');
-		if ( !$cat_id = category_exists( $cat_name ) )
-			$cat_id = wp_create_category( $cat_name );
+		$category_nicename = sanitize_title($cat_name);
+		if ( '' === $category_nicename )
+			continue;
+		$cat_id = wp_create_category( $cat_name );
 		$cat_name = wp_specialchars(stripslashes($cat_name));
 		$x->add( array(
 			'what' => 'category',
@@ -169,8 +169,9 @@
 	$x = new WP_Ajax_Response();
 	foreach ( $names as $cat_name ) {
 		$cat_name = trim($cat_name);
-		if ( !$slug = sanitize_title($cat_name) )
-			die('0');
+		$slug = sanitize_title($cat_name);
+		if ( '' === $slug )
+			continue;
 		if ( !$cat_id = is_term( $cat_name, 'link_category' ) ) {
 			$cat_id = wp_insert_term( $cat_name, 'link_category' );
 		}
@@ -189,6 +190,15 @@
 	check_ajax_referer( 'add-category' );
 	if ( !current_user_can( 'manage_categories' ) )
 		die('-1');
+
+	if ( '' === trim($_POST['cat_name']) ) {
+		$x = new WP_Ajax_Response( array(
+			'what' => 'cat',
+			'id' => new WP_Error( 'cat_name', __('You did not enter a category name.') )
+		) );
+		$x->send();
+	}
+
 	if ( !$cat = wp_insert_category( $_POST ) )
 		die('0');
 	if ( !$cat = get_category( $cat ) )
@@ -216,6 +226,14 @@
 	if ( !current_user_can( 'manage_categories' ) )
 		die('-1');
 
+	if ( '' === trim($_POST['name']) ) {
+		$x = new WP_Ajax_Response( array(
+			'what' => 'link-cat',
+			'id' => new WP_Error( 'name', __('You did not enter a category name.') )
+		) );
+		$x->send();
+	}
+
 	$r = wp_insert_term($_POST['name'], 'link_category', $_POST );
 	if ( is_wp_error( $r ) ) {
 		$x = new WP_AJAX_Response( array(
@@ -270,6 +288,8 @@
 	if ( isset($_POST['addmeta']) ) {
 		if ( !current_user_can( 'edit_post', $pid ) )
 			die('-1');
+		if ( '#NONE#' == $_POST['metakeyselect'] && empty($_POST['metakeyinput']) )
+			die('1');
 		if ( $pid < 0 ) {
 			$now = current_time('timestamp', 1);
 			if ( $pid = wp_insert_post( array(
@@ -334,9 +354,11 @@
 	if ( !$user_id = add_user() )
 		die('0');
 	elseif ( is_wp_error( $user_id ) ) {
-		foreach( $user_id->get_error_messages() as $message )
-			echo "<p>$message<p>";
-		exit;
+		$x = new WP_Ajax_Response( array(
+			'what' => 'user',
+			'id' => $user_id
+		) );
+		$x->send();
 	}
 	$user_object = new WP_User( $user_id );
 
Index: wp-admin/wp-admin.css
===================================================================
--- wp-admin/wp-admin.css	(revision 6301)
+++ wp-admin/wp-admin.css	(working copy)
@@ -184,6 +184,10 @@
 	border: 1px solid #686868;
 }
 
+.form-invalid {
+	background-color: #FF9999 !important;
+}
+
 label {
 	cursor: pointer;
 }
Index: wp-admin/includes/user.php
===================================================================
--- wp-admin/includes/user.php	(revision 6301)
+++ wp-admin/includes/user.php	(working copy)
@@ -82,21 +82,25 @@
 	/* checking the password has been typed twice */
 	do_action_ref_array( 'check_passwords', array ( $user->user_login, & $pass1, & $pass2 ));
 
-	if (!$update ) {
-		if ( $pass1 == '' || $pass2 == '' )
-			$errors->add( 'pass', __( '<strong>ERROR</strong>: Please enter your password twice.' ));
+	if ( $update ) {
+		if ( empty($pass1) && !empty($pass2) )
+			$errors->add( 'pass', __( '<strong>ERROR</strong>: You entered your new password only once.' ), array( 'form-field' => 'pass1' ) );
+		elseif ( !empty($pass1) && empty($pass2) )
+			$errors->add( 'pass', __( '<strong>ERROR</strong>: You entered your new password only once.' ), array( 'form-field' => 'pass2' ) );
 	} else {
-		if ((empty ( $pass1 ) && !empty ( $pass2 ) ) || (empty ( $pass2 ) && !empty ( $pass1 ) ) )
-			$errors->add( 'pass', __( '<strong>ERROR</strong>: You entered your new password only once.' ));
+		if ( empty($pass1) )
+			$errors->add( 'pass', __( '<strong>ERROR</strong>: Please enter your password.' ), array( 'form-field' => 'pass1' ) );
+		elseif ( empty($pass2) )
+			$errors->add( 'pass', __( '<strong>ERROR</strong>: Please enter your password twice.' ), array( 'form-field' => 'pass2' ) );
 	}
 
 	/* Check for "\" in password */
 	if( strpos( " ".$pass1, "\\" ) )
-		$errors->add( 'pass', __( '<strong>ERROR</strong>: Passwords may not contain the character "\\".' ));
+		$errors->add( 'pass', __( '<strong>ERROR</strong>: Passwords may not contain the character "\\".' ), array( 'form-field' => 'pass1' ) );
 
 	/* checking the password has been typed twice the same */
 	if ( $pass1 != $pass2 )
-		$errors->add( 'pass', __( '<strong>ERROR</strong>: Please enter the same password in the two password fields.' ));
+		$errors->add( 'pass', __( '<strong>ERROR</strong>: Please enter the same password in the two password fields.' ), array( 'form-field' => 'pass1' ) );
 
 	if (!empty ( $pass1 ))
 		$user->user_pass = $pass1;
@@ -109,10 +113,10 @@
 
 	/* checking e-mail address */
 	if ( empty ( $user->user_email ) ) {
-		$errors->add( 'user_email', __( '<strong>ERROR</strong>: Please enter an e-mail address.' ));
+		$errors->add( 'user_email', __( '<strong>ERROR</strong>: Please enter an e-mail address.' ), array( 'form-field' => 'email' ) );
 	} else
 		if (!is_email( $user->user_email ) ) {
-			$errors->add( 'user_email', __( "<strong>ERROR</strong>: The e-mail address isn't correct." ));
+			$errors->add( 'user_email', __( "<strong>ERROR</strong>: The e-mail address isn't correct." ), array( 'form-field' => 'email' ) );
 		}
 
 	if ( $errors->get_error_codes() )
Index: wp-admin/js/cat.js
===================================================================
--- wp-admin/js/cat.js	(revision 6301)
+++ wp-admin/js/cat.js	(working copy)
@@ -1,4 +1,5 @@
 jQuery( function($) {
+	var myConfirm = function() { return '' !== $('#newcat').val(); };
 	$('#jaxcat').prepend('<span id="ajaxcat"><input type="text" name="newcat" id="newcat" size="16" autocomplete="off"/><input type="button" name="Button" class="add:categorychecklist:jaxcat" id="catadd" value="' + catL10n.add + '"/><input type="hidden"/><input type="hidden"/><span id="howto">' + catL10n.how + '</span></span><span id="cat-ajax-response"></span>')
-	var a = $('#categorychecklist').wpList( { alt: '', response: 'cat-ajax-response' } );
+	$('#categorychecklist').wpList( { alt: '', response: 'cat-ajax-response', confirm: myConfirm } );
 } );
Index: wp-admin/edit-link-category-form.php
===================================================================
--- wp-admin/edit-link-category-form.php	(revision 6301)
+++ wp-admin/edit-link-category-form.php	(working copy)
@@ -24,15 +24,15 @@
 <input type="hidden" name="cat_ID" value="<?php echo $category->term_id ?>" />
 <?php wp_nonce_field($nonce_action); ?>
 	<table class="editform" width="100%" cellspacing="2" cellpadding="5">
-		<tr>
+		<tr class="form-field form-required">
 			<th width="33%" scope="row" valign="top"><label for="name"><?php _e('Category name:') ?></label></th>
 			<td width="67%"><input name="name" id="name" type="text" value="<?php echo $category->name; ?>" size="40" /></td>
 		</tr>
-		<tr>
+		<tr class="form-field">
 			<th scope="row" valign="top"><label for="slug"><?php _e('Category slug:') ?></label></th>
 			<td><input name="slug" id="slug" type="text" value="<?php echo $category->slug; ?>" size="40" /></td>
 		</tr>
-		<tr>
+		<tr class="form-field">
 			<th scope="row" valign="top"><label for="description"><?php _e('Description: (optional)') ?></label></th>
 			<td><textarea name="description" id="description" rows="5" cols="50" style="width: 97%;"><?php echo $category->description; ?></textarea></td>
 		</tr>
Index: wp-admin/edit-category-form.php
===================================================================
--- wp-admin/edit-category-form.php	(revision 6301)
+++ wp-admin/edit-category-form.php	(working copy)
@@ -24,21 +24,21 @@
 <input type="hidden" name="cat_ID" value="<?php echo $category->term_id ?>" />
 <?php wp_nonce_field($nonce_action); ?>
 	<table class="editform" width="100%" cellspacing="2" cellpadding="5">
-		<tr>
+		<tr class="form-field form-required">
 			<th width="33%" scope="row" valign="top"><label for="cat_name"><?php _e('Category name:') ?></label></th>
 			<td width="67%"><input name="cat_name" id="cat_name" type="text" value="<?php echo attribute_escape($category->name); ?>" size="40" /></td>
 		</tr>
-		<tr>
+		<tr class="form-field">
 			<th scope="row" valign="top"><label for="category_nicename"><?php _e('Category slug:') ?></label></th>
 			<td><input name="category_nicename" id="category_nicename" type="text" value="<?php echo attribute_escape($category->slug); ?>" size="40" /></td>
 		</tr>
-		<tr>
+		<tr class="form-field">
 			<th scope="row" valign="top"><label for="category_parent"><?php _e('Category parent:') ?></label></th>
 			<td>
 	  			<?php wp_dropdown_categories('hide_empty=0&name=category_parent&orderby=name&selected=' . $category->parent . '&hierarchical=1&show_option_none=' . __('None')); ?>
 	  		</td>
 		</tr>
-		<tr>
+		<tr class="form-field">
 			<th scope="row" valign="top"><label for="category_description"><?php _e('Description: (optional)') ?></label></th>
 			<td><textarea name="category_description" id="category_description" rows="5" cols="50" style="width: 97%;"><?php echo wp_specialchars($category->description); ?></textarea></td>
 		</tr>

