Index: wp-includes/js/tinymce/plugins/wpview/editor_plugin.js
===================================================================
Index: wp-includes/js/tinymce/plugins/wpview/editor_plugin_src.js
===================================================================
--- wp-includes/js/tinymce/plugins/wpview/editor_plugin_src.js	(revision 0)
+++ wp-includes/js/tinymce/plugins/wpview/editor_plugin_src.js	(revision 0)
@@ -0,0 +1,79 @@
+/**
+ * WordPress View plugin.
+ */
+
+(function() {
+	tinymce.create('tinymce.plugins.wpView', {
+		init : function( editor, url ) {
+			var wpView = this;
+
+			// Check if the `wp.mce` API exists.
+			if ( typeof wp === 'undefined' || ! wp.mce )
+				return;
+
+			editor.onPreInit.add( function( editor ) {
+				// Add elements so we can set `contenteditable` to false.
+				editor.schema.addValidElements('div[*],span[*]');
+			});
+
+			// When the editor's content changes, scan the new content for
+			// matching view patterns, and transform the matches into
+			// view wrappers. Since the editor's DOM is outdated at this point,
+			// we'll wait to render the views.
+			editor.onBeforeSetContent.add( function( editor, o ) {
+				if ( ! o.content )
+					return;
+
+				o.content = wp.mce.view.toViews( o.content );
+			});
+
+			// When the editor's content has been updated and the DOM has been
+			// processed, render the views in the document.
+			editor.onSetContent.add( function( editor, o ) {
+				wp.mce.view.render( editor.getDoc() );
+			});
+
+			editor.onInit.add( function( editor ) {
+
+				// When the selection's content changes, scan any new content
+				// for matching views and immediately render them.
+				//
+				// Runs on paste and on inserting nodes/html.
+				editor.selection.onSetContent.add( function( selection, o ) {
+					if ( ! o.context )
+						return;
+
+					var node = selection.getNode();
+
+					if ( ! node.innerHTML )
+						return;
+
+					node.innerHTML = wp.mce.view.toViews( node.innerHTML );
+					wp.mce.view.render( node );
+				});
+			});
+
+			// When the editor's contents are being accessed as a string,
+			// transform any views back to their text representations.
+			editor.onPostProcess.add( function( editor, o ) {
+				if ( ( ! o.get && ! o.save ) || ! o.content )
+					return;
+
+				o.content = wp.mce.view.toText( o.content );
+			});
+		},
+
+		getInfo : function() {
+			return {
+				longname  : 'WordPress Views',
+				author    : 'WordPress',
+				authorurl : 'http://wordpress.org',
+				infourl   : 'http://wordpress.org',
+				version   : '1.0'
+			};
+		}
+	});
+
+	// Register plugin
+	tinymce.PluginManager.add( 'wpview', tinymce.plugins.wpView );
+})();
Index: wp-includes/js/tinymce/themes/advanced/skins/wp_theme/content.css
===================================================================
--- wp-includes/js/tinymce/themes/advanced/skins/wp_theme/content.css	(revision 21959)
+++ wp-includes/js/tinymce/themes/advanced/skins/wp_theme/content.css	(working copy)
@@ -141,3 +141,7 @@
 	height: 250px;
 }
 
+/* WordPress TinyMCE Previews */
+div.wp-preview-wrap {
+	display: inline;
+}
Index: wp-includes/js/mce-view.js
===================================================================
--- wp-includes/js/mce-view.js	(revision 0)
+++ wp-includes/js/mce-view.js	(revision 0)
@@ -0,0 +1,134 @@
+if ( typeof wp === 'undefined' )
+	var wp = {};
+
+(function($){
+	var views = {},
+		instances = {};
+
+	wp.mce = {};
+
+	wp.mce.view = {
+		// The default properties used for the objects in `wp.mce.view.add()`.
+		defaults: {
+			view: Backbone.View,
+			text: function( instance ) {
+				return instance.options.original;
+			}
+		},
+
+		// Registers a new TinyMCE view.
+		//
+		// Accepts a unique `id` and an `options` object.
+		//
+		// `options`
+		// If `view` is an object, it will automatically be passed to
+		// `wp.mce.View.extend( view, properties )` to create a new view class.
+		//
+		// If the `view` provided is already a constructor, the `properties`
+		// variable is ignored.
+		add: function( id, options ) {
+			var parent;
+
+			// Fetch the parent view or the default options.
+			parent = options.extend ? wp.mce.view.get( options.extend ) : wp.mce.view.defaults;
+
+			// Extend the `options` object with the parent's properties.
+			_.defaults( options, parent );
+
+			// If the `view` provided was an object, automatically create
+			// a new `Backbone.View` constructor, using the parent's `view`
+			// constructor as a base.
+			if ( ! _.isFunction( options.view ) )
+				options.view = parent.view.extend( options.view );
+
+			views[ id ] = options;
+		},
+
+		// Returns a TinyMCE view options object.
+		get: function( id ) {
+			return views[ id ];
+		},
+
+		// Unregisters a TinyMCE view.
+		remove: function( id ) {
+			delete views[ id ];
+		},
+
+		// Scans a `content` string for each view's pattern, replacing any
+		// matches with wrapper elements, and creates a new view instance for
+		// every match.
+		//
+		// To render the views, call `wp.mce.view.render( scope )`.
+		toViews: function( content ) {
+			_.each( views, function( view, viewType ) {
+				if ( ! view.pattern )
+					return;
+
+				// Scan for matches.
+				content = content.replace( view.pattern, function( match ) {
+					var instance, id, tag;
+
+					// Create a new view instance.
+					instance = new view.view({
+						original: match,
+						results:  _.toArray( arguments ),
+						viewType: viewType
+					});
+
+					// Use the view's `id` if it already exists. Otherwise,
+					// create a new `id`.
+					id = instance.el.id = instance.el.id || _.uniqueId('__wpmce-');
+					instances[ id ] = instance;
+
+					// If the view is a span, wrap it in a span.
+					tag = 'span' === instance.tagName ? 'span' : 'div';
+
+					return '<' + tag + ' class="wp-view-wrap" data-wp-view="' + id + '" contenteditable="false"></' + tag + '>';
+				});
+			});
+
+			return content;
+		},
+
+		// Renders any view instances inside a DOM node `scope`.
+		//
+		// View instances are detected by the presence of wrapper elements.
+		// To generate wrapper elements, pass your content through
+		// `wp.mce.view.toViews( content )`.
+		render: function( scope ) {
+			$( '.wp-view-wrap', scope ).each( function() {
+				var wrapper = $(this),
+					id = wrapper.data('wp-view'),
+					view = instances[ id ];
+
+				if ( ! view )
+					return;
+
+				// Render the view.
+				view.render();
+				// Detach the view element to ensure events are not unbound.
+				view.$el.detach();
+
+				// Empty the wrapper, attach the view element to the wrapper,
+				// and add an ending marker to the wrapper to help regexes
+				// scan the HTML string.
+				wrapper.empty().append( view.el ).append('<span data-wp-view-end></span>');
+			});
+		},
+
+		// Scans an HTML `content` string and replaces any view instances with
+		// their respective text representations.
+		toText: function( content ) {
+			return content.replace( /<(?:div|span)[^>]+data-wp-view="([^"]+)"[^>]*>.*?<span data-wp-view-end[^>]*><\/span><\/(?:div|span)>/g, function( match, id ) {
+				var instance = instances[ id ],
+					view;
+
+				if ( instance )
+					view = wp.mce.view.get( instance.options.viewType );
+
+				return instance && view ? view.text( instance ) : '';
+			});
+		}
+	};
+
+}(jQuery));
\ No newline at end of file
Index: wp-includes/script-loader.php
===================================================================
--- wp-includes/script-loader.php	(revision 21959)
+++ wp-includes/script-loader.php	(working copy)
@@ -322,6 +322,8 @@
 		'selectMediaMultiple' => __( 'Select one or more media files:' ),
 	) );
 
+	$scripts->add( 'mce-view', "/wp-includes/js/mce-view$suffix.js", array( 'backbone', 'jquery' ), false, 1 );
+
 	if ( is_admin() ) {
 		$scripts->add( 'ajaxcat', "/wp-admin/js/cat$suffix.js", array( 'wp-lists' ) );
 		$scripts->add_data( 'ajaxcat', 'group', 1 );
Index: wp-includes/class-wp-editor.php
===================================================================
--- wp-includes/class-wp-editor.php	(revision 21959)
+++ wp-includes/class-wp-editor.php	(working copy)
@@ -167,12 +167,12 @@
 				self::$baseurl = includes_url('js/tinymce');
 				self::$mce_locale = $mce_locale = ( '' == get_locale() ) ? 'en' : strtolower( substr(get_locale(), 0, 2) ); // only ISO 639-1
 				$no_captions = (bool) apply_filters( 'disable_captions', '' );
-				$plugins = array( 'inlinepopups', 'spellchecker', 'tabfocus', 'paste', 'media', 'fullscreen', 'wordpress', 'wpeditimage', 'wpgallery', 'wplink', 'wpdialogs' );
+				$plugins = array( 'inlinepopups', 'spellchecker', 'tabfocus', 'paste', 'media', 'fullscreen', 'wordpress', 'wpeditimage', 'wpgallery', 'wplink', 'wpdialogs', 'wpview' );
 				$first_run = true;
 				$ext_plugins = '';
 
 				if ( $set['teeny'] ) {
-					self::$plugins = $plugins = apply_filters( 'teeny_mce_plugins', array('inlinepopups', 'fullscreen', 'wordpress', 'wplink', 'wpdialogs'), $editor_id );
+					self::$plugins = $plugins = apply_filters( 'teeny_mce_plugins', array('inlinepopups', 'fullscreen', 'wordpress', 'wplink', 'wpdialogs', 'wpview'), $editor_id );
 				} else {
 					/*
 					The following filter takes an associative array of external plugins for TinyMCE in the form 'plugin_name' => 'url'.
Index: wp-admin/edit-form-advanced.php
===================================================================
--- wp-admin/edit-form-advanced.php	(revision 21959)
+++ wp-admin/edit-form-advanced.php	(working copy)
@@ -22,6 +22,8 @@
 	wp_enqueue_style( 'media-views' );
 	wp_plupload_default_settings();
 	add_action( 'admin_footer', 'wp_print_media_templates' );
+
+	wp_enqueue_script( 'mce-view' );
 }
 
 /**
