WordPress.org

Make WordPress Core

Ticket #24409: 24409-01.patch

File 24409-01.patch, 19.4 KB (added by gcorne, 5 years ago)
  • src/wp-includes/js/media-models.js

    diff --git src/wp-includes/js/media-models.js src/wp-includes/js/media-models.js
    index 569beec..e51e4d7 100644
     
    22window.wp = window.wp || {};
    33
    44(function($){
    5         var Attachment, Attachments, Query, compare, l10n, media;
     5        var Attachment, Attachments, Query, PostImage, compare, l10n, media;
    66
    77        /**
    88         * wp.media( attributes )
    window.wp = window.wp || {}; 
    3030                        frame = new MediaFrame.Select( attributes );
    3131                } else if ( 'post' === attributes.frame && MediaFrame.Post ) {
    3232                        frame = new MediaFrame.Post( attributes );
     33                } else if ( 'image' === attributes.frame && MediaFrame.ImageDetails ) {
     34                        frame = new MediaFrame.ImageDetails( attributes );
    3335                }
    3436
    3537                delete attributes.frame;
    window.wp = window.wp || {}; 
    326328        });
    327329
    328330        /**
     331         * wp.media.model.Attachment
     332         *
     333         * @constructor
     334         * @augments Backbone.Model
     335         *
     336         **/
     337        PostImage = media.model.PostImage = Backbone.Model.extend({
     338
     339                initialize: function( attributes ) {
     340                        this.attachment = false;
     341
     342                        if ( attributes.attachment_id ) {
     343                                this.attachment = media.model.Attachment.get( attributes.attachment_id );
     344                                this.dfd = this.attachment.fetch();
     345                                this.listenTo( this.attachment, 'sync', this.setLinkTypeFromUrl );
     346                        }
     347
     348                        // keep url in sync with changes to the type of link
     349                        this.on( 'change:link', this.updateLinkUrl, this );
     350                        this.on( 'change:size', this.updateSize, this );
     351
     352                },
     353
     354                setLinkTypeFromUrl: function() {
     355                        var linkUrl = this.get( 'linkUrl' ),
     356                                type;
     357
     358                        if ( ! linkUrl ) {
     359                                this.set( 'link', 'none' );
     360                                return;
     361                        }
     362
     363                        // default to custom if there is a linkUrl
     364                        type = 'custom';
     365
     366                        if ( this.attachment ) {
     367                                if ( this.attachment.get( 'url' ) === linkUrl ) {
     368                                        type = 'file';
     369                                } else if ( this.attachment.get( 'link' ) === linkUrl ) {
     370                                        type = 'post';
     371                                }
     372                        } else {
     373                                if ( this.get( 'url' ) === linkUrl ) {
     374                                        type = 'file';
     375                                }
     376                        }
     377
     378                        this.set( 'link', type );
     379
     380                },
     381
     382
     383                updateLinkUrl: function() {
     384                        var link = this.get( 'link' ),
     385                                url;
     386
     387                        switch( link ) {
     388                                case 'file':
     389                                        if ( this.attachment ) {
     390                                                url = this.attachment.get( 'url' );
     391                                        } else {
     392                                                url = this.get( 'url' );
     393                                        }
     394                                        this.set( 'linkUrl', url );
     395                                        break;
     396                                case 'post':
     397                                        this.set( 'linkUrl', this.attachment.get( 'link' ) );
     398                                        break;
     399                                case 'none':
     400                                        this.set( 'linkUrl', '' );
     401                                        break;
     402
     403                        }
     404
     405                },
     406
     407                updateSize: function() {
     408                        var size;
     409
     410                        if ( ! this.attachment ) {
     411                                return;
     412                        }
     413
     414                        size = this.attachment.get( 'sizes' )[ this.get( 'size' ) ];
     415                        this.set( 'url', size.url );
     416                        this.set( 'width', size.width );
     417                        this.set( 'height', size.height );
     418
     419                }
     420
     421
     422        });
     423
     424        /**
    329425         * wp.media.model.Attachments
    330426         *
    331427         * @constructor
    window.wp = window.wp || {}; 
    11111207                window.wp = null;
    11121208        });
    11131209
    1114 }(jQuery));
    1115  No newline at end of file
     1210}(jQuery));
  • src/wp-includes/js/media-views.js

    diff --git src/wp-includes/js/media-views.js src/wp-includes/js/media-views.js
    index 07b49c9..fea8114 100644
     
    980980                }
    981981        });
    982982
     983
     984        media.controller.ImageDetails = media.controller.State.extend({
     985
     986                defaults: _.defaults({
     987                        id: 'image-details',
     988                        filterable: 'uploaded',
     989                        multiple: false,
     990                        toolbar: 'image-details',
     991                        title: l10n.imageDetailsTitle,
     992                        content: 'image-details',
     993                        menu: 'image-details',
     994                        router: false,
     995                        attachment: false,
     996                        priority: 60,
     997                        editing: false,
     998                        syncSelection: false
     999                }, media.controller.Library.prototype.defaults ),
     1000
     1001                // probably should have some notion of an embed model
     1002                initialize: function( options ) {
     1003                        var attachment = false;
     1004                        this.props = new media.model.PostImage( options.metadata );
     1005
     1006                        media.controller.State.prototype.initialize.apply( this, arguments );
     1007                },
     1008
     1009                activate: function() {
     1010                        media.controller.State.prototype.activate.apply( this, arguments );
     1011                },
     1012
     1013                deactivate: function() {
     1014                        /**
     1015                         * call 'deactivate' directly on the parent class
     1016                         */
     1017                        media.controller.State.prototype.deactivate.apply( this, arguments );
     1018                }
     1019
     1020        });
     1021
     1022        /**
     1023         * wp.media.controller.ReplaceImage
     1024         *
     1025         * Replace a selected single image
     1026         *
     1027         **/
     1028        media.controller.ReplaceImage = media.controller.Library.extend({
     1029
     1030
     1031
     1032        });
     1033
    9831034        /**
    9841035         * wp.media.controller.Embed
    9851036         *
     
    19231974                                        }
    19241975                                }
    19251976                        }) );
     1977                },
     1978
     1979        });
     1980
     1981        media.view.MediaFrame.ImageDetails = media.view.MediaFrame.Select.extend({
     1982                defaults: {
     1983                        id:      'image',
     1984                        url:     '',
     1985                        menu:    'image-details',
     1986                        content: 'image-details',
     1987                        toolbar: 'image-details',
     1988                        type:    'link',
     1989                        title:    l10n.imageDetailsTitle,
     1990                        priority: 120
     1991                },
     1992
     1993                bindHandlers: function() {
     1994                        media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
     1995                        this.on( 'menu:create:image-details', this.createMenu, this );
     1996                        this.on( 'content:render:image-details', this.renderImageDetailsContent, this );
     1997                        this.on( 'menu:render:image-details', this.renderMenu, this );
     1998                        this.on( 'toolbar:render:image-details', this.renderToolbar, this );
     1999                },
     2000
     2001                createStates: function() {
     2002                        var options = this.options;
     2003                        this.states.add([
     2004                                new media.controller.ImageDetails({
     2005                                        metadata: options.metadata,
     2006                                        editable: false,
     2007                                        menu: 'image-details'
     2008                                }),
     2009                                new media.controller.Library({
     2010                                        id: 'replace-image',
     2011                                        library:   media.query(),
     2012                                        multiple:  false,
     2013                                        title:     l10n.imageReplaceTitle,
     2014                                        menu: 'image-details',
     2015                                        priority:  80
     2016                                })
     2017                        ]);
     2018                },
     2019
     2020                renderImageDetailsContent: function() {
     2021                        var view = new media.view.ImageDetails({
     2022                                controller: this,
     2023                                model: this.state().props,
     2024                                attachment: this.state().props.attachment
     2025                        }).render();
     2026
     2027                        this.content.set( view );
     2028
     2029                },
     2030
     2031                renderMenu: function( view ) {
     2032                        var lastState = this.lastState(),
     2033                                previous = lastState && lastState.id,
     2034                                frame = this;
     2035
     2036                        view.set({
     2037                                cancel: {
     2038                                        text:     l10n.imageDetailsCancel,
     2039                                        priority: 20,
     2040                                        click:    function() {
     2041                                                if ( previous ) {
     2042                                                        frame.setState( previous );
     2043                                                } else {
     2044                                                        frame.close();
     2045                                                }
     2046                                        }
     2047                                },
     2048                                separateCancel: new media.View({
     2049                                        className: 'separator',
     2050                                        priority: 40
     2051                                })
     2052                        });
     2053
     2054                },
     2055
     2056                renderToolbar: function() {
     2057                        this.toolbar.set( new media.view.Toolbar({
     2058                                controller: this,
     2059                                items: {
     2060                                        update: {
     2061                                                style:    'primary',
     2062                                                text:     l10n.update,
     2063                                                priority: 80,
     2064
     2065                                                click: function() {
     2066                                                        var controller = this.controller,
     2067                                                                state = controller.state();
     2068
     2069                                                        controller.close();
     2070
     2071                                                        // not sure if we want to use wp.media.string.image which will create a shortcode or
     2072                                                        // perhaps wp.html.string to at least to build the <img />
     2073
     2074                                                        state.trigger( 'update', state.props.toJSON() );
     2075
     2076                                                        // Restore and reset the default state.
     2077                                                        controller.setState( controller.options.state );
     2078                                                        controller.reset();
     2079                                                }
     2080                                        }
     2081                                }
     2082                        }) );
    19262083                }
     2084
     2085
     2086
    19272087        });
    19282088
     2089
    19292090        /**
    19302091         * wp.media.view.Modal
    19312092         *
     
    49325093                        this.$('img').attr( 'src', this.model.get('url') );
    49335094                }
    49345095        });
    4935 }(jQuery));
    4936  No newline at end of file
     5096
     5097        // maybe I should just avoid the inheritance
     5098        media.view.ImageDetails = media.view.Settings.AttachmentDisplay.extend({
     5099                className: 'image-details',
     5100                template:  media.template('image-details'),
     5101
     5102                prepare: function() {
     5103                        var attachment = false;
     5104
     5105                        if ( this.model.attachment ) {
     5106                                attachment = this.model.attachment.toJSON();
     5107                        }
     5108                        return _.defaults({
     5109                                model: this.model.toJSON(),
     5110                                attachment: attachment
     5111                        }, this.options );
     5112                },
     5113
     5114
     5115                render: function() {
     5116                        var self = this,
     5117                                args = arguments;
     5118                        if ( this.model.attachment && 'pending' === this.model.dfd.state() ) {
     5119                                // should instead show a spinner when the attachment is new and then add a listener that updates on change
     5120                                this.model.dfd.done( function() {
     5121                                        media.view.Settings.AttachmentDisplay.prototype.render.apply( self, args );
     5122                                } );
     5123                        } else {
     5124                                media.view.Settings.AttachmentDisplay.prototype.render.apply( this, arguments );
     5125                        }
     5126
     5127
     5128                        return this;
     5129                }
     5130        });
     5131}(jQuery));
  • 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 3f4ca10..e34e7e7 100644
    tinymce.PluginManager.add( 'wpeditimage', function( editor ) { 
    101101                });
    102102        }
    103103
     104        function extractImageData( imageNode ) {
     105                var classes, metadata, captionBlock, caption;
     106
     107                // default attributes
     108                metadata = {
     109                        attachment_id: false,
     110                        url: false,
     111                        height: '',
     112                        width: '',
     113                        size: 'none',
     114                        caption: '',
     115                        alt: '',
     116                        align: 'none',
     117                        link: 'none',
     118                        linkUrl: ''
     119                };
     120
     121                metadata.url = editor.dom.getAttrib( imageNode, 'src' );
     122                metadata.alt = editor.dom.getAttrib( imageNode, 'alt' );
     123                metadata.width = parseInt( editor.dom.getAttrib( imageNode, 'width' ), 10 );
     124                metadata.height = parseInt( editor.dom.getAttrib( imageNode, 'height' ), 10 );
     125
     126                //TODO: probably should capture attributes on both the <img /> and the <a /> so that they can be restored when the image and/or caption are updated
     127                // maybe use getAttribs()
     128
     129                // extract meta data from classes (candidate for turning into a method)
     130                classes = imageNode.className.split( ' ' );
     131                tinymce.each( classes, function( name ) {
     132
     133                        if ( /^wp-image/.test( name ) ) {
     134                                metadata.attachment_id = parseInt( name.replace( 'wp-image-', '' ), 10 );
     135                        }
     136
     137                        if ( /^align/.test( name ) ) {
     138                                metadata.align = name.replace( 'align', '' );
     139                        }
     140
     141                        if ( /^size/.test( name ) ) {
     142                                metadata.size = name.replace( 'size-', '' );
     143                        }
     144                } );
     145
     146
     147                // extract caption
     148                captionBlock = editor.dom.getParents( imageNode, '.wp-caption' );
     149
     150                if ( captionBlock.length ) {
     151                        captionBlock = captionBlock[0];
     152
     153                        classes = captionBlock.className.split( ' ' );
     154                        tinymce.each( classes, function( name ) {
     155                                if ( /^align/.test( name ) ) {
     156                                        metadata.align = name.replace( 'align', '' );
     157                                }
     158                        } );
     159                        caption = editor.dom.select( 'dd.wp-caption-dd', captionBlock );
     160                        if ( caption.length ) {
     161                                caption = caption[0];
     162                                // need to do some more thinking about this
     163                                metadata.caption = editor.serializer.serialize( caption )
     164                                        .replace( /<br[^>]*>/g, '$&\n' ).replace( /^<p>/, '' ).replace( /<\/p>$/, '' );
     165
     166                        }
     167                }
     168
     169                // extract linkTo
     170                if ( imageNode.parentNode.nodeName === 'A' ) {
     171                        metadata.linkUrl = editor.dom.getAttrib( imageNode.parentNode, 'href' );
     172                }
     173
     174                return metadata;
     175
     176        }
     177
     178        function updateImage( imageNode, imageData ) {
     179                var className, width, node, html, captionNode, nodeToReplace, uid;
     180
     181                if ( imageData.caption ) {
     182
     183                        html = createImageAndLink( imageData, 'html' );
     184
     185                        width = imageData.width + 10;
     186                        className = 'align' + imageData.align;
     187
     188                        //TODO: shouldn't add the id attribute if it isn't an attachment
     189
     190                        // should create a new function for genrating the caption markup
     191                        html =  '<dl id="'+ imageData.attachment_id +'" class="wp-caption '+ className +'" style="width: '+ width +'px">' +
     192                                '<dt class="wp-caption-dt">'+ html + '</dt><dd class="wp-caption-dd">'+ imageData.caption +'</dd></dl>';
     193
     194                        node = editor.dom.create( 'div', { 'class': 'mceTemp', draggable: 'true' }, html );
     195                } else {
     196                        node = createImageAndLink( imageData, 'node' );
     197                }
     198
     199                nodeToReplace = imageNode;
     200
     201                captionNode = editor.dom.getParent( imageNode, '.mceTemp' );
     202
     203                if ( captionNode ) {
     204                        nodeToReplace = captionNode;
     205                } else {
     206                        if ( imageNode.parentNode.nodeName === 'A' ) {
     207                                nodeToReplace = imageNode.parentNode;
     208                        }
     209                }
     210                // uniqueId isn't super exciting, so maybe we want to use something else
     211                uid = editor.dom.uniqueId( 'wp_' );
     212                editor.dom.setAttrib( node, 'data-wp-replace-id', uid );
     213                editor.dom.replace( node, nodeToReplace );
     214
     215                // find the updated node
     216                node = editor.dom.select( '[data-wp-replace-id="' + uid + '"]' )[0];
     217
     218                editor.dom.setAttrib( node, 'data-wp-replace-id', '' );
     219
     220                if ( node.nodeName === 'IMG' ) {
     221                        editor.selection.select( node );
     222                } else {
     223                        editor.selection.select( editor.dom.select( 'img', node )[0] );
     224                }
     225                editor.nodeChanged();
     226
     227        }
     228
     229        function createImageAndLink( imageData, mode ) {
     230                var classes = [],
     231                        props;
     232
     233                mode = mode ? mode : 'node';
     234
     235
     236                if ( ! imageData.caption ) {
     237                        classes.push( 'align' + imageData.align );
     238                }
     239
     240                if ( imageData.attachment_id ) {
     241                        classes.push( 'wp-image-' + imageData.attachment_id );
     242                        if ( imageData.size ) {
     243                                classes.push( 'size-' + imageData.size );
     244                        }
     245                }
     246
     247                props = {
     248                        src: imageData.url,
     249                        width: imageData.width,
     250                        height: imageData.height,
     251                        alt: imageData.alt
     252                };
     253
     254                if ( classes.length ) {
     255                        props['class'] = classes.join( ' ' );
     256                }
     257
     258                if ( imageData.linkUrl ) {
     259                        if ( mode === 'node' ) {
     260                                return editor.dom.create( 'a', { href: imageData.linkUrl }, editor.dom.createHTML( 'img', props ) );
     261                        } else if ( mode === 'html' ) {
     262                                return editor.dom.createHTML( 'a', { href: imageData.linkUrl }, editor.dom.createHTML( 'img', props ) );
     263                        }
     264                } else {
     265                        if ( mode === 'node' ) {
     266                                return editor.dom.create( 'img', props );
     267                        } else if ( mode === 'html' ) {
     268                                return editor.dom.createHTML( 'img', props );
     269                        }
     270
     271                }
     272        }
     273
    104274        editor.on( 'init', function() {
    105275                var dom = editor.dom;
    106276
    tinymce.PluginManager.add( 'wpeditimage', function( editor ) { 
    452622                }
    453623        });
    454624
     625        editor.on( 'mouseup', function( e ) {
     626                var imageNode, frame;
     627                if ( e.target.nodeName === 'IMG' && editor.dom.getAttrib( e.target, 'data-mce-selected' ) === '1' ) {
     628                        // Don't trigger on right-click
     629                        if ( e.button !== 2 ) {
     630
     631                                if ( editor.dom.hasClass( e.target, 'mceItem' ) || '1' === editor.dom.getAttrib( e.target, 'data-mce-placeholder' ) ) {
     632                                        return;
     633                                }
     634
     635
     636                                imageNode = e.target;
     637
     638                                // file, post, custom, none
     639                                frame = wp.media({
     640                                        frame: 'image',
     641                                        state: 'image-details',
     642                                        multiple: false,
     643                                        editing: true,
     644                                        metadata: extractImageData( imageNode )
     645                                } );
     646
     647                                // update the image when update is clicked in the media frame
     648                                frame.state('image-details').on( 'update', function( imageData ) {
     649                                        editor.focus();
     650                                        updateImage( imageNode, imageData );
     651                                } );
     652
     653                                frame.open();
     654
     655
     656                        }
     657                }
     658        } );
     659
    455660        editor.wpSetImgCaption = function( content ) {
    456661                return parseShortcode( content );
    457662        };
  • src/wp-includes/media-template.php

    diff --git src/wp-includes/media-template.php src/wp-includes/media-template.php
    index 57d1c00..3e251b8 100644
    function wp_print_media_templates() { 
    500500                        }
    501501                </style>
    502502        </script>
     503
     504        <script type="text/html" id="tmpl-image-details">
     505                <?php // reusing .media-embed to pick up the styles for now ?>
     506                <div class="media-embed">
     507                        <div class="embed-image-settings">
     508                                <div class="thumbnail">
     509                                        <img src="{{ data.model.url }}" draggable="false" />
     510                                </div>
     511
     512                                <div class="url">
     513                                        <?php // might want to make the url editable if it isn't an attachment ?>
     514                                        <input type="text" disabled="disabled" value="{{ data.model.url }}" />
     515                                </div>
     516
     517                                <?php
     518                                /** This filter is documented in wp-admin/includes/media.php */
     519                                if ( ! apply_filters( 'disable_captions', '' ) ) : ?>
     520                                        <label class="setting caption">
     521                                                <span><?php _e('Caption'); ?></span>
     522                                                <textarea data-setting="caption">{{ data.model.caption }}</textarea>
     523                                        </label>
     524                                <?php endif; ?>
     525
     526                                <label class="setting alt-text">
     527                                        <span><?php _e('Alt Text'); ?></span>
     528                                        <input type="text" data-setting="alt" value="{{ data.model.alt }}" />
     529                                </label>
     530
     531                                <div class="setting align">
     532                                        <span><?php _e('Align'); ?></span>
     533                                        <div class="button-group button-large" data-setting="align">
     534                                                <button class="button" value="left">
     535                                                        <?php esc_attr_e('Left'); ?>
     536                                                </button>
     537                                                <button class="button" value="center">
     538                                                        <?php esc_attr_e('Center'); ?>
     539                                                </button>
     540                                                <button class="button" value="right">
     541                                                        <?php esc_attr_e('Right'); ?>
     542                                                </button>
     543                                                <button class="button active" value="none">
     544                                                        <?php esc_attr_e('None'); ?>
     545                                                </button>
     546                                        </div>
     547                                </div>
     548                                <div class="setting link-to">
     549                                <span><?php _e('Link To'); ?></span>
     550
     551                                <# if ( data.attachment ) { #>
     552                                        <div class="button-group button-large" data-setting="link">
     553                                                <button class="button" value="file">
     554                                                        <?php esc_attr_e('Media File'); ?>
     555                                                </button>
     556                                                <button class="button" value="post">
     557                                                        <?php esc_attr_e('Attachment Page'); ?>
     558                                                </button>
     559                                                <button class="button" value="custom">
     560                                                        <?php esc_attr_e('Custom URL'); ?>
     561                                                </button>
     562                                                <button class="button active" value="none">
     563                                                        <?php esc_attr_e('None'); ?>
     564                                                </button>
     565                                        </div>
     566                                        <input type="text" class="link-to-custom" data-setting="linkUrl" />
     567
     568                                <# } else { #>
     569                                        <div class="button-group button-large" data-setting="link">
     570                                                <button class="button" value="file">
     571                                                        <?php esc_attr_e('Image URL'); ?>
     572                                                </button>
     573                                                <button class="button" value="custom">
     574                                                        <?php esc_attr_e('Custom URL'); ?>
     575                                                </button>
     576                                                <button class="button active" value="none">
     577                                                        <?php esc_attr_e('None'); ?>
     578                                                </button>
     579                                        </div>
     580                                        <input type="text" class="link-to-custom" data-setting="linkUrl" />
     581
     582                                <# } #>
     583
     584
     585                                <# if ( data.attachment ) { #>
     586                                        <div class="setting size">
     587                                                <span><?php _e('Size'); ?></span>
     588                                                <div class="button-group button-large" data-setting="size">
     589                                                <?php
     590                                                        /** This filter is documented in wp-admin/includes/media.php */
     591                                                        $sizes = apply_filters( 'image_size_names_choose', array(
     592                                                                'thumbnail' => __('Thumbnail'),
     593                                                                'medium'    => __('Medium'),
     594                                                                'large'     => __('Large'),
     595                                                                'full'      => __('Full Size'),
     596                                                        ) );
     597
     598                                                        foreach ( $sizes as $value => $name ) : ?>
     599                                                                <#
     600                                                                var size = data.attachment.sizes['<?php echo esc_js( $value ); ?>'];
     601                                                                if ( size ) { #>
     602                                                                        <button class="button" value="<?php echo esc_attr( $value ); ?>">
     603                                                                                <?php echo esc_html( $name ); ?>
     604                                                                                </button>
     605                                                                <# } #>
     606                                                        <?php endforeach; ?>
     607                                                </div>
     608                                        </div>
     609                                <# } #>
     610                                </div>
     611                        </div>
     612                </div>
     613        </script>
    503614        <?php
    504615
    505616        /**
  • src/wp-includes/media.php

    diff --git src/wp-includes/media.php src/wp-includes/media.php
    index 4ce006e..70bba6d 100644
    function wp_enqueue_media( $args = array() ) { 
    19671967                'search'      => __( 'Search' ),
    19681968                'select'      => __( 'Select' ),
    19691969                'cancel'      => __( 'Cancel' ),
     1970                'update'      => __( 'Update' ),
    19701971                /* translators: This is a would-be plural string used in the media manager.
    19711972                   If there is not a word you can use in your language to avoid issues with the
    19721973                   lack of plural support here, turn it into "selected: %d" then translate it.
    function wp_enqueue_media( $args = array() ) { 
    20052006                'addToGallery'       => __( 'Add to gallery' ),
    20062007                'addToGalleryTitle'  => __( 'Add to Gallery' ),
    20072008                'reverseOrder'       => __( 'Reverse order' ),
     2009
     2010
     2011                // Edit Image
     2012                'imageDetailsTitle'     => __( 'Image Details' ),
     2013                'imageReplaceTitle'     => __( 'Replace Image' ),
     2014                'imageDetailsCancel'     => __( 'Cancel Edit' )
    20082015        );
    20092016
    20102017        $settings = apply_filters( 'media_view_settings', $settings, $post );