Index: /CKEditor/branches/prototype/_source/core/dom/node.js
===================================================================
--- /CKEditor/branches/prototype/_source/core/dom/node.js	(revision 2752)
+++ /CKEditor/branches/prototype/_source/core/dom/node.js	(revision 2753)
@@ -354,4 +354,9 @@
 		},
 
+		/**
+		 * Gets the closes ancestor node of a specified node name.
+		 * @param {String} name Node name of ancestor node.
+		 * @returns {CKEDITOR.dom.node} Ancestor node.
+		 */
 		getAscendant : function( name )
 		{
Index: /CKEditor/branches/prototype/_source/lang/en.js
===================================================================
--- /CKEditor/branches/prototype/_source/lang/en.js	(revision 2752)
+++ /CKEditor/branches/prototype/_source/lang/en.js	(revision 2753)
@@ -131,4 +131,5 @@
 	linkEmailSubject	: 'Message Subject',
 	linkEmailBody		: 'Message Body',
+	linkNoAnchors		: '(No anchors available in the document)',
 	linkNoUrl			: 'Please type the link URL',
 	linkNoEmail			: 'Please type the e-mail address',
Index: /CKEditor/branches/prototype/_source/plugins/dialogui/plugin.js
===================================================================
--- /CKEditor/branches/prototype/_source/plugins/dialogui/plugin.js	(revision 2752)
+++ /CKEditor/branches/prototype/_source/plugins/dialogui/plugin.js	(revision 2753)
@@ -894,4 +894,57 @@
 				{
 					return this._.select.getElement();
+				},
+
+				/**
+				 * Adds an option to the select box.
+				 * @param {String} label Option label.
+				 * @param {String} value (Optional) Option value, if not defined it'll be
+				 * assumed to be the same as the label.
+				 * @param {Number} index (Optional) Position of the option to be inserted
+				 * to. If not defined the new option will be inserted to the end of list.
+				 * @example
+				 * @returns {CKEDITOR.ui.dialog.select} The current select UI element.
+				 */
+				add : function( label, value, index )
+				{
+					var option = new CKEDITOR.dom.element( 'option', this.getDialog().getParentEditor().document ),
+						selectElement = this.getInputElement().$;
+					option.$.text = label;
+					option.$.value = ( value === undefined || value === null ) ? label : value;
+					if ( index === undefined || index === null )
+					{
+						if ( CKEDITOR.env.ie )
+							selectElement.add( option.$ );
+						else
+							selectElement.add( option.$, null );
+					}
+					else
+						selectElement.add( option.$, index );
+					return this;
+				},
+
+				/**
+				 * Removes an option from the selection list.
+				 * @param {Number} index Index of the option to be removed.
+				 * @example
+				 * @returns {CKEDITOR.ui.dialog.select} The current select UI element.
+				 */
+				remove : function( index )
+				{
+					var selectElement = this.getInputElement().$;
+					selectElement.remove( index );
+					return this;
+				},
+
+				/**
+				 * Clears all options out of the selection list.
+				 * @returns {CKEDITOR.ui.dialog.select} The current select UI element.
+				 */
+				clear : function()
+				{
+					var selectElement = this.getInputElement().$;
+					while ( selectElement.length > 0 )
+						selectElement.remove( 0 );
+					return this;
 				}
 			}, commonPrototype, true );
Index: /CKEditor/branches/prototype/_source/plugins/link/dialogs/link.js
===================================================================
--- /CKEditor/branches/prototype/_source/plugins/link/dialogs/link.js	(revision 2752)
+++ /CKEditor/branches/prototype/_source/plugins/link/dialogs/link.js	(revision 2753)
@@ -65,4 +65,48 @@
 				element.hide();
 		}
+	},
+		emailRegex = /^mailto:([^?]+)(?:\?(.+))?$/,
+		emailSubjectRegex = /subject=([^;?:@&=$,\/]*)/,
+		emailBodyRegex = /body=([^;?:@&=$,\/]*)/,
+		anchorRegex = /^#(.*)$/,
+		urlRegex = /^((?:http|https|ftp|news):\/\/)?(.*)$/,
+		loadLink = function( editor, selection, ranges, element )
+	{
+		var href = element.getAttribute( '_cksavedhref' ) || element.getAttribute( 'href' ),
+			emailMatch = href.match( emailRegex ),
+			anchorMatch = href.match( anchorRegex );
+
+		// Load the link type and URL.
+		if ( emailMatch )
+		{
+			var subjectMatch = href.match( emailSubjectRegex ),
+				bodyMatch = href.match( emailBodyRegex );
+			this.setValueOf( 'info', 'linkType', 'email' );
+			this.setValueOf( 'info', 'emailAddress', emailMatch[1] );
+			subjectMatch && this.setValueOf( 'info', 'emailSubject', decodeURIComponent( subjectMatch[1] ) );
+			bodyMatch && this.setValueOf( 'info', 'emailBody', decodeURIComponent( bodyMatch[1] ) );
+		}
+		else if ( anchorMatch )
+		{
+			this.setValueOf( 'info', 'linkType', 'anchor' );
+			this.setValueOf( 'info', 'anchorName', anchorMatch[1] );
+			this.setValueOf( 'info', 'anchorId', anchorMatch[1] );
+		}
+		else
+		{
+			var urlMatch = href.match( urlRegex );
+			this.setValueOf( 'info', 'linkType', 'url' );
+			this.setValueOf( 'info', 'protocol', urlMatch[1] );
+			this.setValueOf( 'info', 'url', urlMatch[2] );
+		}
+
+		// Load target.
+
+		// Load popup settings.
+
+		// Load advanced attributes.
+
+		// Record down the selected element in the dialog.
+		this._.selectedElement = element;
 	};
 
@@ -148,8 +192,16 @@
 							{
 								type : 'html',
+								id : 'selectAnchorText',
 								html : CKEDITOR.tools.htmlEncode( editor.lang.linkSelectAnchor )
 							},
 							{
-								type : 'hbox',
+								type : 'html',
+								id : 'noAnchors',
+								style : 'text-align: center;',
+								html : '<div>' + CKEDITOR.tools.htmlEncode( editor.lang.linkNoAnchors ) + '</div>'
+							},
+							{
+								type : 'hbox',
+								id : 'selectAnchor',
 								children :
 								[
@@ -516,4 +568,48 @@
 		onShow : function()
 		{
+			var editor = this.getParentEditor(),
+				selection = editor.getSelection(),
+				ranges = selection.getRanges();
+
+			// Find out whether we have any anchors in the editor.
+			var anchors = editor.document.$.anchors;
+			if ( anchors.length < 1 )
+			{
+				this.getContentElement( 'info', 'selectAnchor' ).getElement().hide();
+				this.getContentElement( 'info', 'selectAnchorText' ).getElement().hide();
+				this.getContentElement( 'info', 'noAnchors' ).getElement().show();
+			}
+			else
+			{
+				this.getContentElement( 'info', 'selectAnchor' ).getElement().show();
+				this.getContentElement( 'info', 'selectAnchorText' ).getElement().show();
+				this.getContentElement( 'info', 'noAnchors' ).getElement().hide();
+
+				var names = this.getContentElement( 'info', 'anchorName' ).clear(),
+					ids = this.getContentElement( 'info', 'anchorId' ).clear();
+				names.add( '' );
+				ids.add( '' );
+				for ( var i = 0 ; i < anchors.length ; i++ )
+				{
+					if ( anchors[i].getAttribute( 'name' ) )
+						names.add( anchors[i].getAttribute( 'name' ) );
+					else if ( anchors[i].getAttribute( 'id' ) )
+						names.add( anchors[i].getAttribute( 'id' ) );
+				}
+				names.setValue( '' );
+				ids.setValue( '' );
+			}
+			
+			// Fill in all the relevant fields if there's already one link selected.
+			if ( ranges.length == 1 )
+			{
+				var rangeRoot = ranges[0].getCommonAncestor(),
+					element = rangeRoot && rangeRoot.getAscendant( 'a' );
+				if ( element && element.getAttribute( 'href' ) )
+					loadLink.apply( this, [ editor, selection, ranges, element ] );
+				selection.selectElement( element );
+				this.saveSelection();
+			}
+
 			this.getContentElement( 'info', 'url' ).focus();
 		},
@@ -521,5 +617,5 @@
 		{
 			var attributes = { href : 'javascript:void(0)/*' + CKEDITOR.tools.getNextNumber() + '*/' },
-				linkList, subject, body, me = this;
+				linkList, subject, body, me = this, editor = this.getParentEditor();
 
 			// Compose the URL.
@@ -534,11 +630,13 @@
 				case 'email':
 					linkList = [ 'mailto:', this.getValueOf( 'info', 'emailAddress' ) ];
-					subject = encodeURICompoenent( this.getValueOf( 'info', 'emailSubject' ) );
+					subject = encodeURIComponent( this.getValueOf( 'info', 'emailSubject' ) );
 					body = encodeURIComponent( this.getValueOf( 'info', 'emailBody' ) );
 					if ( subject || body)
 					{
+						var argList = [];
 						linkList.push( '?' );
-						subject && linkList.push( 'subject=', subject );
-						body && body.push( 'body=', body );
+						subject && argList.push( 'subject=' + subject );
+						body && argList.push( 'body=' + body );
+						linkList.push( argList.join( '&' ) );
 					}
 					attributes._cksavedhref = linkList.join( '' );
@@ -595,26 +693,43 @@
 			advAttr( 'advStyles', 'style' );
 
-			// Create element if current selection is collapsed, else apply style.
-			var style = new CKEDITOR.style( { element : 'a', attributes : attributes } );
-			style.type = CKEDITOR.STYLE_INLINE;		// need to override... dunno why.
-			style.apply( this.getParentEditor().document );
-			
-			// Id. Apply only to the first link.
-			if ( this.getValueOf( 'advanced', 'advId' ) != '' )
-			{
-				var links = this.getParentEditor().document.$.getElementsByTagName( 'a' );
-				for ( var i = 0 ; i < links.length ; i++ )
+			if ( !this._.selectedElement )
+			{
+				// Create element if current selection is collapsed.
+				var selection = editor.getSelection(),
+					ranges = selection.getRanges();
+				if ( ranges.length == 1 && ranges[0].collapsed )
 				{
-					if ( links[i].href == attributes.href )
-					{
-						console.log( 'fadhm' );
-						links[i].id = this.getValueOf( 'advanced', 'advId' );
-						break;
+					ranges[0].insertNode( new CKEDITOR.dom.text( attributes._cksavedhref, editor.document ) );
+					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 ( this.getValueOf( 'advanced', '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 = this.getValueOf( 'advanced', 'advId' );
+							break;
+						}
 					}
 				}
-			}
-
-			// style.apply() changed the selection already, so clear the old one.
-			this.clearSavedSelection();
+			
+				// style.apply() changed the selection already, so clear the old one.
+				this.clearSavedSelection();
+			}
+			else
+			{
+				// We're only editing an existing link, so just overwrite the attributes.
+				this._.selectedElement.setAttributes( attributes );
+				delete this._.selectedElement;
+			}
 		}
 	};
Index: /CKEditor/branches/prototype/_source/plugins/link/plugin.js
===================================================================
--- /CKEditor/branches/prototype/_source/plugins/link/plugin.js	(revision 2752)
+++ /CKEditor/branches/prototype/_source/plugins/link/plugin.js	(revision 2753)
@@ -53,7 +53,5 @@
 } );
 
-CKEDITOR.unlinkCommand = function()
-{
-};
+CKEDITOR.unlinkCommand = function(){};
 CKEDITOR.unlinkCommand.prototype =
 {
