WordPress.org

Make WordPress Core

Ticket #24409: 24409-04.patch

File 24409-04.patch, 13.8 KB (added by gcorne, 5 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 bcbc631..c469e3d 100644
    final class _WP_Editors { 
    335335                                        self::$first_init['external_plugins'] = json_encode( $mce_external_plugins );
    336336                                }
    337337
    338                                 // WordPress default stylesheet
    339                                 $mce_css = array( self::$baseurl . '/skins/wordpress/wp-content.css' );
     338                                $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
     339
     340
     341                                $version = 'ver=' . $GLOBALS['wp_version'];
     342                                $dashicons = includes_url( "css/dashicons$suffix.css?$version" );
     343
     344                                // WordPress default stylesheet and dashicons
     345                                $mce_css = array( $dashicons, self::$baseurl . '/skins/wordpress/wp-content.css' );
    340346
    341347                                // load editor_style.css if the current theme supports it
    342348                                if ( ! empty( $GLOBALS['editor_styles'] ) && is_array( $GLOBALS['editor_styles'] ) ) {
  • src/wp-includes/js/tinymce/plugins/wpeditimage/plugin.js

    diff --git src/wp-includes/js/tinymce/plugins/wpeditimage/plugin.js src/wp-includes/js/tinymce/plugins/wpeditimage/plugin.js
    index 6681eda..08f91b4 100644
     
    11/* global tinymce */
    22tinymce.PluginManager.add( 'wpeditimage', function( editor ) {
     3        var selected = false;
     4
    35        function parseShortcode( content ) {
    46                return content.replace( /(?:<p>)?\[(?:wp_)?caption([^\]]+)\]([\s\S]+?)\[\/(?:wp_)?caption\](?:<\/p>)?/g, function( a, b, c ) {
    57                        var id, cls, w, cap, img, width,
    tinymce.PluginManager.add( 'wpeditimage', function( editor ) { 
    215217
    216218                editor.dom.setAttrib( node, 'data-wp-replace-id', '' );
    217219
     220                editor.nodeChanged();
     221
    218222                if ( node.nodeName === 'IMG' ) {
    219223                        editor.selection.select( node );
    220224                } else {
    221225                        editor.selection.select( editor.dom.select( 'img', node )[0] );
    222226                }
    223                 editor.nodeChanged();
    224227        }
    225228
    226229        function createImageAndLink( imageData, mode ) {
    tinymce.PluginManager.add( 'wpeditimage', function( editor ) { 
    264267                }
    265268        }
    266269
     270        function editImage( img ) {
     271                var frame, callback;
     272
     273                frame = wp.media({
     274                        frame: 'image',
     275                        state: 'image-details',
     276                        metadata: extractImageData( img )
     277                } );
     278
     279                callback = function( imageData ) {
     280                        updateImage( img, imageData );
     281                        editor.focus();
     282                };
     283
     284                frame.state('image-details').on( 'update', callback );
     285                frame.state('replace-image').on( 'replace', callback );
     286                frame.on( 'close', function() {
     287                        editor.focus();
     288                        editor.selection.select( img );
     289                        editor.nodeChanged();
     290                });
     291
     292                frame.open();
     293
     294        }
     295
     296        function removeImage( node ) {
     297                var wrap;
     298
     299                if ( node.nodeName === 'DIV' && editor.dom.hasClass( node, 'mceTemp' ) ) {
     300                        wrap = node;
     301                } else if ( node.nodeName === 'IMG' || node.nodeName === 'DT' || node.nodeName === 'A' ) {
     302                        wrap = editor.dom.getParent( node, 'div.mceTemp' );
     303                }
     304
     305                if ( wrap ) {
     306                        if ( wrap.nextSibling ) {
     307                                editor.selection.select( wrap.nextSibling );
     308                        } else if ( wrap.previousSibling ) {
     309                                editor.selection.select( wrap.previousSibling );
     310                        } else {
     311                                editor.selection.select( wrap.parentNode );
     312                        }
     313
     314                        editor.selection.collapse( true );
     315                        editor.nodeChanged();
     316                        editor.dom.remove( wrap );
     317                } else {
     318                        editor.dom.remove( node );
     319                }
     320
     321                selected = false;
     322
     323        }
     324
     325        function addToolbar( img ) {
     326                var position, toolbarHtml, toolbar;
     327
     328                removeToolbar();
     329
     330                // Don't attempt to edit placeholders
     331                if ( editor.dom.hasClass( img, 'mceItem' ) || '1' === editor.dom.getAttrib( img, 'data-mce-placeholder' ) ) {
     332                        return;
     333                }
     334
     335                position = editor.dom.getPos( img, editor.getBody() );
     336
     337                toolbarHtml = '<div class="wrapper"><div class="dashicons dashicons-format-image edit"></div> <div class="dashicons dashicons-no-alt remove"></div></div>';
     338
     339                toolbar = editor.dom.create( 'div', {
     340                        'id': 'wp-image-toolbar',
     341                        'data-mce-bogus': '1',
     342                        'contenteditable': false
     343                }, toolbarHtml );
     344
     345
     346                editor.getBody().appendChild( toolbar );
     347
     348                editor.dom.setStyles( toolbar, {
     349                        position: 'absolute',
     350                        top: position.y,
     351                        left: position.x,
     352                        width: img.width
     353                } );
     354        }
     355
     356        function removeToolbar() {
     357                var toolbar = editor.dom.get( 'wp-image-toolbar' );
     358
     359                if ( toolbar ) {
     360                        editor.dom.remove( toolbar );
     361                }
     362        }
     363
    267364        editor.on( 'init', function() {
    268365                var dom = editor.dom;
    269366
    tinymce.PluginManager.add( 'wpeditimage', function( editor ) { 
    299396                        }
    300397                });
    301398
    302                 editor.on( 'wpImageFormSubmit', function( e ) {
    303                         var data = e.imgData.data,
    304                                 imgNode = e.imgData.node,
    305                                 caption = e.imgData.caption,
    306                                 captionId = '',
    307                                 captionAlign = '',
    308                                 captionWidth = '',
    309                                 wrap, parent, node, html, imgId;
    310 
    311                         // Temp image id so we can find the node later
    312                         data.id = '__wp-temp-img-id';
    313                         // Cancel the original callback
    314                         e.imgData.cancel = true;
    315 
    316                         if ( ! data.style ) {
    317                                 data.style = null;
    318                         }
    319 
    320                         if ( ! data.src ) {
    321                                 // Delete the image and the caption
    322                                 if ( imgNode ) {
    323                                         if ( wrap = dom.getParent( imgNode, 'div.mceTemp' ) ) {
    324                                                 dom.remove( wrap );
    325                                         } else if ( imgNode.parentNode.nodeName === 'A' ) {
    326                                                 dom.remove( imgNode.parentNode );
    327                                         } else {
    328                                                 dom.remove( imgNode );
    329                                         }
    330 
    331                                         editor.nodeChanged();
    332                                 }
    333                                 return;
    334                         }
    335 
    336                         if ( caption ) {
    337                                 caption = caption.replace( /\r\n|\r/g, '\n' ).replace( /<\/?[a-zA-Z0-9]+( [^<>]+)?>/g, function( a ) {
    338                                         // No line breaks inside HTML tags
    339                                         return a.replace( /[\r\n\t]+/, ' ' );
    340                                 });
    341 
    342                                 // Convert remaining line breaks to <br>
    343                                 caption = caption.replace( /(<br[^>]*>)\s*\n\s*/g, '$1' ).replace( /\s*\n\s*/g, '<br />' );
    344                         }
    345 
    346                         if ( ! imgNode ) {
    347                                 // New image inserted
    348                                 html = dom.createHTML( 'img', data );
    349 
    350                                 if ( caption ) {
    351                                         node = editor.selection.getNode();
    352 
    353                                         if ( data.width ) {
    354                                                 captionWidth = parseInt( data.width, 10 ) + 10;
    355                                                 captionWidth = ' style="width: '+ captionWidth +'px"';
    356                                         }
    357 
    358                                         html = '<dl class="wp-caption alignnone"' + captionWidth + '>' +
    359                                                 '<dt class="wp-caption-dt">'+ html +'</dt><dd class="wp-caption-dd">'+ caption +'</dd></dl>';
    360 
    361                                         if ( node.nodeName === 'P' ) {
    362                                                 parent = node;
    363                                         } else {
    364                                                 parent = dom.getParent( node, 'p' );
    365                                         }
    366 
    367                                         if ( parent && parent.nodeName === 'P' ) {
    368                                                 wrap = dom.create( 'div', { 'class': 'mceTemp', 'draggable': 'true' }, html );
    369                                                 dom.insertAfter( wrap, parent );
    370                                                 editor.selection.select( wrap );
    371                                                 editor.nodeChanged();
    372 
    373                                                 if ( dom.isEmpty( parent ) ) {
    374                                                         dom.remove( parent );
    375                                                 }
    376                                         } else {
    377                                                 editor.selection.setContent( '<div class="mceTemp" draggable="true">' + html + '</div>' );
    378                                         }
    379                                 } else {
    380                                         editor.selection.setContent( html );
    381                                 }
    382                         } else {
    383                                 // Edit existing image
    384 
    385                                 // Store the original image id if any
    386                                 imgId = imgNode.id || null;
    387                                 // Update the image node
    388                                 dom.setAttribs( imgNode, data );
    389                                 wrap = dom.getParent( imgNode, 'dl.wp-caption' );
    390 
    391                                 if ( caption ) {
    392                                         if ( wrap ) {
    393                                                 if ( parent = dom.select( 'dd.wp-caption-dd', wrap )[0] ) {
    394                                                         parent.innerHTML = caption;
    395                                                 }
    396                                         } else {
    397                                                 if ( imgNode.className ) {
    398                                                         captionId = imgNode.className.match( /wp-image-([0-9]+)/ );
    399                                                         captionAlign = imgNode.className.match( /align(left|right|center|none)/ );
    400                                                 }
    401 
    402                                                 if ( captionAlign ) {
    403                                                         captionAlign = captionAlign[0];
    404                                                         imgNode.className = imgNode.className.replace( /align(left|right|center|none)/g, '' );
    405                                                 } else {
    406                                                         captionAlign = 'alignnone';
    407                                                 }
    408 
    409                                                 captionAlign = ' class="wp-caption ' + captionAlign + '"';
    410 
    411                                                 if ( captionId ) {
    412                                                         captionId = ' id="attachment_' + captionId[1] + '"';
    413                                                 }
    414 
    415                                                 captionWidth = data.width || imgNode.clientWidth;
    416 
    417                                                 if ( captionWidth ) {
    418                                                         captionWidth = parseInt( captionWidth, 10 ) + 10;
    419                                                         captionWidth = ' style="width: '+ captionWidth +'px"';
    420                                                 }
    421 
    422                                                 if ( imgNode.parentNode && imgNode.parentNode.nodeName === 'A' ) {
    423                                                         html = dom.getOuterHTML( imgNode.parentNode );
    424                                                         node = imgNode.parentNode;
    425                                                 } else {
    426                                                         html = dom.getOuterHTML( imgNode );
    427                                                         node = imgNode;
    428                                                 }
    429 
    430                                                 html = '<dl ' + captionId + captionAlign + captionWidth + '>' +
    431                                                         '<dt class="wp-caption-dt">'+ html +'</dt><dd class="wp-caption-dd">'+ caption +'</dd></dl>';
    432 
    433                                                 if ( parent = dom.getParent( imgNode, 'p' ) ) {
    434                                                         wrap = dom.create( 'div', { 'class': 'mceTemp', 'draggable': 'true' }, html );
    435                                                         dom.insertAfter( wrap, parent );
    436                                                         editor.selection.select( wrap );
    437                                                         editor.nodeChanged();
    438 
    439                                                         // Delete the old image node
    440                                                         dom.remove( node );
    441 
    442                                                         if ( dom.isEmpty( parent ) ) {
    443                                                                 dom.remove( parent );
    444                                                         }
    445                                                 } else {
    446                                                         editor.selection.setContent( '<div class="mceTemp" draggable="true">' + html + '</div>' );
    447                                                 }
    448                                         }
    449                                 } else {
    450                                         if ( wrap ) {
    451                                                 // Remove the caption wrapper and place the image in new paragraph
    452                                                 if ( imgNode.parentNode.nodeName === 'A' ) {
    453                                                         html = dom.getOuterHTML( imgNode.parentNode );
    454                                                 } else {
    455                                                         html = dom.getOuterHTML( imgNode );
    456                                                 }
    457 
    458                                                 parent = dom.create( 'p', {}, html );
    459                                                 dom.insertAfter( parent, wrap.parentNode );
    460                                                 editor.selection.select( parent );
    461                                                 editor.nodeChanged();
    462                                                 dom.remove( wrap.parentNode );
    463                                         }
    464                                 }
    465                         }
    466 
    467                         imgNode = dom.get('__wp-temp-img-id');
    468                         dom.setAttrib( imgNode, 'id', imgId );
    469                         e.imgData.node = imgNode;
    470                 });
    471 
    472                 editor.on( 'wpLoadImageData', function( e ) {
    473                         var parent,
    474                                 data = e.imgData.data,
    475                                 imgNode = e.imgData.node;
    476 
    477                         if ( parent = dom.getParent( imgNode, 'dl.wp-caption' ) ) {
    478                                 parent = dom.select( 'dd.wp-caption-dd', parent )[0];
    479 
    480                                 if ( parent ) {
    481                                         data.caption = editor.serializer.serialize( parent )
    482                                                 .replace( /<br[^>]*>/g, '$&\n' ).replace( /^<p>/, '' ).replace( /<\/p>$/, '' );
    483                                 }
    484                         }
    485                 });
    486 
    487399                // Prevent dragging images out of the caption elements
    488400                dom.bind( editor.getDoc(), 'dragstart', function( event ) {
    489401                        var node = editor.selection.getNode();
    tinymce.PluginManager.add( 'wpeditimage', function( editor ) { 
    498410        var parent, width,
    499411                        node = event.target;
    500412
    501                 if ( node.nodeName === 'IMG' && ( parent = editor.dom.getParent( node, '.wp-caption' ) ) ) {
    502                         width = event.width || editor.dom.getAttrib( node, 'width' );
     413                if ( node.nodeName === 'IMG' ) {
     414                        if ( parent = editor.dom.getParent( node, '.wp-caption' ) ) {
     415                                width = event.width || editor.dom.getAttrib( node, 'width' );
    503416
    504                         if ( width ) {
    505                                 width = parseInt( width, 10 ) + 10;
    506                                 editor.dom.setStyle( parent, 'width', width + 'px' );
     417                                if ( width ) {
     418                                        width = parseInt( width, 10 ) + 10;
     419                                        editor.dom.setStyle( parent, 'width', width + 'px' );
     420                                }
    507421                        }
     422                        // refresh toolbar
     423                        addToolbar( node );
    508424                }
    509425    });
    510426
    tinymce.PluginManager.add( 'wpeditimage', function( editor ) { 
    602518
    603519                        if ( wrap ) {
    604520                                dom.events.cancel(e);
    605 
    606                                 if ( wrap.nextSibling ) {
    607                                         selection.select( wrap.nextSibling );
    608                                 } else if ( wrap.previousSibling ) {
    609                                         selection.select( wrap.previousSibling );
    610                                 } else {
    611                                         selection.select( wrap.parentNode );
    612                                 }
    613 
    614                                 selection.collapse( true );
    615                                 editor.nodeChanged();
    616                                 dom.remove( wrap );
    617                                 wrap = null;
     521                                removeImage( node );
    618522                                return false;
    619523                        }
    620524                }
    621525        });
    622526
    623         editor.on( 'mousedown', function( e ) {
    624                 var imageNode, frame, callback;
    625                 if ( e.target.nodeName === 'IMG' && editor.selection.getNode() === e.target ) {
    626                         // Don't trigger on right-click
    627                         if ( e.button !== 2 ) {
     527        editor.on( 'click', function( event ) {
     528                var node = event.target,
     529                        isToolbar;
    628530
    629                                 // Don't attempt to edit placeholders
    630                                 if ( editor.dom.hasClass( e.target, 'mceItem' ) || '1' === editor.dom.getAttrib( e.target, 'data-mce-placeholder' ) ) {
    631                                         return;
    632                                 }
    633 
    634                                 imageNode = e.target;
     531                // Don't trigger on right-click
     532                if ( event.button && event.button > 1 ) {
     533                        return;
     534                }
    635535
    636                                 frame = wp.media({
    637                                         frame: 'image',
    638                                         state: 'image-details',
    639                                         metadata: extractImageData( imageNode )
    640                                 } );
     536                if ( node.nodeName === 'IMG' ) {
    641537
    642                                 callback = function( imageData ) {
    643                                         updateImage( imageNode, imageData );
    644                                         editor.focus();
    645                                 };
     538                        // Don't attempt to edit placeholders
     539                        if ( editor.dom.hasClass( node, 'mceItem' ) || '1' === editor.dom.getAttrib( node, 'data-mce-placeholder' ) ) {
     540                                return;
     541                        }
    646542
    647                                 frame.state('image-details').on( 'update', callback );
    648                                 frame.state('replace-image').on( 'replace', callback );
     543                        if ( selected === node  ) {
     544                                editImage( selected );
     545                        } else {
     546                                selected = node;
     547                                addToolbar( node );
     548                        }
     549                } else {
     550                        isToolbar = editor.dom.getParent( node, '#wp-image-toolbar' ) ? true : false;
    649551
    650                                 frame.open();
     552                        if ( selected && isToolbar ) {
     553                                if ( editor.dom.hasClass( node, 'remove' ) ) {
     554                                        removeImage( selected );
     555                                        removeToolbar();
     556                                } else {
     557                                        editImage( selected );
     558                                }
     559                        } else {
     560                                removeToolbar();
     561                                selected = false;
    651562                        }
    652563                }
    653564        } );
  • 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..f086a38 100644
    img::selection { 
    117117        cursor: pointer;
    118118}
    119119
     120#wp-image-toolbar {
     121        height: 32px;
     122        background-color: rgba( 0, 0, 0, 0.4);
     123}
     124
     125#wp-image-toolbar .wrapper {
     126        position: relative;
     127
     128}
     129
     130#wp-image-toolbar .dashicons {
     131        position: absolute;
     132        color: white;
     133        width: 16px;
     134        height: 16px;
     135        cursor: pointer;
     136}
     137
     138#wp-image-toolbar div.dashicons-no-alt {
     139        top: 4px;
     140        right: 10px;
     141}
     142
     143#wp-image-toolbar div.dashicons-format-image {
     144        top: 4px;
     145        left: 10px;
     146}
     147
    120148.mce-content-body img.wp-gallery:hover {
    121149        background-color: #ededed;
    122150        border-style: solid;