Index: src/wp-includes/class-wp-editor.php
===================================================================
--- src/wp-includes/class-wp-editor.php	(revision 31691)
+++ src/wp-includes/class-wp-editor.php	(working copy)
@@ -1449,13 +1449,13 @@
 			<div id="link-options">
 				<p class="howto"><?php _e( 'Enter the destination URL' ); ?></p>
 				<div>
-					<label><span><?php _e( 'URL' ); ?></span><input id="url-field" type="text" name="href" /></label>
+					<label><span><?php _e( 'Text' ); ?></span><input id="wp-link-text" type="text" /></label>
 				</div>
 				<div>
-					<label><span><?php _e( 'Title' ); ?></span><input id="link-title-field" type="text" name="linktitle" /></label>
+					<label><span><?php _e( 'Link' ); ?></span><input id="wp-link-url" type="text" /></label>
 				</div>
 				<div class="link-target">
-					<label><span>&nbsp;</span><input type="checkbox" id="link-target-checkbox" /> <?php _e( 'Open link in a new window/tab' ); ?></label>
+					<label><span>&nbsp;</span><input type="checkbox" id="wp-link-target" /> <?php _e( 'Open link in a new window/tab' ); ?></label>
 				</div>
 			</div>
 			<p class="howto"><a href="#" id="wp-link-search-toggle"><?php _e( 'Or link to existing content' ); ?></a></p>
@@ -1463,7 +1463,7 @@
 				<div class="link-search-wrapper">
 					<label>
 						<span class="search-label"><?php _e( 'Search' ); ?></span>
-						<input type="search" id="search-field" class="link-search-field" autocomplete="off" />
+						<input type="search" id="wp-link-search" class="link-search-field" autocomplete="off" />
 						<span class="spinner"></span>
 					</label>
 				</div>
Index: src/wp-includes/js/tinymce/plugins/wplink/plugin.js
===================================================================
--- src/wp-includes/js/tinymce/plugins/wplink/plugin.js	(revision 31691)
+++ src/wp-includes/js/tinymce/plugins/wplink/plugin.js	(working copy)
@@ -1,12 +1,7 @@
 /* global tinymce */
 tinymce.PluginManager.add( 'wplink', function( editor ) {
-	var linkButton;
-
-	// Register a command so that it can be invoked by using tinyMCE.activeEditor.execCommand( 'WP_Link' );
 	editor.addCommand( 'WP_Link', function() {
-		if ( ( ! linkButton || ! linkButton.disabled() ) && typeof window.wpLink !== 'undefined' ) {
-			window.wpLink.open( editor.id );
-		}
+		window.wpLink && window.wpLink.open( editor.id );
 	});
 
 	// WP default shortcut
@@ -14,41 +9,18 @@
 	// The "de-facto standard" shortcut, see #27305
 	editor.addShortcut( 'ctrl+k', '', 'WP_Link' );
 
-	function setState( button, node ) {
-		var parent = editor.dom.getParent( node, 'a' ),
-			getView = editor.plugins.wpview ? editor.plugins.wpview.getView : function() { return false; };
-
-		button.disabled( ( editor.selection.isCollapsed() && ! parent ) || ( parent && ! parent.href ) || getView( node ) );
-		button.active( parent && parent.href );
-	}
-
 	editor.addButton( 'link', {
 		icon: 'link',
 		tooltip: 'Insert/edit link',
 		shortcut: 'Alt+Shift+A',
 		cmd: 'WP_Link',
-
-		onPostRender: function() {
-			linkButton = this;
-
-			editor.on( 'nodechange', function( event ) {
-				setState( linkButton, event.element );
-			});
-		}
+		stateSelector: 'a[href]'
 	});
 
 	editor.addButton( 'unlink', {
 		icon: 'unlink',
 		tooltip: 'Remove link',
-		cmd: 'unlink',
-
-		onPostRender: function() {
-			var unlinkButton = this;
-
-			editor.on( 'nodechange', function( event ) {
-				setState( unlinkButton, event.element );
-			});
-		}
+		cmd: 'unlink'
 	});
 
 	editor.addMenuItem( 'link', {
Index: src/wp-includes/js/wplink.js
===================================================================
--- src/wp-includes/js/wplink.js	(revision 31691)
+++ src/wp-includes/js/wplink.js	(working copy)
@@ -7,6 +7,10 @@
 		rivers = {},
 		isTouch = ( 'ontouchend' in document );
 
+	function getLink() {
+		return editor.dom.getParent( editor.selection.getNode(), 'a' );
+	}
+
 	wpLink = {
 		timeToTriggerRiver: 150,
 		minRiverAJAXDuration: 200,
@@ -21,14 +25,14 @@
 			inputs.backdrop = $( '#wp-link-backdrop' );
 			inputs.submit = $( '#wp-link-submit' );
 			inputs.close = $( '#wp-link-close' );
-			// URL
-			inputs.url = $( '#url-field' );
+
+			// Input
+			inputs.text = $( '#wp-link-text' );
+			inputs.url = $( '#wp-link-url' );
 			inputs.nonce = $( '#_ajax_linking_nonce' );
-			// Secondary options
-			inputs.title = $( '#link-title-field' );
-			// Advanced Options
-			inputs.openInNewTab = $( '#link-target-checkbox' );
-			inputs.search = $( '#search-field' );
+			inputs.openInNewTab = $( '#wp-link-target' );
+			inputs.search = $( '#wp-link-search' );
+
 			// Build Rivers
 			rivers.search = new River( $( '#search-results' ) );
 			rivers.recent = new River( $( '#most-recent-results' ) );
@@ -129,6 +133,7 @@
 			inputs.backdrop.show();
 
 			wpLink.refresh();
+
 			$( document ).trigger( 'wplink-open', inputs.wrap );
 		},
 
@@ -165,22 +170,51 @@
 			correctedURL = inputs.url.val().replace( /^http:\/\//, '' );
 		},
 
+		selectedText: function( object ) {
+			var childNodes,
+				i;
+
+			if ( typeof object === 'string' ) {
+				return /</.test( object ) ? '' : object;
+			} else {
+				childNodes = object.childNodes;
+				i = childNodes.length;
+
+				if ( ! i ) {
+					return '';
+				}
+
+				while ( i-- ) {
+					if ( childNodes[ i ].nodeType !== 3 ) {
+						return '';
+					}
+				}
+
+				return object.textContent || object.innerText;
+			}
+		},
+
 		mceRefresh: function() {
-			var e;
+			var node = getLink(),
+				text;
 
-			// If link exists, select proper values.
-			if ( e = editor.dom.getParent( editor.selection.getNode(), 'A' ) ) {
-				// Set URL and description.
-				inputs.url.val( editor.dom.getAttrib( e, 'href' ) );
-				inputs.title.val( editor.dom.getAttrib( e, 'title' ) );
-				// Set open in new tab.
-				inputs.openInNewTab.prop( 'checked', ( '_blank' === editor.dom.getAttrib( e, 'target' ) ) );
-				// Update save prompt.
+			if ( ! node && editor.selection.isCollapsed() ) {
+				editor.undoManager.transact( function() {
+					editor.execCommand( 'mceInsertLink', false, { href: '#' } );
+					editor.selection.select( getLink() );
+					editor.execCommand( 'unlink' );
+				} );
+			}
+
+			if ( node ) {
+				text = this.selectedText( node );
+
+				inputs.text.val( text ).prop( 'disabled', ! text );
+				inputs.url.val( editor.dom.getAttrib( node, 'href' ) );
+				inputs.openInNewTab.prop( 'checked', '_blank' === editor.dom.getAttrib( node, 'target' ) );
 				inputs.submit.val( wpLinkL10n.update );
-
-			// If there's no link, set the default values.
 			} else {
-				wpLink.setDefaultValues();
+				this.setDefaultValues();
 			}
 		},
 
@@ -209,39 +243,37 @@
 		getAttrs: function() {
 			return {
 				href: $.trim( inputs.url.val() ),
-				title: $.trim( inputs.title.val() ),
 				target: inputs.openInNewTab.prop( 'checked' ) ? '_blank' : ''
 			};
 		},
 
 		update: function() {
-			if ( wpLink.isMCE() )
+			if ( wpLink.isMCE() ) {
 				wpLink.mceUpdate();
-			else
+			} else {
 				wpLink.htmlUpdate();
+			}
 		},
 
 		htmlUpdate: function() {
-			var attrs, html, begin, end, cursor, title, selection,
+			var attrs, text, html, begin, end, cursor, selection,
 				textarea = wpLink.textarea;
 
-			if ( ! textarea )
+			if ( ! textarea ) {
 				return;
+			}
 
 			attrs = wpLink.getAttrs();
+			text = $.trim( inputs.text.val() );
 
 			// If there's no href, return.
-			if ( ! attrs.href )
+			if ( ! attrs.href ) {
 				return;
+			}
 
 			// Build HTML
 			html = '<a href="' + attrs.href + '"';
 
-			if ( attrs.title ) {
-				title = attrs.title.replace( /</g, '&lt;' ).replace( />/g, '&gt;' ).replace( /"/g, '&quot;' );
-				html += ' title="' + title + '"';
-			}
-
 			if ( attrs.target ) {
 				html += ' target="' + attrs.target + '"';
 			}
@@ -254,25 +286,29 @@
 				// Note: If no text is selected, IE will not place the cursor
 				//       inside the closing tag.
 				textarea.focus();
-				wpLink.range.text = html + wpLink.range.text + '</a>';
+				wpLink.range.text = html + ( text || wpLink.range.text ) + '</a>';
 				wpLink.range.moveToBookmark( wpLink.range.getBookmark() );
 				wpLink.range.select();
 
 				wpLink.range = null;
 			} else if ( typeof textarea.selectionStart !== 'undefined' ) {
 				// W3C
-				begin       = textarea.selectionStart;
-				end         = textarea.selectionEnd;
-				selection   = textarea.value.substring( begin, end );
-				html        = html + selection + '</a>';
-				cursor      = begin + html.length;
+				begin = textarea.selectionStart;
+				end = textarea.selectionEnd;
+				selection = text || textarea.value.substring( begin, end );
+				html = html + selection + '</a>';
+				cursor = begin + html.length;
 
 				// If no text is selected, place the cursor inside the closing tag.
-				if ( begin == end )
-					cursor -= '</a>'.length;
+				if ( begin === end && ! selection ) {
+					cursor -= 4;
+				}
 
-				textarea.value = textarea.value.substring( 0, begin ) + html +
-					textarea.value.substring( end, textarea.value.length );
+				textarea.value = (
+					textarea.value.substring( 0, begin ) +
+					html +
+					textarea.value.substring( end, textarea.value.length )
+				);
 
 				// Update cursor position
 				textarea.selectionStart = textarea.selectionEnd = cursor;
@@ -283,8 +319,9 @@
 		},
 
 		mceUpdate: function() {
-			var link,
-				attrs = wpLink.getAttrs();
+			var attrs = wpLink.getAttrs(),
+				link,
+				text;
 
 			wpLink.close();
 			editor.focus();
@@ -293,33 +330,50 @@
 				editor.selection.moveToBookmark( editor.windowManager.bookmark );
 			}
 
-			link = editor.dom.getParent( editor.selection.getNode(), 'a[href]' );
-
-			// If the values are empty, unlink and return
-			if ( ! attrs.href || attrs.href == 'http://' ) {
+			if ( ! attrs.href ) {
 				editor.execCommand( 'unlink' );
 				return;
 			}
 
+			link = getLink();
+			text = $.trim( inputs.text.val() );
+
 			if ( link ) {
+				if ( text ) {
+					if ( 'innerText' in link ) {
+						link.innerText = text;
+					} else {
+						link.textContent = text;
+					}
+				}
+
 				editor.dom.setAttribs( link, attrs );
 			} else {
-				editor.execCommand( 'mceInsertLink', false, attrs );
+				if ( text ) {
+					editor.selection.setNode( editor.dom.create( 'a', attrs, text ) );
+				} else {
+					editor.execCommand( 'mceInsertLink', false, attrs );
+				}
 			}
-
-			// Move the cursor to the end of the selection
-			editor.selection.collapse();
 		},
 
 		updateFields: function( e, li ) {
 			inputs.url.val( li.children( '.item-permalink' ).val() );
-			inputs.title.val( li.hasClass( 'no-title' ) ? '' : li.children( '.item-title' ).text() );
 		},
 
 		setDefaultValues: function() {
-			var selection = editor && editor.selection.getContent(),
+			var selection,
 				emailRegexp = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i,
-				urlRegexp = /^(https?|ftp):\/\/[A-Z0-9.-]+\.[A-Z]{2,4}[^ "]*$/i;
+				urlRegexp = /^(https?|ftp):\/\/[A-Z0-9.-]+\.[A-Z]{2,4}[^ "]*$/i,
+				text;
+
+			if ( this.isMCE() ) {
+				selection = editor.selection.getContent();
+			} else if ( document.selection && wpLink.range ) {
+				selection = wpLink.range.text;
+			} else if ( typeof this.textarea.selectionStart !== 'undefined' ) {
+				selection = this.textarea.value.substring( this.textarea.selectionStart, this.textarea.selectionEnd );
+			}
 
 			if ( selection && emailRegexp.test( selection ) ) {
 				// Selection is email address
@@ -332,8 +386,8 @@
 				inputs.url.val( '' );
 			}
 
-			// Set description to default.
-			inputs.title.val( '' );
+			text = this.selectedText( selection );
+			inputs.text.val( text ).prop( 'disabled', ! text );
 
 			// Update save prompt.
 			inputs.submit.val( wpLinkL10n.save );
