<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[27408] trunk/src/wp-includes: Update mce-view.js and the `wpview` TinyMCE plugin, and use them to show gallery previews in the Visual editor, props gcorne, see #26959</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://core.trac.wordpress.org/changeset/27408">27408</a></dd>
<dt>Author</dt> <dd>azaozz</dd>
<dt>Date</dt> <dd>2014-03-05 07:00:18 +0000 (Wed, 05 Mar 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Update mce-view.js and the `wpview` TinyMCE plugin, and use them to show gallery previews in the Visual editor, props gcorne, see <a href="http://core.trac.wordpress.org/ticket/26959">#26959</a></pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesclasswpeditorphp">trunk/src/wp-includes/class-wp-editor.php</a></li>
<li><a href="#trunksrcwpincludesjsmceviewjs">trunk/src/wp-includes/js/mce-view.js</a></li>
<li><a href="#trunksrcwpincludesjstinymcepluginswpgallerypluginjs">trunk/src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js</a></li>
<li><a href="#trunksrcwpincludesjstinymcepluginswpviewpluginjs">trunk/src/wp-includes/js/tinymce/plugins/wpview/plugin.js</a></li>
<li><a href="#trunksrcwpincludesjstinymceskinswordpresswpcontentcss">trunk/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css</a></li>
<li><a href="#trunksrcwpincludesmediatemplatephp">trunk/src/wp-includes/media-template.php</a></li>
<li><a href="#trunksrcwpincludesversionphp">trunk/src/wp-includes/version.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpincludesclasswpeditorphp"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-includes/class-wp-editor.php (27407 => 27408)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/class-wp-editor.php        2014-03-05 06:38:23 UTC (rev 27407)
+++ trunk/src/wp-includes/class-wp-editor.php   2014-03-05 07:00:18 UTC (rev 27408)
</span><span class="lines">@@ -242,6 +242,7 @@
</span><span class="cx">                                          'wpgallery',
</span><span class="cx">                                          'wplink',
</span><span class="cx">                                          'wpdialogs',
</span><ins>+                                               'wpview',
</ins><span class="cx">                                   ) ) );
</span><span class="cx"> 
</span><span class="cx">                                  if ( ( $key = array_search( 'spellchecker', $plugins ) ) !== false ) {
</span><span class="lines">@@ -501,6 +502,9 @@
</span><span class="cx">          if ( self::$has_medialib ) {
</span><span class="cx">                  add_thickbox();
</span><span class="cx">                  wp_enqueue_script('media-upload');
</span><ins>+
+                       if ( self::$has_tinymce )
+                               wp_enqueue_script('mce-view');
</ins><span class="cx">           }
</span><span class="cx">  }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunksrcwpincludesjsmceviewjs"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-includes/js/mce-view.js (27407 => 27408)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/js/mce-view.js     2014-03-05 06:38:23 UTC (rev 27407)
+++ trunk/src/wp-includes/js/mce-view.js        2014-03-05 07:00:18 UTC (rev 27408)
</span><span class="lines">@@ -1,3 +1,5 @@
</span><ins>+/* global tinymce */
+
</ins><span class="cx"> // Ensure the global `wp` object exists.
</span><span class="cx"> window.wp = window.wp || {};
</span><span class="cx"> 
</span><span class="lines">@@ -3,169 +5,89 @@
</span><span class="cx"> (function($){
</span><span class="cx">  var views = {},
</span><del>-               instances = {};
</del><ins>+                instances = {},
+               media = wp.media,
+               viewOptions = ['encodedText'];
</ins><span class="cx"> 
</span><span class="cx">  // Create the `wp.mce` object if necessary.
</span><span class="cx">  wp.mce = wp.mce || {};
</span><span class="cx"> 
</span><del>-       // wp.mce.view
-       // -----------
-       // A set of utilities that simplifies adding custom UI within a TinyMCE editor.
-       // At its core, it serves as a series of converters, transforming text to a
-       // custom UI, and back again.
-       wp.mce.view = {
-               // ### defaults
-               defaults: {
-                       // The default properties used for objects with the `pattern` key in
-                       // `wp.mce.view.add()`.
-                       pattern: {
-                               view: Backbone.View,
-                               text: function( instance ) {
-                                       return instance.options.original;
-                               },
</del><ins>+        /**
+        * wp.mce.View
+        *
+        * A Backbone-like View constructor intended for use when rendering a TinyMCE View. The main difference is
+        * that the TinyMCE View is not tied to a particular DOM node.
+        */
+       wp.mce.View = function( options ) {
+               options || (options = {});
+               _.extend(this, _.pick(options, viewOptions));
+               this.initialize.apply(this, arguments);
+       };
</ins><span class="cx"> 
</span><del>-                               toView: function( content ) {
-                                       if ( ! this.pattern )
-                                               return;
-
-                                       this.pattern.lastIndex = 0;
-                                       var match = this.pattern.exec( content );
-
-                                       if ( ! match )
-                                               return;
-
-                                       return {
-                                               index:   match.index,
-                                               content: match[0],
-                                               options: {
-                                                       original: match[0],
-                                                       results:  match
-                                               }
-                                       };
</del><ins>+        _.extend( wp.mce.View.prototype, {
+               initialize: function() {},
+               html: function() {},
+               render: function() {
+                       var html = this.getHtml();
+                       // Search all tinymce editor instances and update the placeholders
+                       _.each( tinymce.editors, function( editor ) {
+                               var doc;
+                               if ( editor.plugins.wpview ) {
+                                       doc = editor.getDoc();
+                                       $( doc ).find( '[data-wpview-text="' + this.encodedText + '"]' ).html( html );
</ins><span class="cx">                           }
</span><del>-                       },
</del><ins>+                        }, this );
+               }
+       } );
</ins><span class="cx"> 
</span><del>-                       // The default properties used for objects with the `shortcode` key in
-                       // `wp.mce.view.add()`.
-                       shortcode: {
-                               view: Backbone.View,
-                               text: function( instance ) {
-                                       return instance.options.shortcode.string();
-                               },
</del><ins>+        // take advantage of the Backbone extend method
+       wp.mce.View.extend = Backbone.View.extend;
</ins><span class="cx"> 
</span><del>-                               toView: function( content ) {
-                                       var match = wp.shortcode.next( this.shortcode, content );
</del><ins>+        /**
+        * wp.mce.views
+        *
+        * A set of utilities that simplifies adding custom UI within a TinyMCE editor.
+        * At its core, it serves as a series of converters, transforming text to a
+        * custom UI, and back again.
+        */
+       wp.mce.views = {
</ins><span class="cx"> 
</span><del>-                                       if ( ! match )
-                                               return;
-
-                                       return {
-                                               index:   match.index,
-                                               content: match.content,
-                                               options: {
-                                                       shortcode: match.shortcode
-                                               }
-                                       };
-                               }
-                       }
</del><ins>+                /**
+                * wp.mce.views.register( type, view )
+                *
+                * Registers a new TinyMCE view.
+                *
+                * @param type
+                * @param constructor
+                *
+                */
+               register: function( type, constructor ) {
+                       views[ type ] = constructor;
</ins><span class="cx">           },
</span><span class="cx"> 
</span><del>-               // ### add( id, options )
-               // Registers a new TinyMCE view.
-               //
-               // Accepts a unique `id` and an `options` object.
-               //
-               // `options` accepts the following properties:
-               //
-               // * `pattern` is the regular expression used to scan the content and
-               // detect matching views.
-               //
-               // * `view` is a `Backbone.View` constructor. If a plain object is
-               // provided, it will automatically extend the parent constructor
-               // (usually `Backbone.View`). Views are instantiated when the `pattern`
-               // is successfully matched. The instance's `options` object is provided
-               // with the `original` matched value, the match `results` including
-               // capture groups, and the `viewType`, which is the constructor's `id`.
-               //
-               // * `extend` an existing view by passing in its `id`. The current
-               // view will inherit all properties from the parent view, and if
-               // `view` is set to a plain object, it will extend the parent `view`
-               // constructor.
-               //
-               // * `text` is a method that accepts an instance of the `view`
-               // constructor and transforms it into a text representation.
-               add: function( id, options ) {
-                       var parent, remove, base, properties;
-
-                       // Fetch the parent view or the default options.
-                       if ( options.extend )
-                               parent = wp.mce.view.get( options.extend );
-                       else if ( options.shortcode )
-                               parent = wp.mce.view.defaults.shortcode;
-                       else
-                               parent = wp.mce.view.defaults.pattern;
-
-                       // Extend the `options` object with the parent's properties.
-                       _.defaults( options, parent );
-                       options.id = id;
-
-                       // Create properties used to enhance the view for use in TinyMCE.
-                       properties = {
-                               // Ensure the wrapper element and references to the view are
-                               // removed. Otherwise, removed views could randomly restore.
-                               remove: function() {
-                                       delete instances[ this.el.id ];
-                                       this.$el.parent().remove();
-
-                                       // Trigger the inherited `remove` method.
-                                       if ( remove )
-                                               remove.apply( this, arguments );
-
-                                       return this;
-                               }
-                       };
-
-                       // If the `view` provided was an object, use the parent's
-                       // `view` constructor as a base. If a `view` constructor
-                       // was provided, treat that as the base.
-                       if ( _.isFunction( options.view ) ) {
-                               base = options.view;
-                       } else {
-                               base   = parent.view;
-                               remove = options.view.remove;
-                               _.defaults( properties, options.view );
-                       }
-
-                       // If there's a `remove` method on the `base` view that wasn't
-                       // created by this method, inherit it.
-                       if ( ! remove && ! base._mceview )
-                               remove = base.prototype.remove;
-
-                       // Automatically create the new `Backbone.View` constructor.
-                       options.view = base.extend( properties, {
-                               // Flag that the new view has been created by `wp.mce.view`.
-                               _mceview: true
-                       });
-
-                       views[ id ] = options;
</del><ins>+                /**
+                * wp.mce.views.get( id )
+                *
+                * Returns a TinyMCE view constructor.
+                */
+               get: function( type ) {
+                       return views[ type ];
</ins><span class="cx">           },
</span><span class="cx"> 
</span><del>-               // ### get( id )
-               // Returns a TinyMCE view options object.
-               get: function( id ) {
-                       return views[ id ];
</del><ins>+                /**
+                * wp.mce.views.unregister( type )
+                *
+                * Unregisters a TinyMCE view.
+                */
+               unregister: function( type ) {
+                       delete views[ type ];
</ins><span class="cx">           },
</span><span class="cx"> 
</span><del>-               // ### remove( id )
-               // Unregisters a TinyMCE view.
-               remove: function( id ) {
-                       delete views[ id ];
-               },
-
-               // ### toViews( content )
-               // 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 )`.
</del><ins>+                /**
+                * toViews( content )
+                * Scans a `content` string for each view's pattern, replacing any
+                * matches with wrapper elements, and creates a new instance for
+                * every match, which triggers the related data to be fetched.
+                *
+                */
</ins><span class="cx">           toViews: function( content ) {
</span><span class="cx">                  var pieces = [ { content: content } ],
</span><span class="lines">@@ -190,12 +112,13 @@
</span><span class="cx">                                  // and slicing the string as we go.
</span><span class="cx">                                  while ( remaining && (result = view.toView( remaining )) ) {
</span><span class="cx">                                          // Any text before the match becomes an unprocessed piece.
</span><del>-                                               if ( result.index )
</del><ins>+                                                if ( result.index ) {
</ins><span class="cx">                                                   pieces.push({ content: remaining.substring( 0, result.index ) });
</span><ins>+                                               }
</ins><span class="cx"> 
</span><span class="cx">                                          // Add the processed piece for the match.
</span><span class="cx">                                          pieces.push({
</span><del>-                                                       content:   wp.mce.view.toView( viewType, result.options ),
</del><ins>+                                                        content: wp.mce.views.toView( viewType, result.content, result.options ),
</ins><span class="cx">                                                   processed: true
</span><span class="cx">                                          });
</span><span class="cx"> 
</span><span class="lines">@@ -205,145 +128,178 @@
</span><span class="cx"> 
</span><span class="cx">                                  // There are no additional matches. If any content remains,
</span><span class="cx">                                  // add it as an unprocessed piece.
</span><del>-                                       if ( remaining )
</del><ins>+                                        if ( remaining ) {
</ins><span class="cx">                                           pieces.push({ content: remaining });
</span><ins>+                                       }
</ins><span class="cx">                           });
</span><span class="cx">                  });
</span><span class="cx"> 
</span><span class="cx">                  return _.pluck( pieces, 'content' ).join('');
</span><span class="cx">          },
</span><span class="cx"> 
</span><del>-               toView: function( viewType, options ) {
-                       var view = wp.mce.view.get( viewType ),
-                               instance, id;
</del><ins>+                /**
+                * Create a placeholder for a particular view type
+                *
+                * @param viewType
+                * @param text
+                * @param options
+                *
+                */
+               toView: function( viewType, text, options ) {
+                       var view = wp.mce.views.get( viewType ),
+                               encodedText = window.encodeURIComponent( text ),
+                               instance, viewOptions;
</ins><span class="cx"> 
</span><del>-                       if ( ! view )
-                               return '';
</del><span class="cx"> 
</span><del>-                       // Create a new view instance.
-                       instance = new view.view( _.extend( options || {}, {
-                               viewType: viewType
-                       }) );
</del><ins>+                        if ( ! view ) {
+                               return text;
+                       }
</ins><span class="cx"> 
</span><del>-                       // 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;
</del><ins>+                        if ( ! wp.mce.views.getInstance( encodedText ) ) {
+                               viewOptions = options;
+                               viewOptions.encodedText = encodedText;
+                               instance = new view.View( viewOptions );
+                               instances[ encodedText ] = instance;
+                       }
</ins><span class="cx"> 
</span><del>-                       // Create a dummy `$wrapper` property to allow `$wrapper` to be
-                       // called in the view's `render` method without a conditional.
-                       instance.$wrapper = $();
-
</del><span class="cx">                   return wp.html.string({
</span><del>-                               // If the view is a span, wrap it in a span.
-                               tag: 'span' === instance.tagName ? 'span' : 'div',
</del><ins>+                                tag: 'div',
</ins><span class="cx"> 
</span><span class="cx">                          attrs: {
</span><del>-                                       'class':           'wp-view-wrap wp-view-type-' + viewType,
-                                       'data-wp-view':    id,
-                                       'contenteditable': false
-                               }
</del><ins>+                                        'class': 'wpview-wrap wpview-type-' + viewType,
+                                       'data-wpview-text': encodedText,
+                                       'data-wpview-type': viewType,
+                                       'contenteditable': 'false'
+                               },
+
+                               content: '\u00a0'
</ins><span class="cx">                   });
</span><span class="cx">          },
</span><span class="cx"> 
</span><del>-               // ### render( scope )
-               // 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),
-                                       view = wp.mce.view.instance( this );
</del><ins>+                /**
+                * Refresh views after an update is made
+                * 
+                * @param view {object} being refreshed
+                * @param text {string} textual representation of the view
+                */
+               refreshView: function( view, text ) {
+                       var encodedText = window.encodeURIComponent( text ),
+                               viewOptions,
+                               result, instance;
</ins><span class="cx"> 
</span><del>-                               if ( ! view )
-                                       return;
</del><ins>+                        instance = wp.mce.views.getInstance( encodedText );
</ins><span class="cx"> 
</span><del>-                               // Link the real wrapper to the view.
-                               view.$wrapper = wrapper;
-                               // Render the view.
-                               view.render();
-                               // Detach the view element to ensure events are not unbound.
-                               view.$el.detach();
</del><ins>+                        if ( ! instance ) {
+                               result = view.toView( text );
+                               viewOptions = result.options;
+                               viewOptions.encodedText = encodedText;
+                               instance = new view.View( viewOptions );
+                               instances[ encodedText ] = instance;
+                       }
</ins><span class="cx"> 
</span><del>-                               // 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 class="wp-view-end"></span>');
-                       });
</del><ins>+                        wp.mce.views.render();
</ins><span class="cx">           },
</span><span class="cx"> 
</span><del>-               // ### toText( content )
-               // 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 ) : '';
-                       });
</del><ins>+                getInstance: function( encodedText ) {
+                       return instances[ encodedText ];
</ins><span class="cx">           },
</span><span class="cx"> 
</span><del>-               // ### Remove internal TinyMCE attributes.
-               removeInternalAttrs: function( attrs ) {
-                       var result = {};
-                       _.each( attrs, function( value, attr ) {
-                               if ( -1 === attr.indexOf('data-mce') )
-                                       result[ attr ] = value;
-                       });
-                       return result;
</del><ins>+                /** 
+                * render( scope )
+                * 
+                * 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() {
+                       _.each( instances, function( instance ) {
+                               instance.render();
+                       } );
</ins><span class="cx">           },
</span><span class="cx"> 
</span><del>-               // ### Parse an attribute string and removes internal TinyMCE attributes.
-               attrs: function( content ) {
-                       return wp.mce.view.removeInternalAttrs( wp.html.attrs( content ) );
-               },
</del><ins>+                edit: function( node ) {
+                       var viewType = $( node ).data('wpview-type'),
+                               view = wp.mce.views.get( viewType );
</ins><span class="cx"> 
</span><del>-               // ### instance( scope )
-               //
-               // Accepts a MCE view wrapper `node` (i.e. a node with the
-               // `wp-view-wrap` class).
-               instance: function( node ) {
-                       var id = $( node ).data('wp-view');
</del><ins>+                        if ( view ) {
+                               view.edit( node );
+                       }
+               }
+       };
</ins><span class="cx"> 
</span><del>-                       if ( id )
-                               return instances[ id ];
-               },
</del><ins>+        wp.mce.gallery = {
+               shortcode: 'gallery',
+               toView:  function( content ) {
+                       var match = wp.shortcode.next( this.shortcode, content );
</ins><span class="cx"> 
</span><del>-               // ### Select a view.
-               //
-               // Accepts a MCE view wrapper `node` (i.e. a node with the
-               // `wp-view-wrap` class).
-               select: function( node ) {
-                       var $node = $(node);
-
-                       // Bail if node is already selected.
-                       if ( $node.hasClass('selected') )
</del><ins>+                        if ( ! match ) {
</ins><span class="cx">                           return;
</span><ins>+                       }
</ins><span class="cx"> 
</span><del>-                       $node.addClass('selected');
-                       $( node.firstChild ).trigger('select');
</del><ins>+                        return {
+                               index:   match.index,
+                               content: match.content,
+                               options: {
+                                       shortcode: match.shortcode
+                               }
+                       };
</ins><span class="cx">           },
</span><ins>+               View: wp.mce.View.extend({
+                       className: 'editor-gallery',
+                       template:  media.template('editor-gallery'),
</ins><span class="cx"> 
</span><del>-               // ### Deselect a view.
-               //
-               // Accepts a MCE view wrapper `node` (i.e. a node with the
-               // `wp-view-wrap` class).
-               deselect: function( node ) {
-                       var $node = $(node);
</del><ins>+                        // The fallback post ID to use as a parent for galleries that don't
+                       // specify the `ids` or `include` parameters.
+                       //
+                       // Uses the hidden input on the edit posts page by default.
+                       postID: $('#post_ID').val(),
</ins><span class="cx"> 
</span><del>-                       // Bail if node is already selected.
-                       if ( ! $node.hasClass('selected') )
-                               return;
</del><ins>+                        initialize: function( options ) {
+                               this.shortcode = options.shortcode;
+                               this.fetch();
+                       },
</ins><span class="cx"> 
</span><del>-                       $node.removeClass('selected');
-                       $( node.firstChild ).trigger('deselect');
</del><ins>+                        fetch: function() {
+                               this.attachments = wp.media.gallery.attachments( this.shortcode, this.postID );
+                               this.attachments.more().done( _.bind( this.render, this ) );
+                       },
+
+                       getHtml: function() {
+                               var attrs = this.shortcode.attrs.named,
+                                       options;
+
+                               if ( ! this.attachments.length ) {
+                                       return;
+                               }
+
+                               options = {
+                                       attachments: this.attachments.toJSON(),
+                                       columns: attrs.columns ? parseInt( attrs.columns, 10 ) : 3
+                               };
+
+                               return this.template( options );
+
+                       }
+               }),
+
+               edit: function( node ) {
+                       var gallery = wp.media.gallery,
+                               self = this,
+                               frame, data;
+
+                       data = window.decodeURIComponent( $( node ).data('wpview-text') );
+                       frame = gallery.edit( data );
+
+                       frame.state('gallery-edit').on( 'update', function( selection ) {
+                               var shortcode = gallery.shortcode( selection ).string();
+                               $( node ).attr( 'data-wpview-text', window.encodeURIComponent( shortcode ) );
+                               wp.mce.views.refreshView( self, shortcode );
+                               frame.detach();
+                       });
</ins><span class="cx">           }
</span><ins>+
</ins><span class="cx">   };
</span><del>-
-}(jQuery));
</del><span class="cx">\ No newline at end of file
</span><ins>+       wp.mce.views.register( 'gallery', wp.mce.gallery );
+}(jQuery));
</ins></span></pre></div>
<a id="trunksrcwpincludesjstinymcepluginswpgallerypluginjs"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js (27407 => 27408)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js     2014-03-05 06:38:23 UTC (rev 27407)
+++ trunk/src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js        2014-03-05 07:00:18 UTC (rev 27408)
</span><span class="lines">@@ -59,7 +59,7 @@
</span><span class="cx">                  return;
</span><span class="cx">          }
</span><span class="cx"> 
</span><del>-               // Check if the `wp.media.gallery` API exists.
</del><ins>+                // Check if the `wp.media` API exists.
</ins><span class="cx">           if ( typeof wp === 'undefined' || ! wp.media ) {
</span><span class="cx">                  return;
</span><span class="cx">          }
</span><span class="lines">@@ -166,7 +166,11 @@
</span><span class="cx">  });
</span><span class="cx"> 
</span><span class="cx">  editor.on( 'BeforeSetContent', function( event ) {
</span><del>-               event.content = replaceGalleryShortcodes( event.content );
</del><ins>+                // 'wpview' handles the gallery shortcode when present
+               if ( ! editor.plugins.wpview ) {
+                       event.content = replaceGalleryShortcodes( event.content );
+               }
+
</ins><span class="cx">           event.content = replaceAVShortcodes( event.content );
</span><span class="cx">  });
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunksrcwpincludesjstinymcepluginswpviewpluginjs"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-includes/js/tinymce/plugins/wpview/plugin.js (27407 => 27408)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/js/tinymce/plugins/wpview/plugin.js        2014-03-05 06:38:23 UTC (rev 27407)
+++ trunk/src/wp-includes/js/tinymce/plugins/wpview/plugin.js   2014-03-05 07:00:18 UTC (rev 27408)
</span><span class="lines">@@ -2,190 +2,366 @@
</span><span class="cx"> /**
</span><span class="cx">  * WordPress View plugin.
</span><span class="cx">  */
</span><del>-
-(function() {
-       var VK = tinymce.VK,
</del><ins>+tinymce.PluginManager.add( 'wpview', function( editor ) {
+       var selected,
+               VK = tinymce.util.VK,
</ins><span class="cx">           TreeWalker = tinymce.dom.TreeWalker,
</span><del>-               selected;
</del><ins>+                toRemove = false;
</ins><span class="cx"> 
</span><del>-       tinymce.create('tinymce.plugins.wpView', {
-               init : function( editor ) {
-                       var wpView = this;
-
-                       // Check if the `wp.mce` API exists.
-                       if ( typeof wp === 'undefined' || ! wp.mce ) {
-                               return;
</del><ins>+        function getParentView( node ) {
+               while ( node && node.nodeName !== 'BODY' ) {
+                       if ( isView( node ) ) {
+                               return node;
</ins><span class="cx">                   }
</span><span class="cx"> 
</span><del>-                       editor.on( 'PreInit', function() {
-                               // Add elements so we can set `contenteditable` to false.
-                               editor.schema.addValidElements('div[*],span[*]');
-                       });
</del><ins>+                        node = node.parentNode;
+               }
+       }
</ins><span class="cx"> 
</span><del>-                       // 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.on( 'BeforeSetContent', function( e ) {
-                               if ( ! e.content ) {
-                                       return;
-                               }
</del><ins>+        function isView( node ) {
+               return node && /\bwpview-wrap\b/.test( node.className );
+       }
</ins><span class="cx"> 
</span><del>-                               e.content = wp.mce.view.toViews( e.content );
-                       });
</del><ins>+        function createPadNode() {
+               return editor.dom.create( 'p', { 'data-wpview-pad': 1 },
+                       ( tinymce.Env.ie && tinymce.Env.ie < 11 ) ? '' : '<br data-mce-bogus="1" />' );
+       }
</ins><span class="cx"> 
</span><del>-                       // When the editor's content has been updated and the DOM has been
-                       // processed, render the views in the document.
-                       editor.on( 'SetContent', function() {
-                               wp.mce.view.render( editor.getDoc() );
-                       });
</del><ins>+        /**
+        * Get the text/shortcode string for a view.
+        *
+        * @param view The view wrapper's HTML id or node
+        * @returns string The text/shoercode string of the view
+        */
+       function getViewText( view ) {
+               view = getParentView( typeof view === 'string' ? editor.dom.get( view ) : view );
</ins><span class="cx"> 
</span><del>-                       editor.on( 'init', function() {
-                               var selection = editor.selection;
-                               // When a view is selected, ensure content that is being pasted
-                               // or inserted is added to a text node (instead of the view).
-                               editor.on( 'BeforeSetContent', function() {
-                                       var walker, target,
-                                               view = wpView.getParentView( selection.getNode() );
</del><ins>+                if ( view ) {
+                       return window.decodeURIComponent( editor.dom.getAttrib( view, 'data-wpview-text' ) || '' );
+               }
+               return '';
+       }
</ins><span class="cx"> 
</span><del>-                                       // If the selection is not within a view, bail.
-                                       if ( ! view ) {
-                                               return;
-                                       }
</del><ins>+        /**
+        * Set the view's original text/shortcode string
+        *
+        * @param view The view wrapper's HTML id or node
+        * @param text The text string to be set
+        */
+       function setViewText( view, text ) {
+               view = getParentView( typeof view === 'string' ? editor.dom.get( view ) : view );
</ins><span class="cx"> 
</span><del>-                                       // If there are no additional nodes or the next node is a
-                                       // view, create a text node after the current view.
-                                       if ( ! view.nextSibling || wpView.isView( view.nextSibling ) ) {
-                                               target = editor.getDoc().createTextNode('');
-                                               editor.dom.insertAfter( target, view );
</del><ins>+                if ( view ) {
+                       editor.dom.setAttrib( view, 'data-wpview-text', window.encodeURIComponent( text || '' ) );
+                       return true;
+               }
+               return false;
+       }
</ins><span class="cx"> 
</span><del>-                                       // Otherwise, find the next text node.
-                                       } else {
-                                               walker = new TreeWalker( view.nextSibling, view.nextSibling );
-                                               target = walker.next();
-                                       }
</del><ins>+        function _stop( event ) {
+               event.stopPropagation();
+       }
</ins><span class="cx"> 
</span><del>-                                       // Select the `target` text node.
-                                       selection.select( target );
-                                       selection.collapse( true );
-                               });
</del><ins>+        function select( viewNode ) {
+               var clipboard,
+                       dom = editor.dom;
</ins><span class="cx"> 
</span><del>-                               // 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.on( 'SetContent', function( e ) {
-                                       if ( ! e.context ) {
-                                               return;
-                                       }
</del><ins>+                // Bail if node is already selected.
+               if ( viewNode === selected ) {
+                       return;
+               }
</ins><span class="cx"> 
</span><del>-                                       var node = selection.getNode();
</del><ins>+                deselect();
+               selected = viewNode;
+               dom.addClass( viewNode, 'selected' );
</ins><span class="cx"> 
</span><del>-                                       if ( ! node.innerHTML ) {
-                                               return;
-                                       }
</del><ins>+                clipboard = dom.create( 'div', {
+                       'class': 'wpview-clipboard',
+                       'contenteditable': 'true'
+               }, getViewText( viewNode ) );
</ins><span class="cx"> 
</span><del>-                                       node.innerHTML = wp.mce.view.toViews( node.innerHTML );
-                                       wp.mce.view.render( node );
-                               });
-                       });
</del><ins>+                viewNode.appendChild( clipboard );
</ins><span class="cx"> 
</span><del>-                       // When the editor's contents are being accessed as a string,
-                       // transform any views back to their text representations.
-                       editor.on( 'PostProcess', function( e ) {
-                               if ( ( ! e.get && ! e.save ) || ! e.content ) {
-                                       return;
-                               }
</del><ins>+                // Both of the following are necessary to prevent manipulating the selection/focus
+               editor.dom.bind( clipboard, 'beforedeactivate focusin focusout', _stop );
+               editor.dom.bind( selected, 'beforedeactivate focusin focusout', _stop );
</ins><span class="cx"> 
</span><del>-                               e.content = wp.mce.view.toText( e.content );
-                       });
</del><ins>+                // select the hidden div
+               editor.selection.select( clipboard, true );
+       }
</ins><span class="cx"> 
</span><del>-                       // Triggers when the selection is changed.
-                       // Add the event handler to the top of the stack.
-                       editor.on( 'NodeChange', function( e ) {
-                               var view = wpView.getParentView( e.element );
</del><ins>+        /**
+        * Deselect a selected view and remove clipboard
+        */
+       function deselect() {
+               var clipboard,
+                       dom = editor.dom;
</ins><span class="cx"> 
</span><del>-                               // Update the selected view.
-                               if ( view ) {
-                                       wpView.select( view );
</del><ins>+                if ( selected ) {
+                       clipboard = editor.dom.select( '.wpview-clipboard', selected )[0];
+                       dom.unbind( clipboard );
+                       dom.remove( clipboard );
</ins><span class="cx"> 
</span><del>-                                       // Prevent the selection from propagating to other plugins.
-                                       return false;
</del><ins>+                        dom.unbind( selected, 'beforedeactivate focusin focusout click mouseup', _stop );
+                       dom.removeClass( selected, 'selected' );
</ins><span class="cx"> 
</span><del>-                               // If we've clicked off of the selected view, deselect it.
-                               } else {
-                                       wpView.deselect();
-                               }
-                       });
</del><ins>+                        editor.selection.select( selected.nextSibling );
+                       editor.selection.collapse();
</ins><span class="cx"> 
</span><del>-                       editor.on( 'keydown', function( event ) {
-                               var keyCode = event.keyCode,
-                                       view, instance;
</del><ins>+                }
</ins><span class="cx"> 
</span><del>-                               // If a view isn't selected, let the event go on its merry way.
-                               if ( ! selected ) {
-                                       return;
-                               }
</del><ins>+                selected = null;
+       }
</ins><span class="cx"> 
</span><del>-                               // If the caret is not within the selected view, deselect the
-                               // view and bail.
-                               view = wpView.getParentView( editor.selection.getNode() );
-                               if ( view !== selected ) {
-                                       wpView.deselect();
-                                       return;
-                               }
</del><ins>+        // Check if the `wp.mce` API exists.
+       if ( typeof wp === 'undefined' || ! wp.mce ) {
+               return;
+       }
</ins><span class="cx"> 
</span><del>-                               // If delete or backspace is pressed, delete the view.
-                               if ( keyCode === VK.DELETE || keyCode === VK.BACKSPACE ) {
-                                       if ( (instance = wp.mce.view.instance( selected )) ) {
-                                               instance.remove();
-                                               wpView.deselect();
</del><ins>+        editor.on( 'BeforeAddUndo', function( event ) {
+               if ( selected && ! toRemove ) {
+                       event.preventDefault();
+               }
+       });
+
+       // When the editor's content changes, scan the new content for
+       // matching view patterns, and transform the matches into
+       // view wrappers.
+       editor.on( 'BeforeSetContent', function( e ) {
+               if ( ! e.content ) {
+                       return;
+               }
+
+               e.content = wp.mce.views.toViews( e.content );
+       });
+
+       // When the editor's content has been updated and the DOM has been
+       // processed, render the views in the document.
+       editor.on( 'SetContent', function( event ) {
+               var body, padNode;
+
+               wp.mce.views.render();
+
+               // Add padding <p> if the noneditable node is last
+               if ( event.load || ! event.set ) {
+                       body = editor.getBody();
+
+                       if ( isView( body.lastChild ) ) {
+                               padNode = createPadNode();
+                               body.appendChild( padNode );
+                               editor.selection.setCursorLocation( padNode, 0 );
+                       }
+               }
+
+       //      refreshEmptyContentNode();
+       });
+
+       // Detect mouse down events that are adjacent to a view when a view is the first view or the last view
+       editor.on( 'click', function( event ) {
+               var body = editor.getBody(),
+                       doc = editor.getDoc(),
+                       scrollTop = doc.documentElement.scrollTop || body.scrollTop || 0,
+                       x, y, firstNode, lastNode, padNode;
+
+               if ( event.target.nodeName === 'HTML' && ! event.metaKey && ! event.ctrlKey ) {
+                       firstNode = body.firstChild;
+                       lastNode = body.lastChild;
+                       x = event.clientX;
+                       y = event.clientY;
+
+                       if ( isView( firstNode ) && ( ( x < firstNode.offsetLeft && y < ( firstNode.offsetHeight - scrollTop ) ) ||
+                               y < firstNode.offsetTop ) ) {
+                               // detect events above or to the left of the first view
+
+                               padNode = createPadNode();
+                               body.insertBefore( padNode, firstNode );
+                       } else if ( isView( lastNode ) && ( x > ( lastNode.offsetLeft + lastNode.offsetWidth ) ||
+                               ( ( scrollTop + y ) - ( lastNode.offsetTop + lastNode.offsetHeight ) ) > 0 ) ) {
+                               // detect events to the right and below the last view
+
+                               padNode = createPadNode();
+                               body.appendChild( padNode );
+                       }
+
+                       if ( padNode ) {
+                               editor.selection.setCursorLocation( padNode, 0 );
+                       }
+               }
+       });
+
+       editor.on( 'init', function() {
+               var selection = editor.selection;
+               // When a view is selected, ensure content that is being pasted
+               // or inserted is added to a text node (instead of the view).
+               editor.on( 'BeforeSetContent', function() {
+                       var walker, target,
+                               view = getParentView( selection.getNode() );
+
+                       // If the selection is not within a view, bail.
+                       if ( ! view ) {
+                               return;
+                       }
+
+                       if ( ! view.nextSibling || isView( view.nextSibling ) ) {
+                               // If there are no additional nodes or the next node is a
+                               // view, create a text node after the current view.
+                               target = editor.getDoc().createTextNode('');
+                               editor.dom.insertAfter( target, view );
+                       } else {
+                               // Otherwise, find the next text node.
+                               walker = new TreeWalker( view.nextSibling, view.nextSibling );
+                               target = walker.next();
+                       }
+
+                       // Select the `target` text node.
+                       selection.select( target );
+                       selection.collapse( true );
+               });
+
+               // When the selection's content changes, scan any new content
+               // for matching views.
+               //
+               // Runs on paste and on inserting nodes/html.
+               editor.on( 'SetContent', function( e ) {
+                       if ( ! e.context ) {
+                               return;
+                       }
+
+                       var node = selection.getNode();
+
+                       if ( ! node.innerHTML ) {
+                               return;
+                       }
+
+                       node.innerHTML = wp.mce.views.toViews( node.innerHTML );
+               });
+
+               editor.dom.bind( editor.getBody(), 'mousedown mouseup click', function( event ) {
+                       var view = getParentView( event.target );
+
+                       // Contain clicks inside the view wrapper
+                       if ( view ) {
+                               event.stopPropagation();
+
+                               if ( event.type === 'click' ) {
+                                       if ( ! event.metaKey && ! event.ctrlKey ) {
+                                               if ( editor.dom.hasClass( event.target, 'edit' ) ) {
+                                                       wp.mce.views.edit( view );
+                                               } else if ( editor.dom.hasClass( event.target, 'remove' ) ) {
+                                                       editor.dom.remove( view );
+                                               }
</ins><span class="cx">                                   }
</span><span class="cx">                          }
</span><del>-
-                               // Let keypresses that involve the command or control keys through.
-                               // Also, let any of the F# keys through.
-                               if ( event.metaKey || event.ctrlKey || ( keyCode >= 112 && keyCode <= 123 ) ) {
-                                       return;
</del><ins>+                                select( view );
+                               // returning false stops the ugly bars from appearing in IE11 and stops the view being selected as a range in FF
+                               // unfortunately, it also inhibits the dragging fo views to a new location
+                               return false;
+                       } else {
+                               if ( event.type === 'click' ) {
+                                       deselect();
</ins><span class="cx">                           }
</span><ins>+                       }
+               });
</ins><span class="cx"> 
</span><del>-                               event.preventDefault();
-                       });
-               },
</del><ins>+        });
</ins><span class="cx"> 
</span><del>-               getParentView : function( node ) {
-                       while ( node ) {
-                               if ( this.isView( node ) ) {
-                                       return node;
-                               }
</del><ins>+        editor.on( 'PreProcess', function( event ) {
+               var dom = editor.dom;
</ins><span class="cx"> 
</span><del>-                               node = node.parentNode;
</del><ins>+                // Remove empty padding nodes
+               tinymce.each( dom.select( 'p[data-wpview-pad]', event.node ), function( node ) {
+                       if ( dom.isEmpty( node ) ) {
+                               dom.remove( node );
+                       } else {
+                               dom.setAttrib( node, 'data-wpview-pad', null );
</ins><span class="cx">                   }
</span><del>-               },
</del><ins>+                });
</ins><span class="cx"> 
</span><del>-               isView : function( node ) {
-                       return (/(?:^|\s)wp-view-wrap(?:\s|$)/).test( node.className );
-               },
</del><ins>+                // Replace the wpview node with the wpview string/shortcode?
+               tinymce.each( dom.select( 'div[data-wpview-text]', event.node ), function( node ) {
+                       // Empty the wrap node
+                       if ( 'textContent' in node ) {
+                               node.textContent = '';
+                       } else {
+                               node.innerText = '';
+                       }
</ins><span class="cx"> 
</span><del>-               select : function( view ) {
-                       if ( view === selected ) {
-                               return;
</del><ins>+                        // TODO: that makes all views into block tags (as we use <div>).
+                       // Can use 'PostProcess' and a regex instead.
+                       dom.replace( dom.create( 'p', null, window.decodeURIComponent( dom.getAttrib( node, 'data-wpview-text' ) ) ), node );
+               });
+    });
+
+       editor.on( 'keydown', function( event ) {
+               var keyCode = event.keyCode,
+                       view;
+
+               // If a view isn't selected, let the event go on its merry way.
+               if ( ! selected ) {
+                       return;
+               }
+
+               // Let keypresses that involve the command or control keys through.
+               // Also, let any of the F# keys through.
+               if ( event.metaKey || event.ctrlKey || ( keyCode >= 112 && keyCode <= 123 ) ) {
+                       if ( ( event.metaKey || event.ctrlKey ) && keyCode === 88 ) {
+                               toRemove = selected;
</ins><span class="cx">                   }
</span><ins>+                       return;
+               }
</ins><span class="cx"> 
</span><del>-                       this.deselect();
-                       selected = view;
-                       wp.mce.view.select( selected );
-               },
</del><ins>+                // If the caret is not within the selected view, deselect the
+               // view and bail.
+               view = getParentView( editor.selection.getNode() );
</ins><span class="cx"> 
</span><del>-               deselect : function() {
-                       if ( selected ) {
-                               wp.mce.view.deselect( selected );
</del><ins>+                if ( view !== selected ) {
+                       deselect();
+                       return;
+               }
+
+               // If delete or backspace is pressed, delete the view.
+               if ( keyCode === VK.DELETE || keyCode === VK.BACKSPACE ) {
+                       editor.dom.remove( selected );
+               }
+
+               event.preventDefault();
+       });
+
+       editor.on( 'keyup', function( event ) {
+               var padNode,
+                       keyCode = event.keyCode,
+                       body = editor.getBody(),
+                       range;
+
+               if ( toRemove ) {
+                       editor.dom.remove( toRemove );
+                       toRemove = false;
+               }
+
+               if ( keyCode === VK.DELETE || keyCode === VK.BACKSPACE ) {
+                       // Make sure there is padding if the last element is a view
+                       if ( isView( body.lastChild ) ) {
+                               padNode = createPadNode();
+                               body.appendChild( padNode );
+
+                               if ( body.childNodes.length === 2 ) {
+                                       editor.selection.setCursorLocation( padNode, 0 );
+                               }
</ins><span class="cx">                   }
</span><span class="cx"> 
</span><del>-                       selected = null;
</del><ins>+                        range = editor.selection.getRng();
+
+                       // Allow an initial element in the document to be removed when it is before a view
+                       if ( body.firstChild === range.startContainer && range.collapsed === true &&
+                                       isView( range.startContainer.nextSibling ) && range.startOffset === 0 ) {
+
+                               editor.dom.remove( range.startContainer );
+                       }
</ins><span class="cx">           }
</span><span class="cx">  });
</span><span class="cx"> 
</span><del>-       // Register plugin
-       tinymce.PluginManager.add( 'wpview', tinymce.plugins.wpView );
-})();
</del><ins>+        return {
+               getViewText: getViewText,
+               setViewText: setViewText
+       };
+});
</ins></span></pre></div>
<a id="trunksrcwpincludesjstinymceskinswordpresswpcontentcss"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css (27407 => 27408)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css  2014-03-05 06:38:23 UTC (rev 27407)
+++ trunk/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css     2014-03-05 07:00:18 UTC (rev 27408)
</span><span class="lines">@@ -198,6 +198,141 @@
</span><span class="cx">  outline: 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+
+/**
+ * WP Views
+ */
+
+/* IE hasLayout. Needed for all IE incl. 11 (ugh, not again!!) */
+.wpview-wrap {
+       width: 99.99%;
+       position: relative;
+}
+
+/* delegate the handling of the selection to the wpview tinymce plugin */
+.wpview-wrap,
+.wpview-wrap * {
+       -moz-user-select: none;
+       -webkit-user-select: none;
+       -ms-user-select: none;
+       user-select: none;
+}
+
+/* hide the shortcode content, but allow the content to still be selected */
+.wpview-wrap .wpview-clipboard {
+       position: absolute;
+       top: 0;
+       left: 0;
+       z-index: -1;
+       clip: rect(1px, 1px, 1px, 1px);
+       overflow: hidden;
+       outline: 0;
+}
+
+/**
+ * Gallery preview
+ */
+.wpview-type-gallery {
+    position: relative;
+    padding: 0 0 12px;
+    margin-bottom: 16px;
+       cursor: pointer;
+}
+
+ .wpview-type-gallery:after {
+    content: '';
+    display: block;
+    height: 0;
+    clear: both;
+    visibility: hidden;
+}
+
+ .wpview-type-gallery.selected {
+       background-color: #efefef;
+}
+
+.wpview-type-gallery .toolbar {
+    position: absolute;
+    top: 0;
+    left: 0;
+    background-color: #333;
+    color: white;
+    padding: 4px;
+       display: none;
+}
+
+.wpview-type-gallery.selected .toolbar {
+       display: block;
+}
+
+.wpview-type-gallery .toolbar span {
+       cursor: pointer;
+}
+
+.gallery img[data-mce-selected]:focus {
+       outline: none;
+}
+
+.gallery a {
+       cursor: default;
+}
+
+.gallery {
+       margin: auto;
+    line-height: 1;
+}
+
+.gallery .gallery-item {
+       float: left;
+       margin: 10px 0 0 0;
+       text-align: center;
+}
+
+.gallery .gallery-caption,
+.gallery .gallery-icon {
+       margin: 0;
+}
+
+.gallery-columns-1 .gallery-item {
+       width: 99%;
+}
+
+.gallery-columns-2 .gallery-item {
+       width: 49.5%;
+}
+
+.gallery-columns-3 .gallery-item {
+       width: 33%;
+}
+
+.gallery-columns-4 .gallery-item {
+       width: 24.75%;
+}
+
+.gallery-columns-5 .gallery-item {
+       width: 19.825%;
+}
+
+.gallery-columns-6 .gallery-item {
+       width: 16%;
+}
+
+.gallery-columns-7 .gallery-item {
+       width: 14%;
+}
+
+.gallery-columns-8 .gallery-item {
+       width: 12%;
+}
+
+.gallery-columns-9 .gallery-item {
+       width: 11%;
+}
+
+.gallery img {
+       border: 1px solid #cfcfcf;
+}
+
</ins><span class="cx"> img.wp-oembed {
</span><span class="cx">  border: 1px dashed #888;
</span><span class="cx">  background: #f7f5f2 url(images/embedded.png) no-repeat scroll center center;
</span></span></pre></div>
<a id="trunksrcwpincludesmediatemplatephp"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-includes/media-template.php (27407 => 27408)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/media-template.php 2014-03-05 06:38:23 UTC (rev 27407)
+++ trunk/src/wp-includes/media-template.php    2014-03-05 07:00:18 UTC (rev 27408)
</span><span class="lines">@@ -650,6 +650,36 @@
</span><span class="cx">  </script>
</span><span class="cx">  <?php
</span><span class="cx"> 
</span><ins>+               //TODO: do we want to deal with the fact that the elements used for gallery items are filterable and can be overriden via shortcode attributes
+               // do we want to deal with the difference between display and edit context at all? (e.g. wptexturize() being applied to the caption.
+       ?>
+
+       <script type="text/html" id="tmpl-editor-gallery">
+               <div class="toolbar">
+                       <div class="dashicons dashicons-format-gallery edit"></div>
+                       <div class="dashicons dashicons-no-alt remove"></div>
+               </div>
+               <div class="gallery gallery-columns-{{{ data.columns }}}">
+                       <# _.each( data.attachments, function( attachment, index ) { #>
+                               <dl class="gallery-item">
+                                       <dt class="gallery-icon">
+                                               <?php // TODO: need to figure out the best way to make sure that we have thumbnails ?>
+                                               <img src="{{{ attachment.sizes.thumbnail.url }}}" />
+                                       </dt>
+                                       <dd class="wp-caption-text gallery-caption">
+                                               {{ attachment.caption }}
+                                       </dd>
+                               </dl>
+                               <?php // this is kind silly, but copied from the gallery shortcode. Maybe it should be removed ?>
+                               <# if ( index % data.columns === data.columns - 1 ) { #>
+                                       <br style="clear: both;">
+                               <# } #>
+
+                       <# } ); #>
+               </div>
+       </script>
+       <?php
+
</ins><span class="cx">   /**
</span><span class="cx">   * Prints the media manager custom media templates.
</span><span class="cx">   *
</span></span></pre></div>
<a id="trunksrcwpincludesversionphp"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-includes/version.php (27407 => 27408)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/version.php        2014-03-05 06:38:23 UTC (rev 27407)
+++ trunk/src/wp-includes/version.php   2014-03-05 07:00:18 UTC (rev 27408)
</span><span class="lines">@@ -18,7 +18,7 @@
</span><span class="cx">  *
</span><span class="cx">  * @global string $tinymce_version
</span><span class="cx">  */
</span><del>-$tinymce_version = '4018-20140303';
</del><ins>+$tinymce_version = '4018-20140304';
</ins><span class="cx"> 
</span><span class="cx"> /**
</span><span class="cx">  * Holds the required PHP version
</span></span></pre>
</div>
</div>

</body>
</html>