Index: src/wp-includes/js/mce-view.js
===================================================================
--- src/wp-includes/js/mce-view.js	(revision 28687)
+++ src/wp-includes/js/mce-view.js	(working copy)
@@ -8,7 +8,9 @@
 // Ensure the global `wp` object exists.
 window.wp = window.wp || {};
 
-(function($){
+( function( $ ) {
+	'use strict';
+
 	var views = {},
 		instances = {},
 		media = wp.media,
@@ -27,6 +29,7 @@
 	 */
 	wp.mce.View = function( options ) {
 		options = options || {};
+		this.type = options.type;
 		_.extend( this, _.pick( options, viewOptions ) );
 		this.initialize.apply( this, arguments );
 	};
@@ -35,22 +38,41 @@
 		initialize: function() {},
 		getHtml: function() {},
 		render: function() {
-			var html = this.getHtml();
+			var html =
+				'<div class="toolbar">' +
+					'<div class="dashicons dashicons-no-alt remove"></div>' +
+					( _.isFunction( views[ this.type ].edit ) ? '<div class="dashicons dashicons-edit edit"></div>' : '' ) +
+				'</div>' +
+				'<div class="wpview-content">' +
+					this.getHtml() +
+				'</div>' +
+				( this.overlay ? '<div class="wpview-overlay"></div>' : '' ) +
+				// The <ins> is used to mark the end of the wrapper div.
+				// Needed when comparing the content as string for preventing extra undo levels.
+				'<ins data-wpview-end="1"></ins>';
+
 			// Search all tinymce editor instances and update the placeholders
 			_.each( tinymce.editors, function( editor ) {
 				var self = this;
 				if ( editor.plugins.wpview ) {
-					$( editor.getDoc() ).find( '[data-wpview-text="' + this.encodedText + '"]' ).each( function ( i, element ) {
-						var node = $( element );
-						// The <ins> is used to mark the end of the wrapper div. Needed when comparing
-						// the content as string for preventing extra undo levels.
-						node.html( html ).append( '<ins data-wpview-end="1"></ins>' );
+					$( editor.getBody() ).find( '[data-wpview-text="' + this.encodedText + '"]' ).each( function ( i, element ) {
+						editor.dom.setHTML( element, html );
 						$( self ).trigger( 'ready', element );
 					});
 				}
 			}, this );
 		},
-		unbind: function() {}
+		unbind: function() {},
+		setContent: function( node, html ) {
+			var dom = tinymce.activeEditor.dom,
+				parent = dom.select( '.wpview-content', node )[0];
+
+			if ( _.isString( html ) ) {
+				dom.setHTML( parent, html );
+			} else {
+				parent.appendChild( html );
+			}
+		}
 	} );
 
 	// take advantage of the Backbone extend method
@@ -209,6 +231,7 @@
 
 			if ( ! wp.mce.views.getInstance( encodedText ) ) {
 				viewOptions = options;
+				viewOptions.type = viewType;
 				viewOptions.encodedText = encodedText;
 				instance = new view.View( viewOptions );
 				instances[ encodedText ] = instance;
@@ -244,6 +267,7 @@
 			if ( ! instance ) {
 				result = view.toView( text );
 				viewOptions = result.options;
+				viewOptions.type = view.type;
 				viewOptions.encodedText = encodedText;
 				instance = new view.View( viewOptions );
 				instances[ encodedText ] = instance;
@@ -361,6 +385,8 @@
 		loaded: false,
 
 		View: _.extend( {}, wp.media.mixin, {
+			overlay: true,
+
 			initialize: function( options ) {
 				this.players = [];
 				this.shortcode = options.shortcode;
@@ -511,6 +537,7 @@
 		state: ['playlist-edit', 'video-playlist-edit'],
 		View: _.extend( {}, wp.media.mixin, {
 			template:  media.template( 'editor-playlist' ),
+			overlay: true,
 
 			initialize: function( options ) {
 				this.players = [];
@@ -637,61 +664,139 @@
 	/**
 	 * TinyMCE handler for the embed shortcode
 	 */
-	wp.mce.views.register( 'embed', {
-		shortcode: 'embed',
-		View: _.extend( {}, wp.media.mixin, {
-			template: media.template( 'editor-embed' ),
-			initialize: function( options ) {
-				this.players = [];
-				this.content = options.content;
-				this.parsed = false;
-				this.shortcode = options.shortcode;
-				_.bindAll( this, 'setHtml', 'setNode', 'fetch' );
-				$( this ).on( 'ready', this.setNode );
-			},
-			unbind: function() {
-				var self = this;
-				_.each( this.players, function ( player ) {
-					player.pause();
-					self.removePlayer( player );
-				} );
-				this.players = [];
-			},
-			setNode: function ( e, node ) {
-				this.node = node;
-				if ( this.parsed ) {
-					this.parseMediaShortcodes();
-				} else {
-					this.fetch();
+	wp.mce.embedView = _.extend( {}, wp.media.mixin, {
+		overlay: true,
+		initialize: function( options ) {
+			this.players = [];
+			this.content = options.content;
+			this.parsed = false;
+			this.original = options.url || options.shortcode.string();
+			if ( options.url ) {
+				this.shortcode = '[embed]' + options.url + '[/embed]';
+			} else {
+				this.shortcode = options.shortcode.string();
+			}
+			_.bindAll( this, 'setHtml', 'setNode', 'fetch' );
+			$( this ).on( 'ready', this.setNode );
+		},
+		unbind: function() {
+			var self = this;
+			_.each( this.players, function ( player ) {
+				player.pause();
+				self.removePlayer( player );
+			} );
+			this.players = [];
+		},
+		setNode: function ( e, node ) {
+			this.node = node;
+			if ( this.parsed ) {
+				this.setHtml( this.parsed );
+				this.parseMediaShortcodes();
+			} else {
+				this.fetch();
+			}
+		},
+		fetch: function () {
+			var self = this;
+			wp.ajax.send( 'parse-embed', {
+				data: {
+					post_ID: $( '#post_ID' ).val(),
+					content: this.shortcode
 				}
-			},
-			fetch: function () {
-				wp.ajax.send( 'parse-embed', {
-					data: {
-						post_ID: $( '#post_ID' ).val(),
-						content: this.shortcode.string()
+			} ).done( function( content ) {
+				self.parsed = content;
+				self.setHtml( content );
+			} );
+		},
+		/* jshint scripturl: true */
+		setHtml: function ( content ) {
+			var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver,
+				$content, scripts, observer, iframe, iframeWin, iframeDoc,
+				test = '<a href',
+				dom = tinymce.activeEditor.dom;
+
+			if ( content.substring( 0, test.length ) === test ) {
+				dom.replace( dom.create( 'P', null, this.original ), this.node );
+			} else {
+				$content = $( $.trim( content ) );
+				scripts = $content.find( 'script' ).add( $content.filter( 'script' ) );
+
+				if ( scripts.length ) {
+
+					iframe = dom.create( 'IFRAME', {
+						src: 'javascript:""',
+						frameBorder: '0',
+						allowTransparency: 'true',
+						style: {
+							width: '100%',
+							display: 'block'
+						}
+					} );
+
+					this.setContent( this.node, iframe );
+
+					iframeWin = iframe.contentWindow;
+					iframeDoc = iframeWin.document;
+
+					iframeWin.resize = function() {
+						$( iframe ).height( $( iframeDoc ).height() );
+					};
+
+					iframeDoc.open();
+					iframeDoc.write( '<!DOCTYPE html><html><head><meta charset="utf-8"></head><body onload="setTimeout( resize, 1000 );">' + content + '</body></html>' );
+					iframeDoc.close();
+
+					if ( MutationObserver ) {
+						observer = new MutationObserver( _.debounce( function() {
+							iframeWin.resize();
+						}, 500 ) ).observe( iframeDoc.body, {
+							attributes: true,
+							childList: true,
+							subtree: true
+						} );
 					}
-				} ).done( this.setHtml );
-			},
-			setHtml: function ( content ) {
-				this.parsed = content;
-				$( this.node ).html( this.getHtml() );
-				this.parseMediaShortcodes();
-			},
-			parseMediaShortcodes: function () {
-				var self = this;
-				$( '.wp-audio-shortcode, .wp-video-shortcode', this.node ).each( function ( i, element ) {
-					self.players.push( new MediaElementPlayer( element, self.mejsSettings ) );
-				} );
-			},
-			getHtml: function() {
-				if ( ! this.parsed ) {
-					return '';
+				} else {
+					this.setContent( this.node, content );
 				}
-				return this.template({ content: this.parsed });
 			}
-		} ),
-		edit: function() {}
+
+			this.parseMediaShortcodes();
+		},
+		parseMediaShortcodes: function () {
+			var self = this;
+			$( '.wp-audio-shortcode, .wp-video-shortcode', this.node ).each( function ( i, element ) {
+				self.players.push( new MediaElementPlayer( element, self.mejsSettings ) );
+			} );
+		},
+		getHtml: function() {
+			return '';
+		}
+	} );
+
+	wp.mce.views.register( 'embed', {
+		shortcode: 'embed',
+		View: wp.mce.embedView
+	} );
+
+	wp.mce.views.register( 'embedURL', {
+		shortcode: 'embed',
+		toView: function( content ) {
+			var re = /^<p>\s*(https?:\/\/[^\s"]+)\s*<\/p>$/gim,
+				match = re.exec( content );
+
+			if ( ! match ) {
+				return;
+			}
+
+			return {
+				index: match.index,
+				content: match[0],
+				options: {
+					url: match[1]
+				}
+			};
+		},
+		View: wp.mce.embedView
 	} );
 
 }(jQuery));
Index: src/wp-includes/js/tinymce/plugins/wpview/plugin.js
===================================================================
--- src/wp-includes/js/tinymce/plugins/wpview/plugin.js	(revision 28687)
+++ src/wp-includes/js/tinymce/plugins/wpview/plugin.js	(working copy)
@@ -158,6 +158,8 @@
 	// matching view patterns, and transform the matches into
 	// view wrappers.
 	editor.on( 'BeforeSetContent', function( event ) {
+		var node;
+
 		if ( ! event.content ) {
 			return;
 		}
@@ -166,14 +168,15 @@
 			wp.mce.views.unbind( editor );
 		}
 
-		event.content = wp.mce.views.toViews( event.content );
-	});
+		node = editor.selection.getNode();
 
-	editor.on( 'PastePreProcess', function( event ) {
-		if ( event.content.match( /^\s*(https?:\/\/[^\s"]+)\s*$/im ) ) {
-			event.content = '[embed]' + event.content + '[/embed]';
+		// If a url is inserted in an empty paragraph, wrap the url in p tags so it's detected by wp.mce.views.
+		if ( node.nodeName === 'P' && editor.dom.isEmpty( node ) && event.content.match( /^\s*(https?:\/\/[^\s"]+)\s*$/im ) ) {
+			event.content = '<p>' + event.content + '</p>';
 		}
-	} );
+
+		event.content = wp.mce.views.toViews( event.content );
+	});
 
 	// When the editor's content has been updated and the DOM has been
 	// processed, render the views in the document.
Index: src/wp-includes/media-template.php
===================================================================
--- src/wp-includes/media-template.php	(revision 28687)
+++ src/wp-includes/media-template.php	(working copy)
@@ -994,9 +994,6 @@
 	</script>
 
 	<script type="text/html" id="tmpl-editor-gallery">
-		<div class="toolbar">
-			<div class="dashicons dashicons-edit edit"></div><div class="dashicons dashicons-no-alt remove"></div>
-		</div>
 		<# if ( data.attachments ) { #>
 			<div class="gallery gallery-columns-{{ data.columns }}">
 				<# _.each( data.attachments, function( attachment, index ) { #>
@@ -1027,30 +1024,16 @@
 	</script>
 
 	<script type="text/html" id="tmpl-editor-audio">
-		<div class="toolbar">
-			<div class="dashicons dashicons-edit edit"></div>
-			<div class="dashicons dashicons-no-alt remove"></div>
-		</div>
 		<?php wp_underscore_audio_template() ?>
-		<div class="wpview-overlay"></div>
 	</script>
 
 	<script type="text/html" id="tmpl-editor-video">
-		<div class="toolbar">
-			<div class="dashicons dashicons-edit edit"></div>
-			<div class="dashicons dashicons-no-alt remove"></div>
-		</div>
 		<?php wp_underscore_video_template() ?>
-		<div class="wpview-overlay"></div>
 	</script>
 
 	<?php wp_underscore_playlist_templates() ?>
 
 	<script type="text/html" id="tmpl-editor-playlist">
-		<div class="toolbar">
-			<div class="dashicons dashicons-edit edit"></div>
-			<div class="dashicons dashicons-no-alt remove"></div>
-		</div>
 		<# if ( data.tracks ) { #>
 			<div class="wp-playlist wp-{{ data.type }}-playlist wp-playlist-{{ data.style }}">
 				<# if ( 'audio' === data.type ){ #>
@@ -1062,7 +1045,6 @@
 				<div class="wp-playlist-next"></div>
 				<div class="wp-playlist-prev"></div>
 			</div>
-			<div class="wpview-overlay"></div>
 		<# } else { #>
 			<div class="wpview-error">
 				<div class="dashicons dashicons-video-alt3"></div><p><?php _e( 'No items found.' ); ?></p>
@@ -1075,14 +1057,6 @@
 		<div class="upload-errors"></div>
 	</script>
 
-	<script type="text/html" id="tmpl-editor-embed">
-		<div class="toolbar">
-			<div class="dashicons dashicons-no-alt remove"></div>
-		</div>
-		{{{ data.content }}}
-		<div class="wpview-overlay"></div>
-	</script>
-
 	<?php
 
 	/**
