Index: wp-includes/js/tinymce/plugins/wplink/editor_plugin.js
===================================================================
--- wp-includes/js/tinymce/plugins/wplink/editor_plugin.js	(revision 0)
+++ wp-includes/js/tinymce/plugins/wplink/editor_plugin.js	(revision 0)
@@ -0,0 +1,56 @@
+(function() {
+	tinymce.create('tinymce.plugins.wpLink', {
+		/**
+		 * Initializes the plugin, this will be executed after the plugin has been created.
+		 * This call is done before the editor instance has finished it's initialization so use the onInit event
+		 * of the editor instance to intercept that event.
+		 *
+		 * @param {tinymce.Editor} ed Editor instance that the plugin is initialized in.
+		 * @param {string} url Absolute URL to where the plugin is located.
+		 */
+		init : function(ed, url) {
+			// Register the command so that it can be invoked by using tinyMCE.activeEditor.execCommand('mceExample');
+			ed.addCommand('WP_Link', function() {
+				ed.windowManager.open({
+					file : tinymce.baseURL + '/wp-mce-link.php',
+					width : 320,
+					height : 260,
+					inline : 1
+				}, {
+					plugin_url : url // Plugin absolute URL
+				});
+			});
+
+			// Register example button
+			ed.addButton('wplink', {
+				title : ed.getLang('wplink.link_desc'),
+				cmd : 'WP_Link'
+			});
+			
+			ed.addShortcut('alt+shift+a', ed.getLang('wplink.link_desc'), 'WP_Link');
+
+			// Add a node change handler, selects the button in the UI when a link is selected
+			ed.onNodeChange.add(function(ed, cm, n) {
+				cm.setActive('wplink', n.nodeName == 'A');
+			});
+		},
+		/**
+		 * Returns information about the plugin as a name/value array.
+		 * The current keys are longname, author, authorurl, infourl and version.
+		 *
+		 * @return {Object} Name/value array containing information about the plugin.
+		 */
+		getInfo : function() {
+			return {
+				longname : 'WordPress Link Dialog',
+				author : 'WordPress',
+				authorurl : 'http://wordpress.org',
+				infourl : '',
+				version : "1.0"
+			};
+		}
+	});
+
+	// Register plugin
+	tinymce.PluginManager.add('wplink', tinymce.plugins.wpLink);
+})();
\ No newline at end of file
Index: wp-includes/js/tinymce/plugins/wplink/editor_plugin.dev.js
===================================================================
Index: wp-includes/js/tinymce/plugins/wplink/js/wplink.js
===================================================================
--- wp-includes/js/tinymce/plugins/wplink/js/wplink.js	(revision 0)
+++ wp-includes/js/tinymce/plugins/wplink/js/wplink.js	(revision 0)
@@ -0,0 +1,189 @@
+(function($){	
+	var inputs = {}, panels, active, ed,
+	wpLink = {
+		init : function() {
+			var e, etarget, eclass;
+			// Init shared vars
+			ed = tinyMCEPopup.editor;
+			// Secondary options
+			inputs.title = $('#link-title-field');
+			// Advanced Options
+			inputs.advancedOptions = $('#link-advanced-options');
+			inputs.target = $('#link-target-select');
+			inputs['class'] = $('#link-class-select');
+			// Types
+			inputs.typeDropdown = $('#link-type');
+			inputs.typeOptions = inputs.typeDropdown.find('option');
+			
+			panels = $('.link-panel');
+			active = $('.link-panel-active');
+			
+			// Build lists
+			wpLink.fillClassList('link-class-select');
+			wpLink.fillTargetList('link-target-select');
+			
+			// Extract type names
+			inputs.typeOptions.each( function(){
+				$(this).data( 'link-type', this.id.replace('link-option-id-','') );
+			});
+			panels.each( function(){
+				$(this).data( 'link-type', this.id.replace('link-panel-id-','') );
+			});
+			
+			// Bind event handlers
+			inputs.typeDropdown.change( wpLink.selectPanel );
+			$('#wp-update').click( wpLink.update );
+			$('#wp-cancel').click( function() { tinyMCEPopup.close(); } );
+			$('#link-advanced-options-toggle').click( wpLink.toggleAdvancedOptions );
+			
+			// If link exists, select proper values.
+			e = ed.dom.getParent(ed.selection.getNode(), 'A');
+			if ( ! e )
+				return;
+			
+			// @TODO: select proper panel/fill values when a link is edited
+			active.find('input.url-field').val( e.href );
+			inputs.title.val( ed.dom.getAttrib(e, 'title') );
+			// Advanced Options
+			inputs.target.val( etarget = ed.dom.getAttrib(e, 'target') );
+			inputs['class'].val( eclass = ed.dom.getAttrib(e, 'class') );
+			if ( etarget || eclass ) // Open the adv. options if one is set.
+				inputs.advancedOptions.toggleClass('adv-options-active');
+		},
+		
+		update : function() {
+			var ed = tinyMCEPopup.editor,
+				attrs = {
+					href : active.find('input.url-field').val(),
+					title : inputs.title.val(),
+					target : inputs.target.val(),
+					'class' : inputs['class'].val()
+				}, defaultContent, e, b;
+			
+			if ( active.hasClass('link-panel-custom') )
+				defaultContent = attrs.href;
+			else // @TODO: Update to use the title
+				defaultContent = attrs.href;
+			
+			tinyMCEPopup.restoreSelection();
+			e = ed.dom.getParent(ed.selection.getNode(), 'A');
+			
+			// If the values are empty...
+			if ( ! attrs.href ) {
+				// ...and nothing is selected, we should return
+				if ( ed.selection.isCollapsed() ) {
+					tinyMCEPopup.close();
+					return;
+				// ...and a link exists, we should unlink and return
+				} else if ( e ) {
+					tinyMCEPopup.execCommand("mceBeginUndoLevel");
+					b = ed.selection.getBookmark();
+					ed.dom.remove(e, 1);
+					ed.selection.moveToBookmark(b);
+					tinyMCEPopup.execCommand("mceEndUndoLevel");
+					tinyMCEPopup.close();
+					return;
+				}
+			}
+			
+			tinyMCEPopup.execCommand("mceBeginUndoLevel");
+
+			if (e == null) {
+				ed.getDoc().execCommand("unlink", false, null);
+				
+				// If no selection exists, create a new link from scratch.
+				if ( ed.selection.isCollapsed() ) {
+					var el = ed.dom.create('a', { href: "#mce_temp_url#" }, defaultContent);
+					ed.selection.setNode(el);
+				// If a selection exists, wrap it in a link.
+				} else {
+					tinyMCEPopup.execCommand("CreateLink", false, "#mce_temp_url#", {skip_undo : 1});
+				}
+
+				tinymce.each(ed.dom.select("a"), function(n) {
+					if (ed.dom.getAttrib(n, 'href') == '#mce_temp_url#') {
+						e = n;
+						ed.dom.setAttribs(e, attrs);
+					}
+				});
+			} else {
+				ed.dom.setAttribs(e, attrs);
+			}
+
+			// Don't move caret if selection was image
+			if (e.childNodes.length != 1 || e.firstChild.nodeName != 'IMG') {
+				ed.focus();
+				ed.selection.select(e);
+				ed.selection.collapse(0);
+				tinyMCEPopup.storeSelection();
+			}
+
+			tinyMCEPopup.execCommand("mceEndUndoLevel");
+			tinyMCEPopup.close();
+		},
+		
+		selectPanel : function( option ) {
+			var sel = inputs.typeOptions.filter(':selected');
+			
+			if ( option.jquery ) {
+				sel.removeAttr('selected');
+				sel = option.attr('selected', 'selected');
+			}
+			
+			active.removeClass('link-panel-active');
+			active = $('#link-panel-id-' + sel.data('link-type') ).addClass('link-panel-active');
+		},
+		
+		toggleAdvancedOptions : function() {
+			inputs.advancedOptions.toggleClass('adv-options-active');
+			return false;
+		},
+		
+		/**
+		 * Taken from themes/advanced/js/link.js
+		 */
+		fillClassList : function(id) {
+			var dom = tinyMCEPopup.dom, lst = dom.get(id), v, cl;
+
+			if (v = tinyMCEPopup.getParam('theme_advanced_styles')) {
+				cl = [];
+
+				tinymce.each(v.split(';'), function(v) {
+					var p = v.split('=');
+
+					cl.push({'title' : p[0], 'class' : p[1]});
+				});
+			} else
+				cl = tinyMCEPopup.editor.dom.getClasses();
+
+			if (cl.length > 0) {
+				lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('not_set'), '');
+
+				tinymce.each(cl, function(o) {
+					lst.options[lst.options.length] = new Option(o.title || o['class'], o['class']);
+				});
+			} else
+				dom.remove(dom.getParent(id, 'tr'));
+		},
+
+		/**
+		 * Taken from themes/advanced/js/link.js
+		 */
+		fillTargetList : function(id) {
+			var dom = tinyMCEPopup.dom, lst = dom.get(id), v;
+
+			lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('not_set'), '');
+			lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('advanced_dlg.link_target_same'), '_self');
+			lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('advanced_dlg.link_target_blank'), '_blank');
+
+			if (v = tinyMCEPopup.getParam('theme_advanced_link_targets')) {
+				tinymce.each(v.split(','), function(v) {
+					v = v.split('=');
+					lst.options[lst.options.length] = new Option(v[0], v[1]);
+				});
+			}
+		}
+	}
+	
+	$(document).ready( wpLink.init );
+})(jQuery);
\ No newline at end of file
Index: wp-includes/js/tinymce/langs/wp-langs-en.js
===================================================================
--- wp-includes/js/tinymce/langs/wp-langs-en.js	(revision 15721)
+++ wp-includes/js/tinymce/langs/wp-langs-en.js	(working copy)
@@ -429,3 +429,8 @@
 caption:"Edit Image Caption",
 alt:"Edit Alternate Text"
 });
+
+tinyMCE.addI18n("en.wplink",{
+link_desc:"Insert/edit link",
+unlink_desc:"Unlink (Alt+Shift+S)"
+});
Index: wp-includes/js/tinymce/langs/wp-langs.php
===================================================================
--- wp-includes/js/tinymce/langs/wp-langs.php	(revision 15721)
+++ wp-includes/js/tinymce/langs/wp-langs.php	(working copy)
@@ -452,4 +452,9 @@
 caption:"' . mce_escape( __('Edit Image Caption') ) . '",
 alt:"' . mce_escape( __('Edit Alternate Text') ) . '"
 });
+
+tinyMCE.addI18n("' . $language . '.wplink",{
+link_desc:"' . mce_escape( __('Insert/edit link') ) . '",
+unlink_desc:"' . mce_escape( __('Unlink') ) . ' (Alt+Shift+S)"
+});
 ';
Index: wp-includes/js/tinymce/themes/advanced/skins/wp_theme/ui.css
===================================================================
--- wp-includes/js/tinymce/themes/advanced/skins/wp_theme/ui.css	(revision 15721)
+++ wp-includes/js/tinymce/themes/advanced/skins/wp_theme/ui.css	(working copy)
@@ -274,7 +274,8 @@
 .wp_themeSkin span.mce_anchor {background-position:-200px 0}
 .wp_themeSkin span.mce_indent {background-position:-400px 0}
 .wp_themeSkin span.mce_outdent {background-position:-540px 0}
-.wp_themeSkin span.mce_link {background-position:-500px 0}
+.wp_themeSkin span.mce_link,
+.wp_themeSkin span.mce_wplink {background-position:-500px 0}
 .wp_themeSkin span.mce_unlink {background-position:-640px 0}
 .wp_themeSkin span.mce_sub {background-position:-600px 0}
 .wp_themeSkin span.mce_sup {background-position:-620px 0}
Index: wp-includes/js/tinymce/wp-mce-link.php
===================================================================
--- wp-includes/js/tinymce/wp-mce-link.php	(revision 0)
+++ wp-includes/js/tinymce/wp-mce-link.php	(revision 0)
@@ -0,0 +1,186 @@
+<?php
+/** @ignore */
+require_once('../../../wp-load.php');
+
+// Set up some vars
+$pts = get_post_types( array( 'show_ui' => true ), 'objects' );
+$taxes = get_taxonomies( array( 'show_ui' => true ), 'objects' );
+
+// Helper functions
+function wp_link_panel_custom() { ?>
+	<div id="link-panel-id-custom" class="link-panel link-panel-custom link-panel-active">
+		<label>
+			<span><?php _e('URL:'); ?></span><input class="url-field" type="text" />
+		</label>
+	</div>
+<?php }
+function wp_link_panel_post_type( $pt_obj ) { ?>
+	<div id="link-panel-id-<?php echo $pt_obj->name; ?>" class="link-panel link-panel-pt">
+		<label>
+			<span><?php _e('URL:'); ?></span><input class="url-field" type="text" />
+		</label>
+	</div>
+<?php }
+function wp_link_panel_taxonomy( $tax_obj ) { ?>
+	<div id="link-panel-id-<?php echo $tax_obj->name; ?>" class="link-panel link-panel-tax">
+		<label>
+			<span><?php _e('URL:'); ?></span><input class="url-field" type="text" />
+		</label>
+	</div>
+<?php }
+
+
+header('Content-Type: text/html; charset=' . get_bloginfo('charset'));
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
+<head>
+<meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php echo get_option('blog_charset'); ?>" />
+<title><?php _e('Insert/edit link') ?></title>
+<script type="text/javascript" src="tiny_mce_popup.js?ver=3223"></script>
+<?php
+wp_print_scripts( array('jquery') );
+?>
+<script type="text/javascript" src="plugins/wplink/js/wplink.js?ver=1.0"></script>
+<?php
+wp_admin_css( 'global', true );
+wp_admin_css( 'wp-admin', true );
+wp_admin_css( 'colors-fresh', true );
+?>
+<style>
+html, body {
+	background: #f1f1f1;
+}
+
+a:link, a:visited {
+	color: #21759B;
+}
+
+select {
+	height: 2em;
+}
+
+#link-header,
+#link-options,
+#link-advanced-options {
+	padding: 5px;
+	border-bottom: 1px solid #dfdfdf;
+}
+#link-type {
+	width: 140px;
+}
+
+.link-panel {
+	padding: 5px 5px 0;
+	display: none;
+}
+	.link-panel-active {
+		display: block;
+	}
+
+label input[type="text"] {
+	width: 220px;
+}
+
+label span {
+	display: inline-block;
+	width: 80px;
+	text-align: right;
+	padding-right: 5px;
+}
+
+#link-advanced-options,
+#link-advanced-options select,
+#link-advanced-options option {
+	font-size: 11px;
+}
+
+#link-advanced-options {
+	background: #f9f9f9;
+	padding: 3px 5px;
+}
+	#link-advanced-options label select {
+		width: 195px;
+	}
+
+#link-advanced-options-toggle {
+	display: block;
+}
+
+#link-advanced-options label {
+	padding-top: 2px;
+	display: none;
+}
+	#link-advanced-options.adv-options-active label {
+		display: block;
+	}
+
+.submitbox {
+	padding: 5px;
+	font-size: 11px;
+	overflow: auto;
+	height: 29px;
+}
+#wp-cancel {
+	line-height: 25px;
+	float: left;
+}
+#wp-update {
+	line-height: 23px;
+	float: right;
+}
+#wp-update a {
+	display: inline-block;
+}
+</style>
+</head>
+<body>
+<div id="link-header">
+	<label for="link-type">
+		<span><strong><?php _e('Link Type:'); ?></strong>
+		</span><select id="link-type">
+			<option id="link-option-id-custom" class="link-custom"><?php _e('External Link'); ?></option>
+		<?php
+		foreach ( $pts as $pt_obj )
+			echo '<option id="link-option-id-' . $pt_obj->name . '" class="link-option-pt">' . $pt_obj->labels->singular_name . '</option>';
+		foreach ( $taxes as $tax_obj )
+			echo '<option id="link-option-id-' . $tax_obj->name . '" class="link-option-tax">' . $tax_obj->labels->singular_name . '</option>';
+		?>
+		</select>
+	</label>
+</div>
+<div id="link-selector">
+	<?php
+	wp_link_panel_custom();
+	foreach ( $pts as $pt_obj ) {
+		wp_link_panel_post_type( $pt_obj );
+	}
+	foreach ( $taxes as $tax_obj ) {
+		wp_link_panel_taxonomy( $tax_obj );
+	}
+	?>
+	<div id="link-options">
+		<label for="link-title-field">
+			<span><?php _e('Description:'); ?></span><input id="link-title-field" type="text" />
+		</label>
+	</div>
+	<div id="link-advanced-options">
+		<a id="link-advanced-options-toggle" href="#"><?php _e('Advanced Options'); ?></a>
+		<label for="link-target-select">
+			<span><?php _e('Target:'); ?></span><select id="link-target-select"></select>
+		</label>
+		<label for="link-class-select">
+			<span><?php _e('Class:'); ?></span><select id="link-class-select"></select>
+		</label>
+	</div>
+</div>
+<div class="submitbox">
+	<div id="wp-cancel">
+		<a class="submitdelete deletion"><?php _e('Cancel'); ?></a>
+	</div>
+	<div id="wp-update">
+		<a class="button-primary"><?php _e('Update'); ?></a>
+	</div>
+</div>
+</body>
+</html>
Index: wp-admin/includes/post.php
===================================================================
--- wp-admin/includes/post.php	(revision 15721)
+++ wp-admin/includes/post.php	(working copy)
@@ -1311,10 +1311,10 @@
 	$mce_spellchecker_languages = apply_filters('mce_spellchecker_languages', '+English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,Portuguese=pt,Spanish=es,Swedish=sv');
 
 	if ( $teeny ) {
-		$plugins = apply_filters( 'teeny_mce_plugins', array('inlinepopups', 'media', 'fullscreen', 'wordpress') );
+		$plugins = apply_filters( 'teeny_mce_plugins', array('inlinepopups', 'media', 'fullscreen', 'wordpress', 'wplink') );
 		$ext_plugins = '';
 	} else {
-		$plugins = array( 'inlinepopups', 'spellchecker', 'paste', 'wordpress', 'media', 'fullscreen', 'wpeditimage', 'wpgallery', 'tabfocus' );
+		$plugins = array( 'inlinepopups', 'spellchecker', 'paste', 'wordpress', 'media', 'fullscreen', 'wpeditimage', 'wpgallery', 'tabfocus', 'wplink' );
 
 		/*
 		The following filter takes an associative array of external plugins for TinyMCE in the form 'plugin_name' => 'url'.
@@ -1398,11 +1398,11 @@
 	$plugins = implode($plugins, ',');
 
 	if ( $teeny ) {
-		$mce_buttons = apply_filters( 'teeny_mce_buttons', array('bold, italic, underline, blockquote, separator, strikethrough, bullist, numlist,justifyleft, justifycenter, justifyright, undo, redo, link, unlink, fullscreen') );
+		$mce_buttons = apply_filters( 'teeny_mce_buttons', array('bold, italic, underline, blockquote, separator, strikethrough, bullist, numlist,justifyleft, justifycenter, justifyright, undo, redo, wplink, unlink, fullscreen') );
 		$mce_buttons = implode($mce_buttons, ',');
 		$mce_buttons_2 = $mce_buttons_3 = $mce_buttons_4 = '';
 	} else {
-		$mce_buttons = apply_filters('mce_buttons', array('bold', 'italic', 'strikethrough', '|', 'bullist', 'numlist', 'blockquote', '|', 'justifyleft', 'justifycenter', 'justifyright', '|', 'link', 'unlink', 'wp_more', '|', 'spellchecker', 'fullscreen', 'wp_adv' ));
+		$mce_buttons = apply_filters('mce_buttons', array('bold', 'italic', 'strikethrough', '|', 'bullist', 'numlist', 'blockquote', '|', 'justifyleft', 'justifycenter', 'justifyright', '|', 'wplink', 'unlink', 'wp_more', '|', 'spellchecker', 'fullscreen', 'wp_adv' ));
 		$mce_buttons = implode($mce_buttons, ',');
 
 		$mce_buttons_2 = array('formatselect', 'underline', 'justifyfull', 'forecolor', '|', 'pastetext', 'pasteword', 'removeformat', '|' );
