Index: /CKEditor/trunk/_source/plugins/link/dialogs/anchor.js
===================================================================
--- /CKEditor/trunk/_source/plugins/link/dialogs/anchor.js	(revision 3049)
+++ /CKEditor/trunk/_source/plugins/link/dialogs/anchor.js	(revision 3049)
@@ -0,0 +1,112 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+CKEDITOR.dialog.add( 'anchor', function( editor )
+{
+	// Function called in onShow to load selected element.
+	var loadElements = function( editor, selection, ranges, element )
+	{
+		this.saveSelection();
+		this.editMode = true;
+		this.editObj = element;
+
+		var attributeValue = this.editObj.getAttribute( 'name' );
+		if ( attributeValue == null )
+			this.setValueOf( 'info','txtName', "" );
+		else
+			this.setValueOf( 'info','txtName', attributeValue );
+	};
+
+	return {
+		title : editor.lang.anchor.title,
+		minWidth : 350,
+		minHeight : 150,
+		onOk : function()
+		{
+			// Always create a new anchor, because of IE BUG.
+			var name = this.getValueOf( 'info', 'txtName' ),
+				element = CKEDITOR.env.ie ?
+				editor.document.createElement( '<a name="' + CKEDITOR.tools.htmlEncode( name ) + '">' ) :
+				editor.document.createElement( 'a' );
+
+			// Move contents and attributes of old anchor to new anchor.
+			if ( this.editMode )
+			{
+				this.editObj.copyAttributes( element, { name : 1 } );
+				this.editObj.moveChildren( element );
+			}
+
+			// Set name.
+			element.setAttribute( 'name', name );
+
+			// Insert a new anchor.
+			var fakeElement = editor.createFakeElement( element, 'cke_anchor', 'anchor' );
+			if ( !this.editMode )
+			{
+				// It doesn't work with IE.
+				this.restoreSelection();
+				this.clearSavedSelection();
+
+				editor.insertElement( fakeElement );
+			}
+			else
+				fakeElement.replace( this.fakeObj );
+			return true;
+		},
+		onShow : function()
+		{
+			this.editObj = false;
+			this.fakeObj = false;
+			this.editMode = false;
+
+			// IE BUG: Selection must be in the editor for getSelection() to work.
+			this.restoreSelection();
+
+			var editor = this.getParentEditor(),
+				selection = editor.getSelection(),
+				ranges = selection.getRanges();
+
+			if ( ranges.length == 1 )
+			{
+				ranges[0].enlarge( CKEDITOR.ENLARGE_ELEMENT );
+				rangeRoot = ranges[0].getCommonAncestor( true );
+				var element = rangeRoot.getAscendant( 'img', true );
+				if ( element && element.getAttribute( '_cke_real_element_type' ) && element.getAttribute( '_cke_real_element_type' ) == 'anchor' )
+				{
+					this.fakeObj = element;
+					element = editor.restoreRealElement( this.fakeObj );
+					loadElements.apply( this, [ editor, selection, ranges, element ] );
+					selection.selectElement( this.fakeObj );
+					this.saveSelection();
+				}
+			}
+			this.getContentElement( 'info', 'txtName' ).focus();
+		},
+		contents : [
+			{
+				id : 'info',
+				label : editor.lang.anchor.title,
+				accessKey : 'I',
+				elements :
+				[
+					{
+						type : 'text',
+						id : 'txtName',
+						label : editor.lang.anchor.name,
+						validate : function()
+						{
+							if ( this.getValue() == '' )
+							{
+								alert( editor.lang.anchor.errorName );
+								return false;
+							}
+							return true;
+						}
+					},
+				]
+			}
+		]
+	};
+} );
Index: /CKEditor/trunk/_source/plugins/link/dialogs/link.js
===================================================================
--- /CKEditor/trunk/_source/plugins/link/dialogs/link.js	(revision 3049)
+++ /CKEditor/trunk/_source/plugins/link/dialogs/link.js	(revision 3049)
@@ -0,0 +1,1187 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+CKEDITOR.dialog.add( 'link', function( editor )
+{
+	// Handles the event when the "Target" selection box is changed.
+	var targetChanged = function()
+	{
+		var dialog = this.getDialog(),
+			popupFeatures = dialog.getContentElement( 'target', 'popupFeatures' ),
+			targetName = dialog.getContentElement( 'target', 'linkTargetName' ),
+			value = this.getValue();
+
+		if ( !popupFeatures || !targetName )
+			return;
+
+		popupFeatures = popupFeatures.getElement();
+
+		if ( value == 'popup' )
+		{
+			popupFeatures.show();
+			targetName.setLabel( editor.lang.link.targetPopupName );
+		}
+		else
+		{
+			popupFeatures.hide();
+			targetName.setLabel( editor.lang.link.targetFrameName );
+			this.getDialog().setValueOf( 'target', 'linkTargetName', value.charAt( 0 ) == '_' ? value : '' );
+		}
+	};
+
+	// Handles the event when the "Type" selection box is changed.
+	var linkTypeChanged = function()
+	{
+		var dialog = this.getDialog(),
+			partIds = [ 'urlOptions', 'anchorOptions', 'emailOptions' ],
+			typeValue = this.getValue();
+		if ( typeValue == 'url' )
+		{
+			if ( editor.config.linkShowTargetTab )
+				dialog.showPage( 'target' );
+			if ( editor.config.linkUploadTab )
+				dialog.showPage( 'upload' );
+		}
+		else
+		{
+			dialog.hidePage( 'target' );
+			dialog.hidePage( 'upload' );
+		}
+
+		for ( var i = 0 ; i < partIds.length ; i++ )
+		{
+			var element = dialog.getContentElement( 'info', partIds[i] );
+			if ( !element )
+				continue;
+
+			element = element.getElement().getParent().getParent();
+			if ( partIds[i] == typeValue + 'Options' )
+				element.show();
+			else
+				element.hide();
+		}
+	};
+
+	// Loads the parameters in a selected link to the link dialog fields.
+	var emailRegex = /^mailto:([^?]+)(?:\?(.+))?$/,
+		emailSubjectRegex = /subject=([^;?:@&=$,\/]*)/,
+		emailBodyRegex = /body=([^;?:@&=$,\/]*)/,
+		anchorRegex = /^#(.*)$/,
+		urlRegex = /^((?:http|https|ftp|news):\/\/)?(.*)$/,
+		selectableTargets = /^(_(?:self|top|parent|blank))$/;
+
+	var popupRegex =
+		/\s*window.open\(\s*this\.href\s*,\s*(?:'([^']*)'|null)\s*,\s*'([^']*)'\s*\)\s*;\s*return\s*false;*\s*/;
+	var popupFeaturesRegex = /(?:^|,)([^=]+)=(\d+|yes|no)/gi;
+
+	var parseLink = function( editor, element )
+	{
+		var href = element ? ( element.getAttribute( '_cke_saved_href' ) || element.getAttribute( 'href' ) ) : '',
+			emailMatch = '',
+			anchorMatch = '',
+			urlMatch = false,
+			retval = {};
+
+		if ( href != null )
+		{
+			emailMatch = href.match( emailRegex );
+			anchorMatch = href.match( anchorRegex );
+			urlMatch = href.match( urlRegex );
+		}
+		
+		// Load the link type and URL.
+		if ( emailMatch )
+		{
+			var subjectMatch = href.match( emailSubjectRegex ),
+				bodyMatch = href.match( emailBodyRegex );
+			retval.type = 'email';
+			retval.email = {};
+			retval.email.address = emailMatch[1];
+			subjectMatch && ( retval.email.subject = decodeURIComponent( subjectMatch[1] ) );
+			bodyMatch && ( retval.email.body = decodeURIComponent( bodyMatch[1] ) );
+		}
+		else if ( anchorMatch )
+		{
+			retval.type = 'anchor';
+			retval.anchor = {};
+			retval.anchor.name = retval.anchor.id = anchorMatch[1];
+		}
+		else if ( href && urlMatch )		// urlRegex matches empty strings, so need to check for href as well.
+		{
+			retval.type = 'url';
+			retval.url = {};
+			retval.url.protocol = urlMatch[1];
+			retval.url.url = urlMatch[2];
+		}
+		else
+			retval.type = 'url';
+
+		// Load target and popup settings.
+		if ( element )
+		{
+			var target = element.getAttribute( 'target' );
+			retval.target = {};
+			retval.adv = {};
+
+			// IE BUG: target attribute is an empty string instead of null in IE if it's not set.
+			if ( !target )
+			{
+				var onclick = element.getAttribute( '_cke_saved_onclick' ) || element.getAttribute( 'onclick' ),
+					onclickMatch = onclick && onclick.match( popupRegex );
+				if ( onclickMatch )
+				{
+					retval.target.type = 'popup';
+					retval.target.name = onclickMatch[1];
+
+					var featureMatch;
+					while ( ( featureMatch = popupFeaturesRegex.exec( onclickMatch[2] ) ) )
+					{
+						if ( featureMatch[2] == 'yes' || featureMatch[2] == '1' )
+							retval.target[ featureMatch[1] ] = true;
+						else if ( isFinite( featureMatch[2] ) )
+							retval.target[ featureMatch[1] ] = featureMatch[2];
+					}
+				}
+			}
+			else
+			{
+				var targetMatch = target.match( selectableTargets );
+				if ( targetMatch )
+					retval.target.type = retval.target.name = target;
+				else
+				{
+					retval.target.type = 'frame';
+					retval.target.name = target;
+				}
+			}
+
+			var me = this;
+			var advAttr = function( inputName, attrName )
+			{
+				var value = element.getAttribute( attrName );
+				if ( value != null )
+					retval.adv[ inputName ] = value || '';
+			};
+			advAttr( 'advId', 'id' );
+			advAttr( 'advLangDir', 'dir' );
+			advAttr( 'advAccessKey', 'accessKey' );
+			advAttr( 'advName', 'name' );
+			advAttr( 'advLangCode', 'lang' );
+			advAttr( 'advTabIndex', 'tabindex' );
+			advAttr( 'advTitle', 'title' );
+			advAttr( 'advContentType', 'type' );
+			advAttr( 'advCSSClasses', 'class' );
+			advAttr( 'advCharset', 'charset' );
+			advAttr( 'advStyles', 'style' );
+		}
+
+		// Find out whether we have any anchors in the editor.
+		// Get all IMG elements in CK document.
+		var elements = editor.document.$.getElementsByTagName( 'img' ),
+			realAnchors = editor.document.$.anchors,
+			anchors = retval.anchors = [];
+		for( var i = 0; i < elements.length ; i++ )
+		{
+			var item = elements.item( i );
+			if ( item.getAttribute( '_cke_realelement' ) && item.getAttribute( '_cke_real_element_type' ) == 'anchor' )
+			{
+				var domElement = new CKEDITOR.dom.element( item );
+				domElement = editor.restoreRealElement( domElement );
+				anchors.push( domElement );
+			}
+		}
+		for ( var i = 0 ; i < realAnchors.length ; i++ )
+			anchors.push( realAnchors[i] );
+		for ( var i = 0, item, length = anchors.length ; i < length && ( item = anchors.shift() ) ; i++ )
+			anchors.push( { name : item.getAttribute( 'name' ), id : item.getAttribute( 'id' ) } );
+
+		// Record down the selected element in the dialog.
+		this._.selectedElement = element;
+
+		return retval;
+	};
+
+	var setupParams = function( page, data )
+	{
+		if ( data[page] )
+			this.setValue( data[page][this.id] || '' );
+	};
+
+	var setupPopupParams = function( data )
+	{
+		return setupParams.call( this, 'target', data );
+	};
+
+	var setupAdvParams = function( data )
+	{
+		return setupParams.call( this, 'adv', data );
+	};
+
+	var commitParams = function( page, data )
+	{
+		if ( !data[page] )
+			data[page] = {};
+
+		data[page][this.id] = this.getValue() || '';
+	};
+
+	var commitPopupParams = function( data )
+	{
+		return commitParams.call( this, 'target', data );
+	};
+
+	var commitAdvParams = function( data )
+	{
+		return commitParams.call( this, 'adv', data );
+	};
+
+	return {
+		title : editor.lang.link.title,
+		minWidth : 400,
+		minHeight : 320,
+		contents : [
+			{
+				id : 'info',
+				label : editor.lang.link.info,
+				title : editor.lang.link.info,
+				elements :
+				[
+					{
+						id : 'linkType',
+						type : 'select',
+						label : editor.lang.link.type,
+						'default' : 'url',
+						items :
+						[
+							[ editor.lang.common.url, 'url' ],
+							[ editor.lang.link.toAnchor, 'anchor' ],
+							[ editor.lang.link.toEmail, 'email' ]
+						],
+						onChange : linkTypeChanged,
+						setup : function( data )
+						{
+							if ( data.type )
+								this.setValue( data.type );
+						},
+						commit : function( data )
+						{
+							data.type = this.getValue();
+						}
+					},
+					{
+						type : 'vbox',
+						id : 'urlOptions',
+						children :
+						[
+							{
+								type : 'hbox',
+								widths : [ '25%', '75%' ],
+								children :
+								[
+									{
+										id : 'protocol',
+										type : 'select',
+										label : editor.lang.common.protocol,
+										'default' : 'http://',
+										style : 'width : 100%;',
+										items :
+										[
+											[ 'http://' ],
+											[ 'https//' ],
+											[ 'ftp://' ],
+											[ 'news://' ],
+											[ '<other>', '' ]
+										],
+										setup : function( data )
+										{
+											if ( data.url )
+												this.setValue( data.url.protocol );
+										},
+										commit : function( data )
+										{
+											if ( !data.url )
+												data.url = {};
+
+											data.url.protocol = this.getValue();
+										}
+									},
+									{
+										type : 'text',
+										id : 'url',
+										label : editor.lang.common.url,
+										validate : function()
+										{
+											var dialog = this.getDialog();
+
+											if ( dialog.getContentElement( 'info', 'linkType' ) &&
+													dialog.getValueOf( 'info', 'linkType' ) != 'url' )
+												return true;
+
+											if ( this.getDialog().fakeObj != false )	// Edit Anchor.
+												return true;
+
+											var func = CKEDITOR.dialog.validate.notEmpty( editor.lang.link.noUrl );
+											return func.apply( this );
+										},
+										setup : function( data )
+										{
+											if ( data.url )
+												this.setValue( data.url.url );
+
+											var linkType = this.getDialog().getContentElement( 'info', 'linkType' );
+											if ( linkType && linkType.getValue() == 'url' )
+												this.select();
+										},
+										commit : function( data )
+										{
+											if ( !data.url )
+												data.url = {};
+
+											data.url.url = this.getValue();
+										}
+									}
+								],
+								setup : function( data )
+								{
+									if ( !this.getDialog().getContentElement( 'info', 'linkType' ) )
+										this.getElement().show();
+								}
+							},
+							{
+								type : 'button',
+								id : 'browse',
+								label : editor.lang.common.browseServer
+							}
+						]
+					},
+					{
+						type : 'vbox',
+						id : 'anchorOptions',
+						width : 260,
+						align : 'center',
+						padding : 0,
+						children :
+						[
+							{
+								type : 'html',
+								id : 'selectAnchorText',
+								html : CKEDITOR.tools.htmlEncode( editor.lang.link.selectAnchor ),
+								setup : function( data )
+								{
+									if ( data.anchors.length > 0 )
+										this.getElement().show();
+									else
+										this.getElement().hide();
+								}
+							},
+							{
+								type : 'html',
+								id : 'noAnchors',
+								style : 'text-align: center;',
+								html : '<div>' + CKEDITOR.tools.htmlEncode( editor.lang.link.noAnchors ) + '</div>',
+								setup : function( data )
+								{
+									if ( data.anchors.length < 1 )
+										this.getElement().show();
+									else
+										this.getElement().hide();
+								}
+							},
+							{
+								type : 'hbox',
+								id : 'selectAnchor',
+								children :
+								[
+									{
+										type : 'select',
+										id : 'anchorName',
+										'default' : '',
+										label : editor.lang.link.anchorName,
+										style : 'width: 100%;',
+										items :
+										[
+											[ '' ]
+										],
+										setup : function( data )
+										{
+											this.clear();
+											this.add( '' );
+											for ( var i = 0 ; i < data.anchors.length ; i++ )
+											{
+												if ( data.anchors[i].name )
+													this.add( data.anchors[i].name );
+											}
+
+											if ( data.anchor )
+												this.setValue( data.anchor.name );
+
+											var linkType = this.getDialog().getContentElement( 'info', 'linkType' );
+											if ( linkType && linkType.getValue() == 'email' )
+												this.focus();
+										},
+										commit : function( data )
+										{
+											if ( !data.anchor )
+												data.anchor = {};
+
+											data.anchor.name = this.getValue();
+										}
+									},
+									{
+										type : 'select',
+										id : 'anchorId',
+										'default' : '',
+										label : editor.lang.link.anchorId,
+										style : 'width: 100%;',
+										items :
+										[
+											[ '' ]
+										],
+										setup : function( data )
+										{
+											this.clear();
+											this.add( '' );
+											for ( var i = 0 ; i < data.anchors.length ; i++ )
+											{
+												if ( data.anchors[i].id )
+													this.add( data.anchors[i].id );
+											}
+
+											if ( data.anchor )
+												this.setValue( data.anchor.id );
+										},
+										commit : function( data )
+										{
+											if ( !data.anchor )
+												data.anchor = {};
+
+											data.anchor.id = this.getValue();
+										}
+									}
+								],
+								setup : function( data )
+								{
+									if ( data.anchors.length > 0 )
+										this.getElement().show();
+									else
+										this.getElement().hide();
+								}
+							}
+						],
+						setup : function( data )
+						{
+							if ( !this.getDialog().getContentElement( 'info', 'linkType' ) )
+								this.getElement().hide();
+						}
+					},
+					{
+						type :  'vbox',
+						id : 'emailOptions',
+						padding : 1,
+						children :
+						[
+							{
+								type : 'text',
+								id : 'emailAddress',
+								label : editor.lang.link.emailAddress,
+								validate : function()
+								{
+									var dialog = this.getDialog();
+
+									if ( !dialog.getContentElement( 'info', 'linkType' ) ||
+											dialog.getValueOf( 'info', 'linkType' ) != 'email' )
+										return true;
+
+									var func = CKEDITOR.dialog.validate.notEmpty( editor.lang.link.noEmail );
+									return func.apply( this );
+								},
+								setup : function( data )
+								{
+									if ( data.email )
+										this.setValue( data.email.address );
+
+									var linkType = this.getDialog().getContentElement( 'info', 'linkType' );
+									if ( linkType && linkType.getValue() == 'email' )
+										this.select();
+								},
+								commit : function( data )
+								{
+									if ( !data.email )
+										data.email = {};
+
+									data.email.address = this.getValue();
+								}
+							},
+							{
+								type : 'text',
+								id : 'emailSubject',
+								label : editor.lang.link.emailSubject,
+								setup : function( data )
+								{
+									if ( data.email )
+										this.setValue( data.email.subject );
+								},
+								commit : function( data )
+								{
+									if ( !data.email )
+										data.email = {};
+
+									data.email.subject = this.getValue();
+								}
+							},
+							{
+								type : 'textarea',
+								id : 'emailBody',
+								label : editor.lang.link.emailBody,
+								rows : 3,
+								'default' : '',
+								setup : function( data )
+								{
+									if ( data.email )
+										this.setValue( data.email.body );
+								},
+								commit : function( data )
+								{
+									if ( !data.email )
+										data.email = {};
+
+									data.email.body = this.getValue();
+								}
+							}
+						],
+						setup : function( data )
+						{
+							if ( !this.getDialog().getContentElement( 'info', 'linkType' ) )
+								this.getElement().hide();
+						}
+					}
+				]
+			},
+			{
+				id : 'target',
+				label : editor.lang.link.target,
+				title : editor.lang.link.target,
+				elements :
+				[
+					{
+						type : 'hbox',
+						widths : [ '50%', '50%' ],
+						children :
+						[
+							{
+								type : 'select',
+								id : 'linkTargetType',
+								label : editor.lang.link.target,
+								'default' : 'notSet',
+								style : 'width : 100%;',
+								'items' :
+								[
+									[ editor.lang.link.targetNotSet, 'notSet' ],
+									[ editor.lang.link.targetFrame, 'frame' ],
+									[ editor.lang.link.targetPopup, 'popup' ],
+									[ editor.lang.link.targetNew, '_blank' ],
+									[ editor.lang.link.targetTop, '_top' ],
+									[ editor.lang.link.targetSelf, '_self' ],
+									[ editor.lang.link.targetParent, '_parent' ]
+								],
+								onChange : targetChanged,
+								setup : function( data )
+								{
+									if ( data.target )
+										this.setValue( data.target.type );
+								},
+								commit : function( data )
+								{
+									if ( !data.target )
+										data.target = {};
+
+									data.target.type = this.getValue();
+								}
+							},
+							{
+								type : 'text',
+								id : 'linkTargetName',
+								label : editor.lang.link.targetFrameName,
+								'default' : '',
+								setup : function( data )
+								{
+									if ( data.target )
+										this.setValue( data.target.name );
+								},
+								commit : function( data )
+								{
+									if ( !data.target )
+										data.target = {};
+
+									data.target.name = this.getValue();
+								}
+							}
+						]
+					},
+					{
+						type : 'vbox',
+						width : 260,
+						align : 'center',
+						padding : 2,
+						id : 'popupFeatures',
+						children :
+						[
+							{
+								type : 'html',
+								html : CKEDITOR.tools.htmlEncode( editor.lang.link.popupFeatures )
+							},
+							{
+								type : 'hbox',
+								children :
+								[
+									{
+										type : 'checkbox',
+										id : 'resizable',
+										label : editor.lang.link.popupResizable,
+										setup : setupPopupParams,
+										commit : commitPopupParams
+									},
+									{
+										type : 'checkbox',
+										id : 'status',
+										label : editor.lang.link.popupStatusBar,
+										setup : setupPopupParams,
+										commit : commitPopupParams
+
+									}
+								]
+							},
+							{
+								type : 'hbox',
+								children :
+								[
+									{
+										type : 'checkbox',
+										id : 'location',
+										label : editor.lang.link.popupLocationBar,
+										setup : setupPopupParams,
+										commit : commitPopupParams
+
+									},
+									{
+										type : 'checkbox',
+										id : 'toolbar',
+										label : editor.lang.link.popupToolbar,
+										setup : setupPopupParams,
+										commit : commitPopupParams
+
+									}
+								]
+							},
+							{
+								type : 'hbox',
+								children :
+								[
+									{
+										type : 'checkbox',
+										id : 'menubar',
+										label : editor.lang.link.popupMenuBar,
+										setup : setupPopupParams,
+										commit : commitPopupParams
+
+									},
+									{
+										type : 'checkbox',
+										id : 'fullscreen',
+										label : editor.lang.link.popupFullScreen,
+										setup : setupPopupParams,
+										commit : commitPopupParams
+
+									}
+								]
+							},
+							{
+								type : 'hbox',
+								children :
+								[
+									{
+										type : 'checkbox',
+										id : 'scrollbars',
+										label : editor.lang.link.popupScrollBars,
+										setup : setupPopupParams,
+										commit : commitPopupParams
+
+									},
+									{
+										type : 'checkbox',
+										id : 'dependent',
+										label : editor.lang.link.popupDependent,
+										setup : setupPopupParams,
+										commit : commitPopupParams
+
+									}
+								]
+							},
+							{
+								type : 'hbox',
+								children :
+								[
+									{
+										type :  'text',
+										widths : [ '30%', '70%' ],
+										labelLayout : 'horizontal',
+										label : editor.lang.link.popupWidth,
+										id : 'width',
+										setup : setupPopupParams,
+										commit : commitPopupParams
+
+									},
+									{
+										type :  'text',
+										labelLayout : 'horizontal',
+										widths : [ '55%', '45%' ],
+										label : editor.lang.link.popupLeft,
+										id : 'left',
+										setup : setupPopupParams,
+										commit : commitPopupParams
+
+									}
+								]
+							},
+							{
+								type : 'hbox',
+								children :
+								[
+									{
+										type :  'text',
+										labelLayout : 'horizontal',
+										widths : [ '30%', '70%' ],
+										label : editor.lang.link.popupHeight,
+										id : 'height',
+										setup : setupPopupParams,
+										commit : commitPopupParams
+
+									},
+									{
+										type :  'text',
+										labelLayout : 'horizontal',
+										label : editor.lang.link.popupTop,
+										widths : [ '55%', '45%' ],
+										id : 'top',
+										setup : setupPopupParams,
+										commit : commitPopupParams
+
+									}
+								]
+							}
+						]
+					}
+				]
+			},
+			{
+				id : 'upload',
+				label : editor.lang.link.upload,
+				title : editor.lang.link.upload,
+				elements :
+				[
+					{
+						type : 'file',
+						id : 'upload',
+						label : editor.lang.common.upload,
+						action : editor.config.linkUploadAction,
+						size : 38
+					},
+					{
+						type : 'fileButton',
+						id : 'uploadButton',
+						label : editor.lang.common.uploadSubmit,
+						'for' : [ 'upload', 'upload' ]
+					}
+				]
+			},
+			{
+				id : 'advanced',
+				label : editor.lang.link.advanced,
+				title : editor.lang.link.advanced,
+				elements :
+				[
+					{
+						type : 'vbox',
+						padding : 1,
+						children :
+						[
+							{
+								type : 'hbox',
+								widths : [ '45%', '35%', '20%' ],
+								children :
+								[
+									{
+										type : 'text',
+										id : 'advId',
+										label : editor.lang.link.id,
+										setup : setupAdvParams,
+										commit : commitAdvParams
+									},
+									{
+										type : 'select',
+										id : 'advLangDir',
+										label : editor.lang.link.langDir,
+										'default' : '',
+										style : 'width: 100%;',
+										items :
+										[
+											[ editor.lang.link.langDirNotSet, '' ],
+											[ editor.lang.link.langDirLTR, 'ltr' ],
+											[ editor.lang.link.langDirRTL, 'rtl' ]
+										],
+										setup : setupAdvParams,
+										commit : commitAdvParams
+									},
+									{
+										type : 'text',
+										id : 'advAccessKey',
+										label : editor.lang.link.acccessKey,
+										maxLength : 1,
+										setup : setupAdvParams,
+										commit : commitAdvParams
+
+									}
+								]
+							},
+							{
+								type : 'hbox',
+								widths : [ '45%', '35%', '20%' ],
+								children :
+								[
+									{
+										type : 'text',
+										label : editor.lang.link.name,
+										id : 'advName',
+										setup : setupAdvParams,
+										commit : commitAdvParams
+
+									},
+									{
+										type : 'text',
+										label : editor.lang.link.langCode,
+										id : 'advLangCode',
+										'default' : '',
+										setup : setupAdvParams,
+										commit : commitAdvParams
+
+									},
+									{
+										type : 'text',
+										label : editor.lang.link.tabIndex,
+										id : 'advTabIndex',
+										maxLength : 5,
+										setup : setupAdvParams,
+										commit : commitAdvParams
+
+									}
+								]
+							}
+						]
+					},
+					{
+						type : 'vbox',
+						padding : 1,
+						children :
+						[
+							{
+								type : 'hbox',
+								widths : [ '45%', '55%' ],
+								children :
+								[
+									{
+										type : 'text',
+										label : editor.lang.link.advisoryTitle,
+										'default' : '',
+										id : 'advTitle',
+										setup : setupAdvParams,
+										commit : commitAdvParams
+
+									},
+									{
+										type : 'text',
+										label : editor.lang.link.advisoryContentType,
+										'default' : '',
+										id : 'advContentType',
+										setup : setupAdvParams,
+										commit : commitAdvParams
+
+									}
+								]
+							},
+							{
+								type : 'hbox',
+								widths : [ '45%', '55%' ],
+								children :
+								[
+									{
+										type : 'text',
+										label : editor.lang.link.cssClasses,
+										'default' : '',
+										id : 'advCSSClasses',
+										setup : setupAdvParams,
+										commit : commitAdvParams
+
+									},
+									{
+										type : 'text',
+										label : editor.lang.link.charset,
+										'default' : '',
+										id : 'advCharset',
+										setup : setupAdvParams,
+										commit : commitAdvParams
+
+									}
+								]
+							},
+							{
+								type : 'hbox',
+								children :
+								[
+									{
+										type : 'text',
+										label : editor.lang.link.styles,
+										'default' : '',
+										id : 'advStyles',
+										setup : setupAdvParams,
+										commit : commitAdvParams
+
+									}
+								]
+							}
+						]
+					}
+				]
+			}
+		],
+		onShow : function()
+		{
+			this.fakeObj = false;
+			// IE BUG: Selection must be in the editor for getSelection() to work.
+			this.restoreSelection();
+			var editor = this.getParentEditor(),
+				selection = editor.getSelection(),
+				ranges = selection.getRanges(),
+				element = null,
+				me = this;
+
+			// Fill in all the relevant fields if there's already one link selected.
+			if ( ranges.length == 1 )
+			{
+				ranges[0].enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+				var rangeRoot = ranges[0].getCommonAncestor( true );
+				element = rangeRoot.getAscendant( 'a', true );
+				if ( element && element.getAttribute( 'href' ) )
+				{
+					selection.selectElement( element );
+					this.saveSelection();
+				}
+				else
+				{
+					element = rangeRoot.getAscendant( 'img', true );
+					if ( element && element.getAttribute( '_cke_real_element_type' ) && element.getAttribute( '_cke_real_element_type' ) == 'anchor' )
+					{
+						this.fakeObj = element;
+						element = editor.restoreRealElement( this.fakeObj );
+						selection.selectElement( this.fakeObj );
+						this.saveSelection();
+					}
+				}
+			}
+
+			this.setupContent( parseLink.apply( this, [ editor, element ] ) );
+		},
+		onOk : function()
+		{
+			var attributes = { href : 'javascript:void(0)/*' + CKEDITOR.tools.getNextNumber() + '*/' },
+				removeAttributes = [],
+				data = { href : attributes.href },
+				me = this, editor = this.getParentEditor();
+
+			this.commitContent( data );
+
+			// Compose the URL.
+			switch ( data.type || 'url' )
+			{
+				case 'url':
+					var protocol = ( data.url && data.url.protocol ) || 'http://',
+						url = ( data.url && data.url.url ) || '';
+					attributes._cke_saved_href = protocol + url;
+					break;
+				case 'anchor':
+					var name = ( data.anchor && data.anchor.name ),
+						id = ( data.anchor && data.anchor.id );
+					attributes._cke_saved_href = '#' + ( name || id || '' );
+					break;
+				case 'email':
+					var address = ( data.email && data.email.address ),
+						subject = ( data.email && encodeURIComponent( data.email.subject || '' ) ),
+						body = ( data.email && encodeURIComponent( data.email.body || '' ) ),
+						linkList = [ 'mailto:', address ];
+					if ( subject || body )
+					{
+						var argList = [];
+						linkList.push( '?' );
+						subject && argList.push( 'subject=' + subject );
+						body && argList.push( 'body=' + body );
+						linkList.push( argList.join( '&' ) );
+					}
+					attributes._cke_saved_href = linkList.join( '' );
+					break;
+				default:
+			}
+
+			// Popups and target.
+			if ( data.target )
+			{
+				if ( data.target.type == 'popup' )
+				{
+					var onclickList = [ 'window.open(this.href, \'',
+							data.target.name || '', '\', \'' ];
+					var featureList = [ 'resizable', 'status', 'location', 'toolbar', 'menubar', 'fullscreen',
+							'scrollbars', 'dependent' ];
+					var featureLength = featureList.length;
+					var addFeature = function( featureName )
+					{
+						if ( data.target[ featureName ] )
+							featureList.push( featureName + '=' + data.target[ featureName ] );
+					};
+
+					for ( var i = 0 ; i < featureLength ; i++ )
+						featureList[i] = featureList[i] + ( data.target[ featureList[i] ] ? '=yes' : '=no' ) ;
+					addFeature( 'width' );
+					addFeature( 'left' );
+					addFeature( 'height' );
+					addFeature( 'top' );
+
+					onclickList.push( featureList.join( ',' ), '\'); return false;' );
+					attributes._cke_saved_onclick = onclickList.join( '' );
+				}
+				else
+				{
+					if ( data.target.type != 'notSet' && data.target.name )
+						attributes.target = data.target.name;
+					removeAttributes.push( '_cke_saved_onclick', 'onclick' );
+				}
+			}
+
+			// Advanced attributes.
+			if ( data.adv )
+			{
+				var advAttr = function( inputName, attrName )
+				{
+					var value = data.adv[ inputName ];
+					if ( value )
+						attributes[attrName] = value;
+					else
+						removeAttributes.push( attrName );
+				};
+
+				if ( this._.selectedElement )
+					advAttr( 'advId', 'id' );
+				advAttr( 'advLangDir', 'dir' );
+				advAttr( 'advAccessKey', 'accessKey' );
+				advAttr( 'advName', 'name' );
+				advAttr( 'advLangCode', 'lang' );
+				advAttr( 'advTabIndex', 'tabindex' );
+				advAttr( 'advTitle', 'title' );
+				advAttr( 'advContentType', 'type' );
+				advAttr( 'advCSSClasses', 'class' );
+				advAttr( 'advCharset', 'charset' );
+				advAttr( 'advStyles', 'style' );
+			}
+
+			if ( !this._.selectedElement )
+			{
+				// IE BUG: Selection must be in the editor for getSelection() to work.
+				this.restoreSelection();
+				this.clearSavedSelection();
+
+				// Create element if current selection is collapsed.
+				var selection = editor.getSelection(),
+					ranges = selection.getRanges();
+				if ( ranges.length == 1 && ranges[0].collapsed )
+				{
+					var text = new CKEDITOR.dom.text( attributes._cke_saved_href, editor.document );
+					ranges[0].insertNode( text );
+					ranges[0].selectNodeContents( text );
+					selection.selectRanges( ranges );
+				}
+
+				// Apply style.
+				var style = new CKEDITOR.style( { element : 'a', attributes : attributes } );
+				style.type = CKEDITOR.STYLE_INLINE;		// need to override... dunno why.
+				style.apply( editor.document );
+
+				// Id. Apply only to the first link.
+				if ( data.adv && data.adv.advId != '' )
+				{
+					var links = this.getParentEditor().document.$.getElementsByTagName( 'a' );
+					for ( var i = 0 ; i < links.length ; i++ )
+					{
+						if ( links[i].href == attributes.href )
+						{
+							links[i].id = data.adv.advId;
+							break;
+						}
+					}
+				}
+			}
+			else
+			{
+				// We're only editing an existing link, so just overwrite the attributes.
+				var element = this._.selectedElement;
+
+				// IE BUG: Setting the name attribute to an existing link doesn't work.
+				// Must re-create the link from weired syntax to workaround.
+				if ( CKEDITOR.env.ie && attributes.name != element.getAttribute( 'name' ) )
+				{
+					var newElement = new CKEDITOR.dom.element( '<a name="' + CKEDITOR.tools.htmlEncode( attributes.name ) + '">',
+							editor.document );
+
+					this.restoreSelection();
+					var selection = editor.getSelection();
+
+					element.moveChildren( newElement );
+					element.copyAttributes( newElement, { name : 1 } );
+					newElement.replace( element );
+					element = newElement;
+
+					this.clearSavedSelection();
+					selection.selectElement( element );
+				}
+
+				element.setAttributes( attributes );
+				element.removeAttributes( removeAttributes );
+
+				// Make the element display as an anchor if a name has been set.
+				if ( element.getAttribute( 'name' ) )
+					element.addClass( 'cke_anchor' );
+				else
+					element.removeClass( 'cke_anchor' );
+
+				if ( this.fakeObj )
+					editor.createFakeElement( element, 'cke_anchor', 'anchor' ).replace( this.fakeObj );
+
+				delete this._.selectedElement;
+			}
+		},
+		onLoad : function()
+		{
+			if ( editor.config.linkUploadTab == false )
+				this.hidePage( 'upload' );		//Hide Upload tab.
+
+			if ( editor.config.linkShowAdvancedTab == false )
+				this.hidePage( 'advanced' );		//Hide Advanded tab.
+
+			if ( editor.config.linkBrowseServer == false )
+				this.getContentElement( 'info', 'browse' ).getElement().hide();
+
+			if ( editor.config.linkShowTargetTab == false )
+				this.hidePage( 'target' );		//Hide Target tab.
+
+		}
+	};
+} );
Index: /CKEditor/trunk/_source/plugins/link/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/link/plugin.js	(revision 3049)
+++ /CKEditor/trunk/_source/plugins/link/plugin.js	(revision 3049)
@@ -0,0 +1,131 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+CKEDITOR.plugins.add( 'link',
+{
+	init : function( editor, pluginPath )
+	{
+		// Add the link and unlink buttons.
+		editor.addCommand( 'link', new CKEDITOR.dialogCommand( 'link' ) );
+		editor.addCommand( 'anchor', new CKEDITOR.dialogCommand( 'anchor' ) );
+		editor.addCommand( 'unlink', new CKEDITOR.unlinkCommand() );
+		editor.ui.addButton( 'Link',
+			{
+				label : editor.lang.link.toolbar,
+				command : 'link'
+			} );
+		editor.ui.addButton( 'Unlink',
+			{
+				label : editor.lang.unlink,
+				command : 'unlink'
+			} );
+		editor.ui.addButton( 'Anchor',
+			{
+				label : editor.lang.anchor.toolbar,
+				command : 'anchor'
+			} );
+		CKEDITOR.dialog.add( 'link', this.path + 'dialogs/link.js' );
+		CKEDITOR.dialog.add( 'anchor', this.path + 'dialogs/anchor.js' );
+
+		// Add the CSS styles for anchor placeholders.
+		editor.addCss(
+			'img.cke_anchor' +
+			'{' +
+				'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/anchor.gif' ) + ');' +
+				'background-position: center center;' +
+				'background-repeat: no-repeat;' +
+				'border: 1px solid #a9a9a9;' +
+				'width: 18px;' +
+				'height: 18px;' +
+			'}\n' +
+			'a.cke_anchor' +
+			'{' +
+				'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/anchor.gif' ) + ');' +
+				'background-position: 0 center;' +
+				'background-repeat: no-repeat;' +
+				'border: 1px solid #a9a9a9;' +
+				'padding-left: 18px;' +
+			'}'
+		   	);
+
+		// Register selection change handler for the unlink button.
+		 editor.on( 'selectionChange', function( evt )
+			{
+				/*
+				 * Despite our initial hope, document.queryCommandEnabled() does not work
+				 * for this in Firefox. So we must detect the state by element paths.
+				 */
+				var command = editor.getCommand( 'unlink' ),
+					element = evt.data.path.lastElement.getAscendant( 'a', true );
+				if ( element && element.getName() == 'a' && element.getAttribute( 'href' ) )
+					command.state = CKEDITOR.TRISTATE_OFF;
+				else
+					command.state = CKEDITOR.TRISTATE_DISABLED;
+				command.fire( 'state' );
+			} );
+
+		// Register a contentDom handler for displaying placeholders after mode change.
+		editor.on( 'contentDom', function()
+			{
+				var rawAnchors = editor.document.$.anchors;
+				for ( var i = rawAnchors.length - 1, anchor ; i >= 0 ; i-- )
+				{
+					anchor = new CKEDITOR.dom.element( rawAnchors[ i ] );
+
+					// IE BUG: When an <a> tag doesn't have href, IE would return empty string
+					// instead of null on getAttribute.
+					if ( !anchor.getAttribute( 'href' ) )
+						editor.createFakeElement( anchor, 'cke_anchor', 'anchor' ).replace( anchor );
+					else
+						anchor.addClass( 'cke_anchor' );
+				}
+			} );
+	},
+
+	requires : [ 'fakeobjects' ]
+} );
+
+CKEDITOR.unlinkCommand = function(){};
+CKEDITOR.unlinkCommand.prototype =
+{
+	/** @ignore */
+	exec : function( editor )
+	{
+		/*
+		 * execCommand( 'unlink', ... ) in Firefox leaves behind <span> tags at where
+		 * the <a> was, so again we have to remove the link ourselves. (See #430)
+		 *
+		 * TODO: Use the style system when it's complete. Let's use execCommand()
+		 * as a stopgap solution for now.
+		 */
+		var selection = editor.getSelection(),
+			bookmarks = selection.createBookmarks(),
+			ranges = selection.getRanges(),
+			rangeRoot,
+			element;
+
+		for ( var i = 0 ; i < ranges.length ; i++ )
+		{
+			rangeRoot = ranges[i].getCommonAncestor( true );
+			element = rangeRoot.getAscendant( 'a', true );
+			if ( !element )
+				continue;
+			ranges[i].selectNodeContents( element );
+		}
+
+		selection.selectRanges( ranges );
+		editor.document.$.execCommand( 'unlink', false, null );
+		selection.selectBookmarks( bookmarks );
+	}
+};
+
+CKEDITOR.tools.extend( CKEDITOR.config,
+{
+	linkUploadTab : true,
+	linkBrowseServer : true,
+	linkUploadAction : 'nowhere.php',
+	linkShowAdvancedTab : true,
+	linkShowTargetTab : true
+} );
Index: /CKEditor/trunk/_source/plugins/table/dialogs/table.js
===================================================================
--- /CKEditor/trunk/_source/plugins/table/dialogs/table.js	(revision 3049)
+++ /CKEditor/trunk/_source/plugins/table/dialogs/table.js	(revision 3049)
@@ -0,0 +1,640 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+(function()
+{
+	var widthPattern = /^(\d+(?:\.\d+)?)(px|%)$/,
+		heightPattern = /^(\d+(?:\.\d+)?)px$/;
+
+	var commitValue = function( data )
+	{
+		var id = this.id;
+		if ( !data.info )
+			data.info = {};
+		data.info[id] = this.getValue();
+	};
+
+	// Copy all the attributes from one node to the other, kinda like a clone
+	// skipAttributes is an object with the attributes that must NOT be copied
+	function copyAttributes( source, dest, skipAttributes )
+	{
+		var attributes = source.$.attributes;
+
+		for ( var n = 0 ; n < attributes.length ; n++ )
+		{
+			var attribute = attributes[n];
+
+			if ( attribute.specified )
+			{
+				var attrName = attribute.nodeName;
+				// We can set the type only once, so do it with the proper value, not copying it.
+				if ( attrName in skipAttributes )
+					continue;
+
+				var attrValue = source.getAttribute( attrName );
+				if ( attrValue == null )
+					attrValue = attribute.nodeValue;
+
+				dest.setAttribute( attrName, attrValue );
+			}
+		}
+		// The style:
+		if ( source.$.style.cssText !== '' )
+			dest.$.style.cssText = source.$.style.cssText;
+	}
+
+	/**
+	* Replaces a tag with another one, keeping its contents:
+	* for example TD --> TH, and TH --> TD.
+	* input: the original node, and the new tag name
+	* http://www.w3.org/TR/DOM-Level-3-Core/core.html#Document3-renameNode
+	*/
+	function renameNode( node , newTag )
+	{
+		// Only rename element nodes.
+		if ( node.type != CKEDITOR.NODE_ELEMENT )
+			return null;
+
+		// If it's already correct exit here.
+		if ( node.getName() == newTag )
+			return node;
+
+		var doc = node.getDocument();
+
+		// Create the new node
+		var newNode = new CKEDITOR.dom.element( newTag, doc );
+
+		// Copy all attributes
+		copyAttributes( node, newNode, {} );
+
+		// Move children to the new node
+		node.moveChildren( newNode );
+
+		// Finally replace the node and return the new one
+		node.$.parentNode.replaceChild( newNode.$, node.$ );
+
+		return newNode;
+	}
+
+	function tableDialog( editor, command )
+	{
+		var makeElement = function( name ){ return new CKEDITOR.dom.element( name, editor.document ); };
+
+		return {
+			title : editor.lang.table.title,
+			minWidth : 480,
+			minHeight : 260,
+			onShow : function()
+			{
+				// Detect if there's a selected table.
+				this.restoreSelection();
+				var selection = editor.getSelection(),
+					ranges = selection.getRanges(),
+					selectedTable = null;
+
+				var rowsInput = this.getContentElement( 'info', 'txtRows' ),
+					colsInput = this.getContentElement( 'info', 'txtCols' ),
+					widthInput = this.getContentElement( 'info', 'txtWidth' );
+				if ( command == 'tableProperties' )
+				{
+					if ( ( selectedTable = this.getSelectedElement() ) )
+					{
+						if ( selectedTable.getName() != 'table' )
+							selectedTable = null;
+					}
+					else if ( ranges.length > 0 )
+					{
+						var rangeRoot = ranges[0].getCommonAncestor( true );
+						selectedTable = rangeRoot.getAscendant( 'table', true );
+					}
+
+					// Save a reference to the selected table, and push a new set of default values.
+					this._.selectedElement = selectedTable;
+				}
+
+				// Enable, disable and select the row, cols, width fields.
+				if ( selectedTable )
+				{
+					this.setupContent( selectedTable );
+					rowsInput && rowsInput.disable();
+					colsInput && colsInput.disable();
+					widthInput && widthInput.select();
+				}
+				else
+				{
+					rowsInput && rowsInput.enable();
+					colsInput && colsInput.enable();
+					rowsInput && rowsInput.select();
+				}
+			},
+			onOk : function()
+			{
+				var table = this._.selectedElement || makeElement( 'table' ),
+					me = this,
+					data = {};
+
+				this.commitContent( data, table );
+
+				if ( data.info )
+				{
+					var info = data.info;
+
+					// Generate the rows and cols.
+					if ( !this._.selectedElement )
+					{
+						var tbody = table.append( makeElement( 'tbody' ) ),
+							rows = parseInt( info.txtRows, 10 ) || 0;
+							cols = parseInt( info.txtCols, 10 ) || 0;
+
+						for ( var i = 0 ; i < rows ; i++ )
+						{
+							var row = tbody.append( makeElement( 'tr' ) );
+							for ( var j = 0 ; j < cols ; j++ )
+							{
+								var cell = row.append( makeElement( 'td' ) );
+								if ( !CKEDITOR.env.ie )
+									cell.append( makeElement( 'br' ) );
+							}
+						}
+					}
+
+					// Modify the table headers. Depends on havint rows and cols generated
+					// correctly so it can't be done in commit functions.
+					
+					// Should we make a <thead>?
+					var headers = info.selHeaders;
+					if ( table.$.tHead == null && ( headers == 'row' || headers == 'both' ) )
+					{
+						var thead = new CKEDITOR.dom.element( table.$.createTHead() ),
+							tbody = table.getElementsByTag( 'tbody' ).getItem( 0 ),
+							theRow = tbody.getElementsByTag( 'tr' ).getItem( 0 );
+
+						// Change TD to TH:
+						for ( var i = 0 ; i < theRow.getChildCount() ; i++ )
+						{
+							var th = renameNode( theRow.getChild( i ), 'th' );
+							if ( th != null )
+								th.setAttribute( 'scope', 'col' );
+						}
+						thead.append( theRow.remove() );
+					}
+
+					if ( table.$.tHead !== null && !( headers == 'row' || headers == 'both' ) )
+					{
+						// Move the row out of the THead and put it in the TBody:
+						var thead = new CKEDITOR.dom.element( table.$.tHead ),
+							tbody = table.getElementsByTag( 'tbody' ).getItem( 0 );
+
+						var previousFirstRow = tbody.getFirst();
+						while ( thead.getChildCount() > 0 )
+						{
+							var theRow = thead.getFirst();
+							for ( var i = 0; i < theRow.getChildCount() ; i++ )
+							{
+								var newCell = renameNode( theRow.getChild( i ), 'td' );
+								if ( newCell != null )
+									newCell.removeAttribute( 'scope' );
+							}
+							theRow.insertBefore( previousFirstRow );
+						}
+						thead.remove();
+					}
+
+					// Should we make all first cells in a row TH?
+					if ( !this.hasColumnHeaders && ( headers == 'col' || headers == 'both' ) )
+					{
+						for( var row = 0 ; row < table.$.rows.length ; row++ )
+						{
+							var newCell = renameNode( new CKEDITOR.dom.element( table.$.rows[row].cells[0] ), 'th' );
+							if ( newCell != null )
+								newCell.setAttribute( 'scope', 'col' );
+						}
+					}
+
+					// Should we make all first TH-cells in a row make TD? If 'yes' we do it the other way round :-)
+					if ( ( this.hasColumnHeaders ) && !( headers == 'col' || headers == 'both' ) )
+					{
+						for( var i = 0 ; i < table.$.rows.length ; i++ )
+						{
+							var row = new CKEDITOR.dom.element( table.$.rows[i] );
+							if ( row.getParent().getName() == 'tbody' )
+							{
+								var newCell = renameNode( new CKEDITOR.dom.element( row.$.cells[0] ), 'td' );
+								if ( newCell != null )
+									newCell.removeAttribute( 'scope' );
+							}
+						}
+					}
+
+					// Set the width and height.
+					var styles = [];
+					if ( info.txtHeight )
+						styles.push( 'height:' + info.txtHeight + 'px' );
+					if ( info.txtWidth )
+					{
+						var type = info.cmbWidthType || 'pixels';
+						styles.push( 'width:' + info.txtWidth + ( type == 'pixels' ? 'px' : '%' ) );
+					}
+					styles = styles.join( ';' );
+					if ( styles != '' )
+						table.$.style.cssText = styles;
+					else
+						table.removeAttribute( 'style' );
+				}
+
+				// Insert the table element if we're creating one.
+				if ( !this._.selectedElement )
+				{
+					this.restoreSelection();
+					editor.insertElement( table );
+					this.clearSavedSelection();
+				}
+
+				return true;
+			},
+			contents : [
+				{
+					id : 'info',
+					label : editor.lang.table.title,
+					accessKey : 'I',
+					elements :
+					[
+						{
+							type : 'hbox',
+							widths : [ '40%', '10%', '60%' ],
+							children :
+							[
+								{
+									type : 'vbox',
+									padding : 0,
+									children :
+									[
+										{
+											type : 'text',
+											id : 'txtRows',
+											labelLayout : 'horizontal',
+											widths : [ '60%','40%' ],
+											style : 'width:105px',
+											'default' : 3,
+											label : editor.lang.table.rows,
+											validate : function()
+											{
+												var pass = true,
+													value = this.getValue();
+												pass = pass && CKEDITOR.dialog.validate.integer()( value )
+													&& value > 0;
+												if ( !pass )
+												{
+													alert( editor.lang.table.invalidRows );
+													this.select();
+												}
+												return pass;
+											},
+											setup : function( selectedElement )
+											{
+												this.setValue( selectedElement.$.rows.length );
+											},
+											commit : commitValue
+										},
+										{
+											type : 'text',
+											id : 'txtCols',
+											labelLayout : 'horizontal',
+											widths : [ '60%','40%' ],
+											style : 'width:105px',
+											'default' : 2,
+											label : editor.lang.table.columns,
+											validate : function()
+											{
+												var pass = true,
+													value = this.getValue();
+												pass = pass && CKEDITOR.dialog.validate.integer()( value )
+													&& value > 0;
+												if ( !pass )
+												{
+													alert( editor.lang.table.invalidCols );
+													this.select();
+												}
+												return pass;
+											},
+											setup : function( selectedTable )
+											{
+												this.setValue( selectedTable.$.rows[0].cells.length);
+											},
+											commit : commitValue
+										},
+										{
+											type : 'select',
+											id : 'selHeaders',
+											labelLayout : 'horizontal',
+											'default' : '',
+											widths : [ '40%', '60%' ],
+											label : editor.lang.table.headers,
+											items :
+											[
+												[ editor.lang.table.headersNone, '' ],
+												[ editor.lang.table.headersRow, 'row' ],
+												[ editor.lang.table.headersColumn, 'col' ],
+												[ editor.lang.table.headersBoth, 'both' ]
+											],
+											setup : function( selectedTable )
+											{
+												// Fill in the headers field.
+												var dialog = this.getDialog();
+												dialog.hasColumnHeaders = true;
+
+												// Check if all the first cells in every row are TH
+												for ( var row = 0 ; row < selectedTable.$.rows.length ; row++ )
+												{
+													// If just one cell isn't a TH then it isn't a header column
+													if ( selectedTable.$.rows[row].cells[0].nodeName.toLowerCase() != 'th' )
+													{
+														dialog.hasColumnHeaders = false;
+														break;
+													}
+												}
+
+												// Check if the table contains <thead>.
+												if ( ( selectedTable.$.tHead !== null) )
+													this.setValue( dialog.hasColumnHeaders ? 'both' : 'row' );
+												else
+													this.setValue( dialog.hasColumnHeaders ? 'col' : '' );
+											},
+											commit : commitValue
+										},
+										{
+											type : 'text',
+											id : 'txtBorder',
+											labelLayout : 'horizontal',
+											widths : [ '60%','40%' ],
+											style : 'width:105px',
+											'default' : 1,
+											label : editor.lang.table.border,
+											validate : CKEDITOR.dialog.validate['number']( editor.lang.table.invalidBorder ),
+											setup : function( selectedTable )
+											{
+												this.setValue( selectedTable.getAttribute( 'border' ) || '' );
+											},
+											commit : function( data, selectedTable )
+											{
+												if ( this.getValue() )
+													selectedTable.setAttribute( 'border', this.getValue() );
+												else
+													selectedTable.removeAttribute( 'border' );
+											}
+										},
+										{
+											id : 'cmbAlign',
+											type : 'select',
+											labelLayout : 'horizontal',
+											'default' : '',
+											widths : [ '40%','60%' ],
+											label : editor.lang.table.align,
+											items :
+											[
+												[ editor.lang.table.alignNotSet , ''],
+												[ editor.lang.table.alignLeft , 'left'],
+												[ editor.lang.table.alignCenter , 'center'],
+												[ editor.lang.table.alignRight , 'right']
+											],
+											setup : function( selectedTable )
+											{
+												this.setValue( selectedTable.getAttribute( 'align' ) || '' );
+											},
+											commit : function( data, selectedTable )
+											{
+												if ( this.getValue() )
+													selectedTable.setAttribute( 'align', this.getValue() );
+												else
+													selectedTable.removeAttribute( 'align' );
+											}
+										}
+									]
+								},
+								{
+									type : 'html',
+									align : 'right',
+									html : ''
+								},
+								{
+									type : 'vbox',
+									align : 'right',
+									padding : 0,
+									children :
+									[
+										{
+											type : 'hbox',
+											align : 'center',
+											widths : [ '70%', '30%' ],
+											children :
+											[
+												{
+													type : 'text',
+													id : 'txtWidth',
+													labelLayout : 'horizontal',
+													widths : [ '50%','50%' ],
+													label : editor.lang.table.width,
+													'default' : 200,
+													validate : CKEDITOR.dialog.validate['number']( editor.lang.table.invalidWidth ),
+													setup : function( selectedTable )
+													{
+														var widthMatch = widthPattern.exec( selectedTable.$.style.width );
+														if ( widthMatch )
+															this.setValue( widthMatch[1] );
+													},
+													commit : commitValue
+												},
+												{
+													id : 'cmbWidthType',
+													type : 'select',
+													labelLayout : 'horizontal',
+													widths : [ '0%','100%' ],
+													label : '',
+													'default' : 'pixels',
+													items :
+													[
+														[ editor.lang.table.widthPx , 'pixels'],
+														[ editor.lang.table.widthPc , 'percents']
+													],
+													setup : function( selectedTable )
+													{
+														var widthMatch = widthPattern.exec( selectedTable.$.style.width );
+														if ( widthMatch )
+															this.setValue( widthMatch[2] == 'px' ? 'pixels' : 'percents' );
+													},
+													commit : commitValue
+												}
+											]
+										},
+										{
+											type : 'hbox',
+											widths : [ '70%', '30%' ],
+											children :
+											[
+												{
+													type : 'text',
+													id : 'txtHeight',
+													labelLayout : 'horizontal',
+													widths : [ '50%','50%' ],
+													label : editor.lang.table.height,
+													'default' : '',
+													validate : CKEDITOR.dialog.validate['number']( editor.lang.table.invalidHeight ),
+													setup : function( selectedTable )
+													{
+														var heightMatch = heightPattern.exec( selectedTable.$.style.height );
+														if ( heightMatch )
+															this.setValue( heightMatch[1] );
+													},
+													commit : commitValue
+												},
+												{
+													type : 'html',
+													html : editor.lang.table.widthPx
+												}
+											]
+										},
+										{
+											type : 'html',
+											html : '&nbsp;'
+										},
+										{
+											type : 'text',
+											id : 'txtCellSpace',
+											labelLayout : 'horizontal',
+											widths : [ '50%','50%' ],
+											style : 'width:140px',
+											label : editor.lang.table.cellSpace,
+											'default' : 1,
+											validate : CKEDITOR.dialog.validate['number']( editor.lang.table.invalidCellSpacing ),
+											setup : function( selectedTable )
+											{
+												this.setValue( selectedTable.getAttribute( 'cellSpacing' ) || '' );
+											},
+											commit : function( data, selectedTable )
+											{
+												if ( this.getValue() )
+													selectedTable.setAttribute( 'cellSpacing', this.getValue() );
+												else
+													setAttribute.removeAttribute( 'cellSpacing' );
+											}
+										},
+										{
+											type : 'text',
+											id : 'txtCellPad',
+											labelLayout : 'horizontal',
+											widths : [ '50%','50%' ],
+											style : 'width:140px',
+											label : editor.lang.table.cellPad,
+											'default' : 1,
+											validate : CKEDITOR.dialog.validate['number']( editor.lang.table.invalidCellPadding ),
+											setup : function( selectedTable )
+											{
+												this.setValue( selectedTable.getAttribute( 'cellPadding' ) || '' );
+											},
+											commit : function( data, selectedTable )
+											{
+												if ( this.getValue() )
+													selectedTable.setAttribute( 'cellPadding', this.getValue() );
+												else
+													selectedTable.removeAttribute( 'cellPadding' );
+											}
+										}
+									]
+								}
+							]
+						},
+						{
+							type : 'html',
+							align : 'right',
+							html : ''
+						},
+						{
+							type : 'vbox',
+							padding : 0,
+							children :
+							[
+								{
+									id : 'txtCaption',
+									type : 'text',
+									label : editor.lang.table.caption,
+									widths : [ '30%','70%' ],
+									labelLayout : 'horizontal',
+									'default' : '',
+									style : 'width:400px',
+									setup : function( selectedTable )
+									{
+										var nodeList = selectedTable.getElementsByTag( 'caption' );
+										if ( nodeList.count() > 0 )
+										{
+											var caption = nodeList.getItem( 0 );
+											caption = ( caption.getChild( 0 ) && caption.getChild( 0 ).getText() ) || '';
+											caption = CKEDITOR.tools.trim( caption );
+											this.setValue( caption );
+										}
+									},
+									commit : function( data, table )
+									{
+										var caption = this.getValue(),
+											captionElement = table.getElementsByTag( 'caption' );
+										if ( caption != '' )
+										{
+											if ( captionElement.count() > 0 )
+											{
+												captionElement = captionElement.getItem( 0 );
+												captionElement.setHtml( '' );
+											}
+											else
+											{
+												captionElement = new CKEDITOR.dom.element( 'caption', editor.document );
+												if ( table.getChildCount() )
+													captionElement.insertBefore( table.getFirst() );
+												else
+													captionElement.appendTo( table );
+											}
+											captionElement.append( new CKEDITOR.dom.text( caption, editor.document ) );
+										}
+										else if ( captionElement.count() > 0 )
+										{
+											for ( var i = captionElement.count() - 1 ; i >= 0 ; i-- )
+												captionElement.getItem( i ).remove();
+										}
+									}
+								},
+								{
+									id : 'txtSummary',
+									type : 'text',
+									labelLayout : 'horizontal',
+									label : editor.lang.table.summary,
+									'default' : '',
+									widths : [ '30%','70%' ],
+									accessKey : 'A',
+									style : 'width:400px',
+									setup : function( selectedTable )
+									{
+										this.setValue( selectedTable.getAttribute( 'summary' ) || '' );
+									},
+									commit : function( data, selectedTable )
+									{
+										if ( this.getValue() )
+											selectedTable.setAttribute( 'summary', this.getValue() );
+									}
+								}
+							]
+						}
+					]
+				}
+			]
+		};
+	}
+
+	CKEDITOR.dialog.add( 'table', function( editor )
+		{
+			return tableDialog( editor, 'table' );
+		} );
+	CKEDITOR.dialog.add( 'tableProperties', function( editor )
+		{
+			return tableDialog( editor, 'tableProperties' );
+		} );
+})();
Index: /CKEditor/trunk/_source/plugins/table/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/table/plugin.js	(revision 3049)
+++ /CKEditor/trunk/_source/plugins/table/plugin.js	(revision 3049)
@@ -0,0 +1,23 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+CKEDITOR.plugins.add( 'table',
+{
+	init : function( editor )
+	{
+		var table = CKEDITOR.plugins.table;
+
+		editor.addCommand( 'table', new CKEDITOR.dialogCommand( 'table' ) );
+		editor.addCommand( 'tableProperties', new CKEDITOR.dialogCommand( 'tableProperties' ) );
+		editor.ui.addButton( 'Table',
+			{
+				label : editor.lang.table.toolbar,
+				command : 'table'
+			});
+
+		CKEDITOR.dialog.add( 'table', this.path + 'dialogs/table.js' );
+		CKEDITOR.dialog.add( 'tableProperties', this.path + 'dialogs/table.js' );
+	}
+} );
