Index: /CKEditor/trunk/_source/plugins/dialog/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/dialog/plugin.js	(revision 3230)
+++ /CKEditor/trunk/_source/plugins/dialog/plugin.js	(revision 3231)
@@ -39,4 +39,39 @@
 (function()
 {
+	function isTabVisible( tabId )
+	{
+		return !!this._.tabs[ tabId ][ 0 ].$.offsetHeight;
+	}
+
+	function getPreviousVisibleTab()
+	{
+		var tabId = this._.currentTabId,
+			length = this._.tabIdList.length,
+			tabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, tabId ) + length;
+
+		for ( var i = tabIndex - 1 ; i > tabIndex - length ; i-- )
+		{
+			if ( isTabVisible.call( this, this._.tabIdList[ i % length ] ) )
+				return this._.tabIdList[ i % length ];
+		}
+
+		return null;
+	}
+
+	function getNextVisibleTab()
+	{
+		var tabId = this._.currentTabId,
+			length = this._.tabIdList.length,
+			tabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, tabId );
+
+		for ( var i = tabIndex + 1 ; i < tabIndex + length ; i++ )
+		{
+			if ( isTabVisible.call( this, this._.tabIdList[ i % length ] ) )
+				return this._.tabIdList[ i % length ];
+		}
+
+		return null;
+	}
+	
 	/**
 	 * This is the base class for runtime dialog objects. An instance of this
@@ -89,6 +124,15 @@
 			// Initialize the tab and page map.
 			tabs : {},
+			tabIdList : [],
+			currentTabId : null,
+			currentTabIndex : null,
 			pageCount : 0,
-			lastTab : null
+			lastTab : null,
+			tabBarMode : false,
+
+			// Initialize the tab order array for input widgets.
+			focusList : [],
+			currentFocusIndex : 0,
+			hasFocus : false
 		};
 
@@ -252,4 +296,97 @@
 				}, this );
 
+		function changeFocus( forward )
+		{
+			var focusList = me._.focusList,
+				offset = forward ? 1 : -1;
+			if ( focusList.length < 1 )
+				return;
+
+			var currentIndex = ( me._.currentFocusIndex + offset + focusList.length ) % focusList.length;
+			while ( !focusList[ currentIndex ].isFocusable() )
+			{
+				currentIndex = ( currentIndex + offset + focusList.length ) % focusList.length;
+				if ( currentIndex == me._.currentFocusIndex )
+					break;
+			}
+			focusList[ currentIndex ].focus();
+		}
+
+		function focusKeydownHandler( evt )
+		{
+			// If I'm not the top dialog, ignore.
+			if ( me != CKEDITOR.dialog._.currentTop )
+				return;
+
+			var keystroke = evt.data.getKeystroke(),
+				processed = false;
+			if ( keystroke == 9 || keystroke == CKEDITOR.SHIFT + 9 )
+			{
+				var shiftPressed = ( keystroke == CKEDITOR.SHIFT + 9 );
+
+				// Handling Tab and Shift-Tab.
+				if ( me._.tabBarMode )
+				{
+					// Change tabs.
+					var nextId = shiftPressed ? getPreviousVisibleTab.call( me ) : getNextVisibleTab.call( me );
+					me.selectPage( nextId );
+					me._.tabs[ nextId ][ 0 ].getFirst().focus();
+				}
+				else
+				{
+					// Change the focus of inputs.
+					changeFocus( !shiftPressed );
+				}
+				
+				processed = true;
+			}
+			else if ( keystroke == CKEDITOR.ALT + 121 && !me._.tabBarMode )
+			{
+				// Alt-F10 puts focus into the current tab item in the tab bar.
+				me._.tabBarMode = true;
+				me._.tabs[ me._.currentTabId ][ 0 ].getFirst().focus();
+				processed = true;
+			}
+			else if ( ( keystroke == 37 || keystroke == 39 ) && me._.tabBarMode )
+			{
+				// Arrow keys - used for changing tabs.
+				var nextId = ( keystroke == 37 ? getPreviousVisibleTab.call( me ) : getNextVisibleTab.call( me ) );
+				me.selectPage( nextId );
+				me._.tabs[ nextId ][ 0 ].getFirst().focus();
+				processed = true;
+			}
+
+			if ( processed )
+			{
+				evt.stop();
+				evt.data.preventDefault();
+			}
+		}
+
+		// Add the dialog keyboard handlers.
+		this.on( 'show', function()
+			{
+				CKEDITOR.document.on( 'keydown', focusKeydownHandler, this, null, 0 );
+				if ( CKEDITOR.env.ie6Compat )
+				{
+					var coverDoc = new CKEDITOR.dom.document( frames( 'cke_dialog_background_iframe' ).document );
+					coverDoc.on( 'keydown', focusKeydownHandler, this, null, 0 );
+				}
+			} );
+		this.on( 'hide', function()
+			{
+				CKEDITOR.document.removeListener( 'keydown', focusKeydownHandler );
+			} );
+
+		// Auto-focus logic in dialog.
+		this.on( 'show', function()
+			{
+				if ( !this._.hasFocus )
+				{
+					this._.currentFocusIndex = -1;
+					changeFocus( true );
+				}
+			}, this, null, 0xffffffff );
+
 		// IE6 BUG: Text fields and text areas are only half-rendered the first time the dialog appears in IE6 (#2661).
 		// This is still needed after [2708] and [2709] because text fields in hidden TR tags are still broken.
@@ -282,5 +419,5 @@
 
 					// If we aren't inside a tab, bail out.
-					if ( !tabRegex.test( target.$.className ) )
+					if ( !( tabRegex.test( target.$.className ) || target.getName() == 'a' ) )
 						return;
 
@@ -292,4 +429,11 @@
 					id = target.$.id.substr( 0, target.$.id.lastIndexOf( '_' ) );
 					this.selectPage( id );
+
+					if ( this._.tabBarMode )
+					{
+						this._.tabBarMode = false;
+						this._.currentFocusIndex = -1;
+						changeFocus( true );
+					}
 				}, this );
 
@@ -467,4 +611,7 @@
 			this._.dummyText.$.select();
 
+			// Reset the hasFocus state.
+			this._.hasFocus = false;
+
 			// Execute onLoad for the first show.
 			this.fireOnce( 'load', {} );
@@ -578,5 +725,5 @@
 		{
 			var pageHtml = [],
-				titleHtml = contents.title ? 'title="' + CKEDITOR.tools.htmlEncode( contents.title ) + '" ' : '',
+				titleHtml = contents.label ? ' title="' + CKEDITOR.tools.htmlEncode( contents.label ) + '"' : '',
 				elements = contents.elements,
 				vbox = CKEDITOR.dialog._.uiElementBuilders.vbox.build( this,
@@ -591,5 +738,6 @@
 			var page = CKEDITOR.dom.element.createFromHtml( pageHtml.join( '' ) );
 			var tab = CKEDITOR.dom.element.createFromHtml( [
-					'<table><tbody><tr><td class="cke_dialog_tab" ', titleHtml, '>',
+					'<table><tbody><tr><td class="cke_dialog_tab">',
+					'<a href="javascript: void(0)"', titleHtml, ' style="display: block; outline: none;" hidefocus="true">',
 					'<table border="0" cellspacing="0" cellpadding="0"><tbody><tr>',
 						'<td class="cke_dialog_tab_left"></td>',
@@ -598,5 +746,5 @@
 						'</td>',
 						'<td class="cke_dialog_tab_right"></td>',
-					'</tr></tbody></table></td></tr></tbody></table>'
+					'</tr></tbody></table></a></td></tr></tbody></table>'
 				].join( '' ) );
 			tab = tab.getChild( [0,0,0] );
@@ -615,4 +763,5 @@
 			// Take records for the tabs and elements created.
 			this._.tabs[ contents.id ] = [ tab, page ];
+			this._.tabIdList.push( contents.id );
 			this._.pageCount++;
 			this._.lastTab = tab;
@@ -666,5 +815,6 @@
 			selected[0].addClass( 'cke_dialog_tab_selected' );
 			selected[1].show();
-			var me = this;
+			this._.currentTabId = id;
+			this._.currentTabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, id );
 		},
 
@@ -1672,5 +1822,5 @@
 			uiElement : function( dialog, elementDefinition, htmlList, nodeNameArg, stylesArg, attributesArg, contentsArg )
 			{
-				if (arguments.length < 4 )
+				if ( arguments.length < 4 )
 					return;
 
@@ -1744,4 +1894,28 @@
 				if ( this.accessKeyUp && this.accessKeyDown && elementDefinition.accessKey )
 					registerAccessKey( this, dialog, 'CTRL+' + elementDefinition.accessKey );
+
+				var me = this;
+				dialog.on( 'load', function()
+					{
+						if ( me.getInputElement() )
+						{
+							me.getInputElement().on( 'focus', function()
+								{
+									dialog._.tabBarMode = false;
+									dialog._.hasFocus = true;
+									me.fire( 'focus' );
+								}, me );
+						}
+					} );
+
+				// Register the object as a tab focus if it can be included.
+				if ( this.keyboardFocusable )
+				{
+					this.focusIndex = dialog._.focusList.push( this ) - 1;
+					this.on( 'focus', function()
+						{
+							dialog._.currentFocusIndex = me.focusIndex;
+						} );
+				}
 
 				// Completes this object with everything we have in the
@@ -1994,4 +2168,8 @@
 			{ /*jsl:pass*/ }
 
+			// Some widgets don't have parent tabs (e.g. OK and Cancel buttons).
+			if ( !cursor )
+				return this;
+
 			tabId = cursor.getAttribute( 'name' );
 
@@ -2148,4 +2326,37 @@
 			element.removeAttribute( 'disabled' );
 			element.removeClass( 'cke_disabled' );
+		},
+
+		/**
+		 * Determines whether an UI element is enabled or not.
+		 * @returns {Boolean} Whether the UI element is enabled.
+		 * @example
+		 */
+		isEnabled : function()
+		{
+			return !this.getInputElement().getAttribute( 'disabled' );
+		},
+
+		/**
+		 * Determines whether an UI element is visible or not.
+		 * @returns {Boolean} Whether the UI element is visible.
+		 * @example
+		 */
+		isVisible : function()
+		{
+			return !!this.getInputElement().$.offsetHeight;
+		},
+
+		/**
+		 * Determines whether an UI element is focus-able or not.
+		 * Focus-able is defined as being both visible and enabled.
+		 * @returns {Boolean} Whether the UI element can be focused.
+		 * @example
+		 */
+		isFocusable : function()
+		{
+			if ( !this.isEnabled() || !this.isVisible() )
+				return false;
+			return true;
 		}
 	};
Index: /CKEditor/trunk/_source/plugins/dialogui/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/dialogui/plugin.js	(revision 3230)
+++ /CKEditor/trunk/_source/plugins/dialogui/plugin.js	(revision 3231)
@@ -209,11 +209,19 @@
 
 				// If user presses Enter in a text box, it implies clicking OK for the dialog.
-				var me = this;
+				var me = this, keyPressedOnMe = false;
 				dialog.on( 'load', function()
 					{
+						me.getInputElement().on( 'keydown', function( evt )
+							{
+								if ( evt.data.getKeystroke() == 13 )
+									keyPressedOnMe = true;
+							} );
 						me.getInputElement().on( 'keyup', function( evt )
 							{
-								if ( evt.data.$.keyCode == 13 )
+								if ( evt.data.getKeystroke() == 13 && keyPressedOnMe )
+								{
 									dialog.getButton( 'ok' ) && dialog.getButton( 'ok' ).click();
+									keyPressedOnMe = false;
+								}
 							} );
 					} );
@@ -437,7 +445,32 @@
 				var innerHTML = function()
 				{
-					return [ '<tbody><tr><td class="cke_dialog_ui_button_txt">',
-						   CKEDITOR.tools.htmlEncode( elementDefinition.label ),
-						   '</td></tr></tbody>' ].join( '' );
+					var styles = [],
+						align = elementDefinition.align || ( dialog.getParentEditor().lang.dir == 'ltr' ? 'left' : 'right' );
+
+					if ( elementDefinition.style )
+					{
+						var defStyle = CKEDITOR.tools.trim( elementDefinition.style );
+						styles.push( defStyle );
+						if ( defStyle.charAt( defStyle.length - 1 ) != ';' )
+							styles.push( ';' );
+					}
+
+					// IE6 & 7 BUG: Need to set margin as well as align.
+					if ( CKEDITOR.env.ie && CKEDITOR.env.version < 8 )
+					{
+						styles.push( [
+							'margin:',
+							'auto',
+							align == 'right' ? '0px' : 'auto',
+							'auto',
+							align == 'left' ? '0px' : 'auto' ].join( ' ' ), ';' );
+					}
+
+					return [
+						'<table align="', align, '" ', styles.length > 0 ? 'style="' + styles.join( '' ) + '">' : '>',
+						'<tbody><tr><td class="cke_dialog_ui_button_txt">',
+						CKEDITOR.tools.htmlEncode( elementDefinition.label ),
+						'</td></tr></tbody></table>'
+					].join( '' );
 				};
 
@@ -450,20 +483,30 @@
 						{
 							var element = this.getElement();
-							element.on( 'mousedown', function( evt )
-								{
-									// If button is disabled, don't do anything.
-									if ( me._.disabled )
-										return;
-
-									// Change styles to indicate the button is being clicked.
-									me.getElement().addClass( 'active' );
-
-									// Store the currently active button.
-									CKEDITOR.ui.dialog.button._.activeButton = [ me, me.getElement() ];
-								});
+							(function()
+							{
+								element.on( 'mousedown', function( evt )
+									{
+										// If button is disabled, don't do anything.
+										if ( me._.disabled )
+											return;
+
+										// Store the currently active button.
+										CKEDITOR.ui.dialog.button._.activeButton = [ me, me.getElement() ];
+									} );
+
+								element.on( 'keydown', function( evt )
+									{
+										// Click if Enter is pressed.
+										if ( evt.data.$.keyCode == 13 )
+										{
+											me.fire( 'click', { dialog : me.getDialog() } );
+											evt.data.preventDefault();
+										}
+									} );
+							})();
 
 							// IE BUG: Padding attributes are ignored for <td> cells.
 							if ( CKEDITOR.env.ie )
-								element.getChild( [0, 0, 0] ).$.innerHTML += '';
+								element.getChild( [0, 0, 0, 0] ).$.innerHTML += '';
 
 							if ( !eventInfo.data.buttonHandlerRegistered )
@@ -478,37 +521,25 @@
 											return;
 
-										// Change styles to remove active status.
-										activeButton[1].removeClass( 'active' );
-
 										// Fire the click event - but only if the
 										// active button is the same as target.
-										if ( activeButton[1].equals( target.getAscendant( 'table' ) ) )
+										if ( activeButton[1].equals( target.getAscendant( 'a' ) ) )
 											activeButton[0].fire( 'click', { dialog : activeButton[0].getDialog() } );
 
 										// Clear active button flag.
 										CKEDITOR.ui.dialog.button._.activeButton = null;
-									});
+									} );
 
 								eventInfo.data.buttonHandlerRegistered = true;
 							}
 
-							this.getElement().unselectable();
+							this.getElement().getFirst().unselectable();
 						}, this );
 
-				var styles = {},
-					align = elementDefinition.align || ( dialog.getParentEditor().lang.dir == 'ltr' ? 'left' : 'right' );
-
-				// IE6 & 7 BUG: Need to set margin as well as align.
-				if ( CKEDITOR.env.ie && CKEDITOR.env.version < 8 )
-				{
-					styles.margin = [
-						'auto',
-						align == 'right' ? '0px' : 'auto',
-						'auto',
-						align == 'left' ? '0px' : 'auto' ].join( ' ' );
-				}
-
-				CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition, htmlList, 'table', styles,
-						{ align : align }, innerHTML );
+				var outerDefinition = CKEDITOR.tools.extend( {}, elementDefinition );
+				delete outerDefinition.style;
+
+				CKEDITOR.ui.dialog.uiElement.call( this, dialog, outerDefinition, htmlList, 'a', { display : 'block', outline : 'none' },
+						{ href : 'javascript:void(0);', title : elementDefinition.label, hidefocus : 'true' },
+						innerHTML );
 			},
 
@@ -780,4 +811,5 @@
 					if ( !this._.disabled )
 						return this.fire( 'click', { dialog : this._.dialog } );
+					this.getElement().$.blur();
 				},
 
@@ -800,4 +832,14 @@
 					this._.disabled = true;
 					this.getElement().addClass( 'disabled' );
+				},
+
+				isVisible : function()
+				{
+					return !!this.getElement().$.firstChild.offsetHeight;
+				},
+
+				isEnabled : function()
+				{
+					return !this._.disabled;
 				},
 
@@ -824,5 +866,4 @@
 				accessKeyUp : function()
 				{
-					this.getElement().removeClass( 'active' );
 					this.click();
 				},
@@ -835,6 +876,8 @@
 				accessKeyDown : function()
 				{
-					this.getElement().addClass( 'active' );
-				}
+					this.focus();
+				},
+
+				keyboardFocusable : true 
 			}, true );
 
@@ -897,5 +940,7 @@
 					value = value || '';
 					return CKEDITOR.ui.dialog.uiElement.prototype.setValue.call( this, value );
-				}
+				},
+
+				keyboardFocusable : true
 			}, commonPrototype, true );
 
@@ -967,5 +1012,7 @@
 						selectElement.remove( 0 );
 					return this;
-				}
+				},
+
+				keyboardFocusable : true
 			}, commonPrototype, true );
 
@@ -1041,5 +1088,7 @@
 						return null;
 					}
-				}
+				},
+
+				keyboardFocusable : true
 			}, commonPrototype, true );
 
@@ -1129,5 +1178,7 @@
 						return null;
 					}
-				}
+				},
+
+				keyboardFocusable : true
 			}, commonPrototype, true );
 
@@ -1194,5 +1245,7 @@
 				 * @example
 				 */
-				eventProcessors : commonEventProcessors
+				eventProcessors : commonEventProcessors,
+
+				keyboardFocusable : true
 			}, true );
 
Index: /CKEditor/trunk/_source/skins/default/dialog.css
===================================================================
--- /CKEditor/trunk/_source/skins/default/dialog.css	(revision 3230)
+++ /CKEditor/trunk/_source/skins/default/dialog.css	(revision 3231)
@@ -376,10 +376,10 @@
 }
 
-.cke_skin_default .cke_dialog_ui_button
+.cke_skin_default .cke_dialog_ui_button table
 {
 	border: #737357 1px solid;
 }
 
-.cke_skin_default .cke_dialog_ui_button.disabled
+.cke_skin_default .cke_dialog_ui_button.disabled table
 {
 	border: #898980 1px solid;
@@ -400,5 +400,6 @@
 }
 
-.cke_skin_default .cke_dialog_ui_button.active .cke_dialog_ui_button_txt
+.cke_skin_default a:focus.cke_dialog_ui_button .cke_dialog_ui_button_txt,
+.cke_skin_default a:active.cke_dialog_ui_button .cke_dialog_ui_button_txt
 {
 	background-color: #e3e3c7;
