Make WordPress Core

Ticket #26959: 26959-01.patch

File 26959-01.patch, 24.4 KB (added by gcorne, 11 years ago)
  • src/wp-includes/class-wp-editor.php

    diff --git src/wp-includes/class-wp-editor.php src/wp-includes/class-wp-editor.php
    index fb36424..46b4978 100644
    final class _WP_Editors { 
    231231                                                'fullscreen',
    232232                                                'wordpress',
    233233                                                'wpeditimage',
    234                                                 'wpgallery',
    235234                                                'wplink',
    236235                                                'wpdialogs',
     236                                                'wpview'
    237237                                        ) ) );
    238238
    239239                                        if ( ( $key = array_search( 'spellchecker', $plugins ) ) !== false ) {
    final class _WP_Editors { 
    495495                if ( self::$has_medialib ) {
    496496                        add_thickbox();
    497497                        wp_enqueue_script('media-upload');
     498
     499                        if ( self::$has_tinymce )
     500                                wp_enqueue_script('mce-view');
    498501                }
     502
    499503        }
    500504
    501505        public static function wp_mce_translation() {
  • src/wp-includes/css/editor.css

    diff --git src/wp-includes/css/editor.css src/wp-includes/css/editor.css
    index f415161..3072e64 100644
    i.mce-i-wp_page:before { 
    10751075        padding-left: 12px;
    10761076}
    10771077*/
     1078
     1079
     1080
    10781081/* Distraction Free Writing mode
    10791082 * =Overlay Styles
    10801083-------------------------------------------------------------- */
  • src/wp-includes/js/mce-view.js

    diff --git src/wp-includes/js/mce-view.js src/wp-includes/js/mce-view.js
    index 912c4c7..89f8522 100644
    window.wp = window.wp || {}; 
    33
    44(function($){
    55        var views = {},
    6                 instances = {};
     6                instances = {},
     7                media = wp.media;
    78
    89        // Create the `wp.mce` object if necessary.
    910        wp.mce = wp.mce || {};
    window.wp = window.wp || {}; 
    2526                                },
    2627
    2728                                toView: function( content ) {
    28                                         if ( ! this.pattern )
     29                                        if ( ! this.pattern ) {
    2930                                                return;
     31                                        }
    3032
    3133                                        this.pattern.lastIndex = 0;
    3234                                        var match = this.pattern.exec( content );
    3335
    34                                         if ( ! match )
     36                                        if ( ! match ) {
    3537                                                return;
     38                                        }
    3639
    3740                                        return {
    3841                                                index:   match.index,
    window.wp = window.wp || {}; 
    5659                                toView: function( content ) {
    5760                                        var match = wp.shortcode.next( this.shortcode, content );
    5861
    59                                         if ( ! match )
     62                                        if ( ! match ) {
    6063                                                return;
     64                                        }
    6165
    6266                                        return {
    6367                                                index:   match.index,
    window.wp = window.wp || {}; 
    98102                        var parent, remove, base, properties;
    99103
    100104                        // Fetch the parent view or the default options.
    101                         if ( options.extend )
     105                        if ( options.extend ) {
    102106                                parent = wp.mce.view.get( options.extend );
    103                         else if ( options.shortcode )
     107                        } else if ( options.shortcode ) {
    104108                                parent = wp.mce.view.defaults.shortcode;
    105                         else
     109                        } else {
    106110                                parent = wp.mce.view.defaults.pattern;
     111                        }
    107112
    108113                        // Extend the `options` object with the parent's properties.
    109114                        _.defaults( options, parent );
    window.wp = window.wp || {}; 
    118123                                        this.$el.parent().remove();
    119124
    120125                                        // Trigger the inherited `remove` method.
    121                                         if ( remove )
     126                                        if ( remove ) {
    122127                                                remove.apply( this, arguments );
     128                                        }
    123129
    124130                                        return this;
    125131                                }
    window.wp = window.wp || {}; 
    138144
    139145                        // If there's a `remove` method on the `base` view that wasn't
    140146                        // created by this method, inherit it.
    141                         if ( ! remove && ! base._mceview )
     147                        if ( ! remove && ! base._mceview ) {
    142148                                remove = base.prototype.remove;
     149                        }
    143150
    144151                        // Automatically create the new `Backbone.View` constructor.
    145152                        options.view = base.extend( properties, {
    window.wp = window.wp || {}; 
    168175                // every match.
    169176                //
    170177                // To render the views, call `wp.mce.view.render( scope )`.
     178                // TODO: needs unit tests!
    171179                toViews: function( content ) {
    172180                        var pieces = [ { content: content } ],
    173181                                current;
    window.wp = window.wp || {}; 
    190198                                        // and slicing the string as we go.
    191199                                        while ( remaining && (result = view.toView( remaining )) ) {
    192200                                                // Any text before the match becomes an unprocessed piece.
    193                                                 if ( result.index )
     201                                                if ( result.index ) {
    194202                                                        pieces.push({ content: remaining.substring( 0, result.index ) });
     203                                                }
    195204
    196205                                                // Add the processed piece for the match.
    197206                                                pieces.push({
    window.wp = window.wp || {}; 
    205214
    206215                                        // There are no additional matches. If any content remains,
    207216                                        // add it as an unprocessed piece.
    208                                         if ( remaining )
     217                                        if ( remaining ) {
    209218                                                pieces.push({ content: remaining });
     219                                        }
    210220                                });
    211221                        });
    212222
    window.wp = window.wp || {}; 
    217227                        var view = wp.mce.view.get( viewType ),
    218228                                instance, id;
    219229
    220                         if ( ! view )
     230                        if ( ! view ) {
    221231                                return '';
    222 
     232                        }
    223233                        // Create a new view instance.
    224234                        instance = new view.view( _.extend( options || {}, {
    225235                                viewType: viewType
    window.wp = window.wp || {}; 
    239249                                tag: 'span' === instance.tagName ? 'span' : 'div',
    240250
    241251                                attrs: {
    242                                         'class':           'wp-view-wrap wp-view-type-' + viewType,
     252                                        'class': 'wp-view-wrap wp-view-type-' + viewType,
    243253                                        'data-wp-view':    id,
    244254                                        'contenteditable': false
    245                                 }
     255                                },
     256
     257                                content: '\u00a0'
    246258                        });
    247259                },
    248260
    window.wp = window.wp || {}; 
    257269                                var wrapper = $(this),
    258270                                        view = wp.mce.view.instance( this );
    259271
    260                                 if ( ! view )
     272                                if ( ! view ) {
    261273                                        return;
     274                                }
    262275
    263276                                // Link the real wrapper to the view.
    264277                                view.$wrapper = wrapper;
    window.wp = window.wp || {}; 
    278291                // Scans an HTML `content` string and replaces any view instances with
    279292                // their respective text representations.
    280293                toText: function( content ) {
    281                         return content.replace( /<(?:div|span)[^>]+data-wp-view="([^"]+)"[^>]*>.*?<span[^>]+data-wp-view-end[^>]*><\/span><\/(?:div|span)>/g, function( match, id ) {
     294
     295                        return content.replace( /<(?:div|span)[^>]+data-wp-view="([^"]+)"[^>]*>.*?<span[^>]+data-wp-view-end[^>]*><\/span><\/(?:div|span)>/mg, function( match, id ) {
    282296                                var instance = instances[ id ],
    283297                                        view;
    284298
    285                                 if ( instance )
     299                                if ( instance ) {
    286300                                        view = wp.mce.view.get( instance.options.viewType );
    287 
     301                                }
    288302                                return instance && view ? view.text( instance ) : '';
    289303                        });
    290304                },
    window.wp = window.wp || {}; 
    293307                removeInternalAttrs: function( attrs ) {
    294308                        var result = {};
    295309                        _.each( attrs, function( value, attr ) {
    296                                 if ( -1 === attr.indexOf('data-mce') )
     310                                if ( -1 === attr.indexOf('data-mce') ) {
    297311                                        result[ attr ] = value;
     312                                }
    298313                        });
    299314                        return result;
    300315                },
    window.wp = window.wp || {}; 
    311326                instance: function( node ) {
    312327                        var id = $( node ).data('wp-view');
    313328
    314                         if ( id )
     329                        if ( id ) {
    315330                                return instances[ id ];
     331                        }
    316332                },
    317333
    318334                // ### Select a view.
    window.wp = window.wp || {}; 
    323339                        var $node = $(node);
    324340
    325341                        // Bail if node is already selected.
    326                         if ( $node.hasClass('selected') )
     342                        if ( $node.hasClass('selected') ) {
    327343                                return;
     344                        }
    328345
    329346                        $node.addClass('selected');
    330347                        $( node.firstChild ).trigger('select');
    window.wp = window.wp || {}; 
    338355                        var $node = $(node);
    339356
    340357                        // Bail if node is already selected.
    341                         if ( ! $node.hasClass('selected') )
     358                        if ( ! $node.hasClass('selected') ) {
    342359                                return;
     360                        }
    343361
    344362                        $node.removeClass('selected');
    345363                        $( node.firstChild ).trigger('deselect');
    346364                }
    347365        };
    348366
    349 }(jQuery));
    350  No newline at end of file
     367        wp.mce.view.add( 'gallery', {
     368                shortcode: 'gallery',
     369
     370                gallery: (function() {
     371                        var galleries = {};
     372
     373                        return {
     374                                attachments: function( shortcode, parent ) {
     375                                        var shortcodeString = shortcode.string(),
     376                                                result = galleries[ shortcodeString ],
     377                                                attrs, args, query, others;
     378
     379                                        delete galleries[ shortcodeString ];
     380
     381                                        if ( result ) {
     382                                                return result;
     383                                        }
     384
     385                                        attrs = shortcode.attrs.named;
     386                                        args  = _.pick( attrs, 'orderby', 'order' );
     387
     388                                        args.type    = 'image';
     389                                        args.perPage = -1;
     390
     391                                        // Map the `ids` param to the correct query args.
     392                                        if ( attrs.ids ) {
     393                                                args.post__in = attrs.ids.split(',');
     394                                                args.orderby  = 'post__in';
     395                                        } else if ( attrs.include ) {
     396                                                args.post__in = attrs.include.split(',');
     397                                        }
     398
     399                                        if ( attrs.exclude ) {
     400                                                args.post__not_in = attrs.exclude.split(',');
     401                                        }
     402
     403                                        if ( ! args.post__in ) {
     404                                                args.parent = attrs.id || parent;
     405                                        }
     406
     407                                        // Collect the attributes that were not included in `args`.
     408                                        others = {};
     409                                        _.filter( attrs, function( value, key ) {
     410                                                if ( _.isUndefined( args[ key ] ) ) {
     411                                                        others[ key ] = value;
     412                                                }
     413                                        });
     414
     415                                        query = media.query( args );
     416                                        query.gallery = new Backbone.Model( others );
     417                                        return query;
     418                                },
     419
     420                                shortcode: function( attachments ) {
     421                                        var props = attachments.props.toJSON(),
     422                                                attrs = _.pick( props, 'include', 'exclude', 'orderby', 'order' ),
     423                                                shortcode, clone;
     424
     425                                        if ( attachments.gallery ) {
     426                                                _.extend( attrs, attachments.gallery.toJSON() );
     427                                        }
     428
     429                                        attrs.ids = attachments.pluck('id');
     430
     431                                        // If the `ids` attribute is set and `orderby` attribute
     432                                        // is the default value, clear it for cleaner output.
     433                                        if ( attrs.ids && 'post__in' === attrs.orderby ) {
     434                                                delete attrs.orderby;
     435                                        }
     436
     437                                        shortcode = new wp.shortcode({
     438                                                tag:    'gallery',
     439                                                attrs:  attrs,
     440                                                type:   'single'
     441                                        });
     442
     443                                        // Use a cloned version of the gallery.
     444                                        clone = new wp.media.model.Attachments( attachments.models, {
     445                                                props: props
     446                                        });
     447                                        clone.gallery = attachments.gallery;
     448                                        galleries[ shortcode.string() ] = clone;
     449
     450                                        return shortcode;
     451                                }
     452                        };
     453                }()),
     454
     455                view: {
     456                        className: 'editor-gallery',
     457                        template:  media.template('editor-gallery'),
     458
     459                        // The fallback post ID to use as a parent for galleries that don't
     460                        // specify the `ids` or `include` parameters.
     461                        //
     462                        // Uses the hidden input on the edit posts page by default.
     463                        parent: $('#post_ID').val(),
     464
     465                        events: {
     466                                'click .remove': 'remove',
     467                                'click .edit':  'edit'
     468                        },
     469
     470                        initialize: function() {
     471                                this.update();
     472                        },
     473
     474                        update: function() {
     475                                var     view = wp.mce.view.get('gallery');
     476
     477                                this.attachments = view.gallery.attachments( this.options.shortcode, this.parent );
     478                                this.attachments.more().done( _.bind( this.render, this ) );
     479                        },
     480
     481                        render: function() {
     482                                var attrs = this.options.shortcode.attrs.named,
     483                                        options;
     484
     485                                if ( ! this.attachments.length ) {
     486                                        return;
     487                                }
     488
     489                                options = {
     490                                        attachments: this.attachments.toJSON(),
     491                                        columns: attrs.columns ? parseInt( attrs.columns, 10 ) : 3
     492                                };
     493
     494                                this.$el.html( this.template( options ) );
     495                        },
     496
     497                        edit: function() {
     498                                var selection;
     499
     500                                if ( ! wp.media.view || this.frame ) {
     501                                        return;
     502                                }
     503
     504                                selection = new wp.media.model.Selection( this.attachments.models, {
     505                                        props:    this.attachments.props.toJSON(),
     506                                        multiple: true
     507                                });
     508                                selection.gallery = this.attachments.gallery;
     509
     510                                this.frame = wp.media({
     511                                        frame:     'post',
     512                                        state:     'gallery-edit',
     513                                        editing:   true,
     514                                        multiple:  true,
     515                                        selection: selection
     516                                });
     517
     518                                // Create a single-use frame. If the frame is closed,
     519                                // then detach it from the DOM and remove the reference.
     520                                this.frame.on( 'close', function() {
     521                                        if ( this.frame ) {
     522                                                this.frame.detach();
     523                                        }
     524                                        delete this.frame;
     525                                }, this );
     526
     527                                // Update the `shortcode` and `attachments`.
     528                                this.frame.state('gallery-edit').on( 'update', function( selection ) {
     529                                        var     view = wp.mce.view.get('gallery');
     530
     531                                        this.options.shortcode = view.gallery.shortcode( selection );
     532                                        this.update();
     533                                }, this );
     534
     535                                this.frame.open();
     536                        }
     537                }
     538        });
     539}(jQuery));
  • src/wp-includes/js/tinymce/plugins/wpview/plugin.js

    diff --git src/wp-includes/js/tinymce/plugins/wpview/plugin.js src/wp-includes/js/tinymce/plugins/wpview/plugin.js
    index 0c56ecb..29e32f7 100644
     
    22/**
    33 * WordPress View plugin.
    44 */
    5 
    6 (function() {
    7         var VK = tinymce.VK,
     5tinymce.PluginManager.add( 'wpview', function( editor ) {
     6        var VK = tinymce.util.VK,
    87                TreeWalker = tinymce.dom.TreeWalker,
    98                selected;
    109
    11         tinymce.create('tinymce.plugins.wpView', {
    12                 init : function( editor ) {
    13                         var wpView = this;
     10        function getParentView( node ) {
     11                while ( node ) {
     12                        if ( isView( node ) ) {
     13                                return node;
     14                        }
     15
     16                        node = node.parentNode;
     17                }
     18        }
     19
     20        function isView( node ) {
     21                return (/(?:^|\s)wp-view-wrap(?:\s|$)/).test( node.className );
     22        }
     23
     24        function select( view ) {
     25                if ( view === selected ) {
     26                        return;
     27                }
     28
     29                deselect();
     30                selected = view;
     31                wp.mce.view.select( selected );
     32        }
     33
     34        function deselect() {
     35                if ( selected ) {
     36                        wp.mce.view.deselect( selected );
     37                }
     38
     39                selected = null;
     40        }
    1441
    15                         // Check if the `wp.mce` API exists.
    16                         if ( typeof wp === 'undefined' || ! wp.mce ) {
     42        // Check if the `wp.mce` API exists.
     43        if ( typeof wp === 'undefined' || ! wp.mce ) {
     44                return;
     45        }
     46
     47        editor.on( 'PreInit', function() {
     48                // Add elements so we can set `contenteditable` to false.
     49                // TODO: since we are serializing, is this needed?
     50                editor.schema.addValidElements('div[*],span[*]');
     51        });
     52
     53        // When the editor's content changes, scan the new content for
     54        // matching view patterns, and transform the matches into
     55        // view wrappers. Since the editor's DOM is outdated at this point,
     56        // we'll wait to render the views.
     57        editor.on( 'BeforeSetContent', function( e ) {
     58                if ( ! e.content ) {
     59                        return;
     60                }
     61
     62                e.content = wp.mce.view.toViews( e.content );
     63        });
     64
     65        // When the editor's content has been updated and the DOM has been
     66        // processed, render the views in the document.
     67        editor.on( 'SetContent', function() {
     68                wp.mce.view.render( editor.getDoc() );
     69        });
     70
     71        editor.on( 'init', function() {
     72                var selection = editor.selection;
     73                // When a view is selected, ensure content that is being pasted
     74                // or inserted is added to a text node (instead of the view).
     75                editor.on( 'BeforeSetContent', function() {
     76                        var walker, target,
     77                                view = getParentView( selection.getNode() );
     78
     79                        // If the selection is not within a view, bail.
     80                        if ( ! view ) {
    1781                                return;
    1882                        }
    1983
    20                         editor.on( 'PreInit', function() {
    21                                 // Add elements so we can set `contenteditable` to false.
    22                                 editor.schema.addValidElements('div[*],span[*]');
    23                         });
    24 
    25                         // When the editor's content changes, scan the new content for
    26                         // matching view patterns, and transform the matches into
    27                         // view wrappers. Since the editor's DOM is outdated at this point,
    28                         // we'll wait to render the views.
    29                         editor.on( 'BeforeSetContent', function( e ) {
    30                                 if ( ! e.content ) {
    31                                         return;
    32                                 }
    33 
    34                                 e.content = wp.mce.view.toViews( e.content );
    35                         });
    36 
    37                         // When the editor's content has been updated and the DOM has been
    38                         // processed, render the views in the document.
    39                         editor.on( 'SetContent', function() {
    40                                 wp.mce.view.render( editor.getDoc() );
    41                         });
    42 
    43                         editor.on( 'init', function() {
    44                                 var selection = editor.selection;
    45                                 // When a view is selected, ensure content that is being pasted
    46                                 // or inserted is added to a text node (instead of the view).
    47                                 editor.on( 'BeforeSetContent', function() {
    48                                         var walker, target,
    49                                                 view = wpView.getParentView( selection.getNode() );
    50 
    51                                         // If the selection is not within a view, bail.
    52                                         if ( ! view ) {
    53                                                 return;
    54                                         }
    55 
    56                                         // If there are no additional nodes or the next node is a
    57                                         // view, create a text node after the current view.
    58                                         if ( ! view.nextSibling || wpView.isView( view.nextSibling ) ) {
    59                                                 target = editor.getDoc().createTextNode('');
    60                                                 editor.dom.insertAfter( target, view );
    61 
    62                                         // Otherwise, find the next text node.
    63                                         } else {
    64                                                 walker = new TreeWalker( view.nextSibling, view.nextSibling );
    65                                                 target = walker.next();
    66                                         }
    67 
    68                                         // Select the `target` text node.
    69                                         selection.select( target );
    70                                         selection.collapse( true );
    71                                 });
    72 
    73                                 // When the selection's content changes, scan any new content
    74                                 // for matching views and immediately render them.
    75                                 //
    76                                 // Runs on paste and on inserting nodes/html.
    77                                 editor.on( 'SetContent', function( e ) {
    78                                         if ( ! e.context ) {
    79                                                 return;
    80                                         }
    81 
    82                                         var node = selection.getNode();
    83 
    84                                         if ( ! node.innerHTML ) {
    85                                                 return;
    86                                         }
    87 
    88                                         node.innerHTML = wp.mce.view.toViews( node.innerHTML );
    89                                         wp.mce.view.render( node );
    90                                 });
    91                         });
    92 
    93                         // When the editor's contents are being accessed as a string,
    94                         // transform any views back to their text representations.
    95                         editor.on( 'PostProcess', function( e ) {
    96                                 if ( ( ! e.get && ! e.save ) || ! e.content ) {
    97                                         return;
    98                                 }
    99 
    100                                 e.content = wp.mce.view.toText( e.content );
    101                         });
    102 
    103                         // Triggers when the selection is changed.
    104                         // Add the event handler to the top of the stack.
    105                         editor.on( 'NodeChange', function( e ) {
    106                                 var view = wpView.getParentView( e.element );
    107 
    108                                 // Update the selected view.
    109                                 if ( view ) {
    110                                         wpView.select( view );
    111 
    112                                         // Prevent the selection from propagating to other plugins.
    113                                         return false;
    114 
    115                                 // If we've clicked off of the selected view, deselect it.
    116                                 } else {
    117                                         wpView.deselect();
    118                                 }
    119                         });
    120 
    121                         editor.on( 'keydown', function( event ) {
    122                                 var keyCode = event.keyCode,
    123                                         view, instance;
    124 
    125                                 // If a view isn't selected, let the event go on its merry way.
    126                                 if ( ! selected ) {
    127                                         return;
    128                                 }
    129 
    130                                 // If the caret is not within the selected view, deselect the
    131                                 // view and bail.
    132                                 view = wpView.getParentView( editor.selection.getNode() );
    133                                 if ( view !== selected ) {
    134                                         wpView.deselect();
    135                                         return;
    136                                 }
    137 
    138                                 // If delete or backspace is pressed, delete the view.
    139                                 if ( keyCode === VK.DELETE || keyCode === VK.BACKSPACE ) {
    140                                         if ( (instance = wp.mce.view.instance( selected )) ) {
    141                                                 instance.remove();
    142                                                 wpView.deselect();
    143                                         }
    144                                 }
    145 
    146                                 // Let keypresses that involve the command or control keys through.
    147                                 // Also, let any of the F# keys through.
    148                                 if ( event.metaKey || event.ctrlKey || ( keyCode >= 112 && keyCode <= 123 ) ) {
    149                                         return;
    150                                 }
    151 
    152                                 event.preventDefault();
    153                         });
    154                 },
    155 
    156                 getParentView : function( node ) {
    157                         while ( node ) {
    158                                 if ( this.isView( node ) ) {
    159                                         return node;
    160                                 }
    161 
    162                                 node = node.parentNode;
    163                         }
    164                 },
     84                        // If there are no additional nodes or the next node is a
     85                        // view, create a text node after the current view.
     86                        if ( ! view.nextSibling || isView( view.nextSibling ) ) {
     87                                target = editor.getDoc().createTextNode('');
     88                                editor.dom.insertAfter( target, view );
    16589
    166                 isView : function( node ) {
    167                         return (/(?:^|\s)wp-view-wrap(?:\s|$)/).test( node.className );
    168                 },
     90                        // Otherwise, find the next text node.
     91                        } else {
     92                                walker = new TreeWalker( view.nextSibling, view.nextSibling );
     93                                target = walker.next();
     94                        }
    16995
    170                 select : function( view ) {
    171                         if ( view === selected ) {
     96                        // Select the `target` text node.
     97                        selection.select( target );
     98                        selection.collapse( true );
     99                });
     100
     101                // When the selection's content changes, scan any new content
     102                // for matching views and immediately render them.
     103                //
     104                // Runs on paste and on inserting nodes/html.
     105                editor.on( 'SetContent', function( e ) {
     106                        if ( ! e.context ) {
    172107                                return;
    173108                        }
    174109
    175                         this.deselect();
    176                         selected = view;
    177                         wp.mce.view.select( selected );
    178                 },
     110                        var node = selection.getNode();
    179111
    180                 deselect : function() {
    181                         if ( selected ) {
    182                                 wp.mce.view.deselect( selected );
     112                        if ( ! node.innerHTML ) {
     113                                return;
    183114                        }
    184115
    185                         selected = null;
     116                        node.innerHTML = wp.mce.view.toViews( node.innerHTML );
     117                        wp.mce.view.render( node );
     118                });
     119        });
     120
     121        // When the editor's contents are being accessed as a string,
     122        // transform any views back to their text representations.
     123        editor.on( 'PostProcess', function( e ) {
     124                if ( ( ! e.get && ! e.save ) || ! e.content ) {
     125                        return;
     126                }
     127
     128                e.content = wp.mce.view.toText( e.content );
     129        });
     130
     131        // Triggers when the selection is changed.
     132        // Add the event handler to the top of the stack.
     133        editor.on( 'NodeChange', function( e ) {
     134                var view = getParentView( e.element );
     135
     136                // Update the selected view.
     137                if ( view ) {
     138                        select( view );
     139
     140                        // Prevent the selection from propagating to other plugins.
     141                        return false;
     142
     143                // If we've clicked off of the selected view, deselect it.
     144                } else {
     145                        deselect();
    186146                }
    187147        });
    188148
    189         // Register plugin
    190         tinymce.PluginManager.add( 'wpview', tinymce.plugins.wpView );
    191 })();
     149        editor.on( 'keydown', function( event ) {
     150                var keyCode = event.keyCode,
     151                        view, instance;
     152
     153                // If a view isn't selected, let the event go on its merry way.
     154                if ( ! selected ) {
     155                        return;
     156                }
     157
     158                // If the caret is not within the selected view, deselect the
     159                // view and bail.
     160                view = getParentView( editor.selection.getNode() );
     161                if ( view !== selected ) {
     162                        deselect();
     163                        return;
     164                }
     165
     166                // If delete or backspace is pressed, delete the view.
     167                if ( keyCode === VK.DELETE || keyCode === VK.BACKSPACE ) {
     168                        if ( (instance = wp.mce.view.instance( selected )) ) {
     169                                instance.remove();
     170                                deselect();
     171                        }
     172                }
     173
     174                // Let keypresses that involve the command or control keys through.
     175                // Also, let any of the F# keys through.
     176                if ( event.metaKey || event.ctrlKey || ( keyCode >= 112 && keyCode <= 123 ) ) {
     177                        return;
     178                }
     179
     180                event.preventDefault();
     181        });
     182});
  • src/wp-includes/js/tinymce/skins/wordpress/wp-content.css

    diff --git src/wp-includes/js/tinymce/skins/wordpress/wp-content.css src/wp-includes/js/tinymce/skins/wordpress/wp-content.css
    index 92e1f35..652d04b 100644
    img::selection { 
    127127        border-style: solid;
    128128}
    129129
     130/**
     131 * Gallery preview
     132 */
     133.wp-view-type-gallery {
     134    position: relative;
     135    padding: 16px 0;
     136    margin-bottom: 16px;
     137        cursor: pointer;
     138}
     139
     140 .wp-view-type-gallery:after {
     141    content: '';
     142    display: block;
     143    height: 0;
     144    clear: both;
     145    visibility: hidden;
     146}
     147
     148 .wp-view-type-gallery.selected {
     149        background-color: #efefef;
     150}
     151
     152
     153.wp-view-type-gallery .toolbar {
     154    position: absolute;
     155    top: 0;
     156    left: 0;
     157    background-color: #333;
     158    color: white;
     159    padding: 4px;
     160        display: none;
     161}
     162
     163.wp-view-type-gallery.selected .toolbar {
     164        display: block;
     165}
     166
     167.wp-view-type-gallery .toolbar span {
     168        cursor: pointer;
     169}
     170
     171.gallery img[data-mce-selected]:focus {
     172        outline: none;
     173}
     174
     175.gallery a {
     176        cursor: default;
     177}
     178
     179.gallery {
     180        margin: auto;
     181    line-height: 1;
     182}
     183
     184.gallery .gallery-item {
     185        float: left;
     186        margin: 10px 0 0 0;
     187        text-align: center;
     188}
     189
     190.gallery .gallery-caption,
     191.gallery .gallery-icon {
     192        margin: 0;
     193}
     194
     195.gallery-columns-1 .gallery-item {
     196        width: 100%;
     197}
     198
     199.gallery-columns-2 .gallery-item {
     200        width: 50%;
     201}
     202
     203.gallery-columns-3 .gallery-item {
     204        width: 33.333%;
     205}
     206
     207.gallery-columns-4 .gallery-item {
     208        width: 25%;
     209}
     210
     211.gallery-columns-5 .gallery-item {
     212        width: 20%;
     213}
     214
     215.gallery-columns-6 .gallery-item {
     216        width: 16%;
     217}
     218
     219.gallery-columns-7 .gallery-item {
     220        width: 14%;
     221}
     222
     223.gallery-columns-8 .gallery-item {
     224        width: 12%;
     225}
     226
     227.gallery-columns-9 .gallery-item {
     228        width: 11%;
     229}
     230
     231.gallery img {
     232        border: 2px solid #cfcfcf;
     233}
     234
    130235img.wp-oembed {
    131236        border: 1px dashed #888;
    132237        background: #f7f5f2 url("images/embedded.png") no-repeat scroll center center;
  • src/wp-includes/media-template.php

    diff --git src/wp-includes/media-template.php src/wp-includes/media-template.php
    index 93bf672..68e305d 100644
    function wp_print_media_templates() { 
    600600        </script>
    601601        <?php
    602602
     603                //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
     604                // do we want to deal with the difference between display and edit context at all? (e.g. wptexturize() being applied to the caption.
     605        ?>
     606
     607        <script type="text/html" id="tmpl-editor-gallery">
     608                <div class="toolbar"><span class="edit"><?php _e( 'edit' ); ?></span> <span class="remove"><?php _e( 'remove' ); ?></span></div>
     609                <div class="gallery gallery-columns-{{{ data.columns }}}">
     610                        <# _.each( data.attachments, function( attachment, index ) { #>
     611                                <dl class="gallery-item">
     612                                        <dt class="gallery-icon">
     613                                                <?php // TODO: need to figure out the best way to make sure that we have thumbnails ?>
     614                                                <img src="{{{ attachment.sizes.thumbnail.url }}}" />
     615                                        </dt>
     616                                        <dd class="wp-caption-text gallery-caption">
     617                                                {{ attachment.caption }}
     618                                        </dd>
     619                                </dl>
     620                                <?php // this is kind silly, but copied from the gallery shortcode. Maybe it should be removed ?>
     621                                <# if ( index % data.columns === data.columns - 1 ) { #>
     622                                        <br style="clear: both;">
     623                                <# } #>
     624
     625                        <# } ); #>
     626                </div>
     627        </script>
     628        <?php
     629
    603630        /**
    604631         * Prints the media manager custom media templates.
    605632         *