WordPress.org

Make WordPress Core

Changeset 27050


Ignore:
Timestamp:
01/28/2014 09:16:42 PM (6 years ago)
Author:
azaozz
Message:

Introduce Edit Image (single mode) in the media modal and use it to edit images inserted in the editor. Adds new feature: replace an image in the editor. Props gcorne, see #24409.

Location:
trunk/src/wp-includes
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-editor.php

    r27030 r27050  
    229229                        'tabfocus',
    230230                        'textcolor',
    231                         'image',
    232231                        'fullscreen',
    233232                        'wordpress',
  • trunk/src/wp-includes/css/media-views.css

    r26929 r27050  
    8787}
    8888
     89.media-frame .hidden {
     90    display: none;
     91}
     92
    8993/* Enable draggable on IE10 touch events until it's rolled into jQuery UI core */
    9094.ui-sortable,
     
    14121416
    14131417/**
    1414  * Embed from URL
     1418 * Embed from URL and Image Details
    14151419 */
    14161420.embed-url {
     
    14531457}
    14541458
     1459.image-details .embed-image-settings {
     1460    top: 0;
     1461}
     1462
    14551463.media-embed .thumbnail {
    14561464    max-width: 100%;
     
    14831491    display: block;
    14841492    clear: both;
     1493}
     1494
     1495.media-embed .setting .hidden {
     1496    display: none;
    14851497}
    14861498
  • trunk/src/wp-includes/js/media-models.js

    r27032 r27050  
    33
    44(function($){
    5     var Attachment, Attachments, Query, compare, l10n, media;
     5    var Attachment, Attachments, Query, PostImage, compare, l10n, media;
    66
    77    /**
     
    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
     
    338340            return Attachments.all.push( attachment || { id: id } );
    339341        })
     342    });
     343
     344    /**
     345     * wp.media.model.Attachment
     346     *
     347     * @constructor
     348     * @augments Backbone.Model
     349     *
     350     **/
     351    PostImage = media.model.PostImage = Backbone.Model.extend({
     352
     353        initialize: function( attributes ) {
     354            this.attachment = false;
     355
     356            if ( attributes.attachment_id ) {
     357                this.attachment = media.model.Attachment.get( attributes.attachment_id );
     358                this.dfd = this.attachment.fetch();
     359                this.bindAttachmentListeners();
     360            }
     361
     362            // keep url in sync with changes to the type of link
     363            this.on( 'change:link', this.updateLinkUrl, this );
     364            this.on( 'change:size', this.updateSize, this );
     365
     366            this.setLinkTypeFromUrl();
     367
     368        },
     369
     370        bindAttachmentListeners: function() {
     371            this.listenTo( this.attachment, 'sync', this.setLinkTypeFromUrl );
     372        },
     373
     374        changeAttachment: function( attachment, props ) {
     375            this.stopListening( this.attachment );
     376            this.attachment = attachment;
     377            this.bindAttachmentListeners();
     378
     379            this.set( 'attachment_id', this.attachment.get( 'id' ) );
     380            this.set( 'caption', this.attachment.get( 'caption' ) );
     381            this.set( 'alt', this.attachment.get( 'alt' ) );
     382            this.set( 'size', props.get( 'size' ) );
     383            this.set( 'align', props.get( 'align' ) );
     384            this.set( 'link', props.get( 'link' ) );
     385            this.updateLinkUrl();
     386            this.updateSize();
     387        },
     388
     389        setLinkTypeFromUrl: function() {
     390            var linkUrl = this.get( 'linkUrl' ),
     391                type;
     392
     393            if ( ! linkUrl ) {
     394                this.set( 'link', 'none' );
     395                return;
     396            }
     397
     398            // default to custom if there is a linkUrl
     399            type = 'custom';
     400
     401            if ( this.attachment ) {
     402                if ( this.attachment.get( 'url' ) === linkUrl ) {
     403                    type = 'file';
     404                } else if ( this.attachment.get( 'link' ) === linkUrl ) {
     405                    type = 'post';
     406                }
     407            } else {
     408                if ( this.get( 'url' ) === linkUrl ) {
     409                    type = 'file';
     410                }
     411            }
     412
     413            this.set( 'link', type );
     414
     415        },
     416
     417
     418        updateLinkUrl: function() {
     419            var link = this.get( 'link' ),
     420                url;
     421
     422            switch( link ) {
     423                case 'file':
     424                    if ( this.attachment ) {
     425                        url = this.attachment.get( 'url' );
     426                    } else {
     427                        url = this.get( 'url' );
     428                    }
     429                    this.set( 'linkUrl', url );
     430                    break;
     431                case 'post':
     432                    this.set( 'linkUrl', this.attachment.get( 'link' ) );
     433                    break;
     434                case 'none':
     435                    this.set( 'linkUrl', '' );
     436                    break;
     437
     438            }
     439
     440        },
     441
     442        updateSize: function() {
     443            var size;
     444
     445            if ( ! this.attachment ) {
     446                return;
     447            }
     448
     449            size = this.attachment.get( 'sizes' )[ this.get( 'size' ) ];
     450            this.set( 'url', size.url );
     451            this.set( 'width', size.width );
     452            this.set( 'height', size.height );
     453
     454        }
     455
     456
    340457    });
    341458
  • trunk/src/wp-includes/js/media-views.js

    r26986 r27050  
    979979            selection.reset( attachment ? [ attachment ] : [] );
    980980        }
     981    });
     982
     983
     984    media.controller.ImageDetails = media.controller.State.extend({
     985
     986        defaults: _.defaults({
     987            id: 'image-details',
     988            toolbar: 'image-details',
     989            title: l10n.imageDetailsTitle,
     990            content: 'image-details',
     991            menu: 'image-details',
     992            router: false,
     993            attachment: false,
     994            priority: 60,
     995            editing: false
     996        }, media.controller.Library.prototype.defaults ),
     997
     998        initialize: function( options ) {
     999            this.image = options.image;
     1000            media.controller.State.prototype.initialize.apply( this, arguments );
     1001        }
     1002    });
     1003
     1004    /**
     1005     * wp.media.controller.ReplaceImage
     1006     *
     1007     * Replace a selected single image
     1008     *
     1009     **/
     1010    media.controller.ReplaceImage = media.controller.Library.extend({
     1011        defaults: _.defaults({
     1012            id:         'replace-image',
     1013            filterable: 'uploaded',
     1014            multiple:   false,
     1015            toolbar:    'replace',
     1016            title:      l10n.replaceImageTitle,
     1017            priority:   60,
     1018            syncSelection: false
     1019        }, media.controller.Library.prototype.defaults ),
     1020
     1021        initialize: function( options ) {
     1022            var library, comparator;
     1023
     1024            this.image = options.image;
     1025
     1026            // If we haven't been provided a `library`, create a `Selection`.
     1027            if ( ! this.get('library') ) {
     1028                this.set( 'library', media.query({ type: 'image' }) );
     1029            }
     1030            /**
     1031             * call 'initialize' directly on the parent class
     1032             */
     1033            media.controller.Library.prototype.initialize.apply( this, arguments );
     1034
     1035            library    = this.get('library');
     1036            comparator = library.comparator;
     1037
     1038            // Overload the library's comparator to push items that are not in
     1039            // the mirrored query to the front of the aggregate collection.
     1040            library.comparator = function( a, b ) {
     1041                var aInQuery = !! this.mirroring.get( a.cid ),
     1042                    bInQuery = !! this.mirroring.get( b.cid );
     1043
     1044                if ( ! aInQuery && bInQuery ) {
     1045                    return -1;
     1046                } else if ( aInQuery && ! bInQuery ) {
     1047                    return 1;
     1048                } else {
     1049                    return comparator.apply( this, arguments );
     1050                }
     1051            };
     1052
     1053            // Add all items in the selection to the library, so any featured
     1054            // images that are not initially loaded still appear.
     1055            library.observe( this.get('selection') );
     1056        },
     1057
     1058        activate: function() {
     1059            this.updateSelection();
     1060            /**
     1061             * call 'activate' directly on the parent class
     1062             */
     1063            media.controller.Library.prototype.activate.apply( this, arguments );
     1064        },
     1065
     1066        deactivate: function() {
     1067            /**
     1068             * call 'deactivate' directly on the parent class
     1069             */
     1070            media.controller.Library.prototype.deactivate.apply( this, arguments );
     1071        },
     1072
     1073        updateSelection: function() {
     1074            var selection = this.get('selection'),
     1075                attachment = this.image.attachment;
     1076
     1077            selection.reset( attachment ? [ attachment ] : [] );
     1078
     1079        }
     1080
     1081
    9811082    });
    9821083
     
    19252026            }) );
    19262027        }
    1927     });
     2028
     2029    });
     2030
     2031    media.view.MediaFrame.ImageDetails = media.view.MediaFrame.Select.extend({
     2032        defaults: {
     2033            id:      'image',
     2034            url:     '',
     2035            menu:    'image-details',
     2036            content: 'image-details',
     2037            toolbar: 'image-details',
     2038            type:    'link',
     2039            title:    l10n.imageDetailsTitle,
     2040            priority: 120
     2041        },
     2042
     2043        initialize: function( options ) {
     2044            this.image = new media.model.PostImage( options.metadata );
     2045            this.options.selection = new media.model.Selection( this.image.attachment, { multiple: false } );
     2046            media.view.MediaFrame.Select.prototype.initialize.apply( this, arguments );
     2047        },
     2048
     2049        bindHandlers: function() {
     2050            media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
     2051            this.on( 'menu:create:image-details', this.createMenu, this );
     2052            this.on( 'content:render:image-details', this.renderImageDetailsContent, this );
     2053            this.on( 'menu:render:image-details', this.renderMenu, this );
     2054            this.on( 'toolbar:render:image-details', this.renderImageDetailsToolbar, this );
     2055            // override the select toolbar
     2056            this.on( 'toolbar:render:replace', this.renderReplaceImageToolbar, this );
     2057        },
     2058
     2059        createStates: function() {
     2060            this.states.add([
     2061                new media.controller.ImageDetails({
     2062                    image: this.image,
     2063                    editable: false,
     2064                    menu: 'image-details'
     2065                }),
     2066                new media.controller.ReplaceImage({
     2067                    id: 'replace-image',
     2068                    library:   media.query( { type: 'image' } ),
     2069                    image: this.image,
     2070                    multiple:  false,
     2071                    title:     l10n.imageReplaceTitle,
     2072                    menu: 'image-details',
     2073                    toolbar: 'replace',
     2074                    priority:  80,
     2075                    displaySettings: true
     2076                })
     2077            ]);
     2078        },
     2079
     2080        renderImageDetailsContent: function() {
     2081            var view = new media.view.ImageDetails({
     2082                controller: this,
     2083                model: this.state().image,
     2084                attachment: this.state().image.attachment
     2085            }).render();
     2086
     2087            this.content.set( view );
     2088
     2089        },
     2090
     2091        renderMenu: function( view ) {
     2092            var lastState = this.lastState(),
     2093                previous = lastState && lastState.id,
     2094                frame = this;
     2095
     2096            view.set({
     2097                cancel: {
     2098                    text:     l10n.imageDetailsCancel,
     2099                    priority: 20,
     2100                    click:    function() {
     2101                        if ( previous ) {
     2102                            frame.setState( previous );
     2103                        } else {
     2104                            frame.close();
     2105                        }
     2106                    }
     2107                },
     2108                separateCancel: new media.View({
     2109                    className: 'separator',
     2110                    priority: 40
     2111                })
     2112            });
     2113
     2114        },
     2115
     2116        renderImageDetailsToolbar: function() {
     2117            this.toolbar.set( new media.view.Toolbar({
     2118                controller: this,
     2119                items: {
     2120                    select: {
     2121                        style:    'primary',
     2122                        text:     l10n.update,
     2123                        priority: 80,
     2124
     2125                        click: function() {
     2126                            var controller = this.controller,
     2127                                state = controller.state();
     2128
     2129                            controller.close();
     2130
     2131                            // not sure if we want to use wp.media.string.image which will create a shortcode or
     2132                            // perhaps wp.html.string to at least to build the <img />
     2133                            state.trigger( 'update', controller.image.toJSON() );
     2134
     2135                            // Restore and reset the default state.
     2136                            controller.setState( controller.options.state );
     2137                            controller.reset();
     2138                        }
     2139                    }
     2140                }
     2141            }) );
     2142        },
     2143
     2144        renderReplaceImageToolbar: function() {
     2145            this.toolbar.set( new media.view.Toolbar({
     2146                controller: this,
     2147                items: {
     2148                    replace: {
     2149                        style:    'primary',
     2150                        text:     l10n.replace,
     2151                        priority: 80,
     2152
     2153                        click: function() {
     2154                            var controller = this.controller,
     2155                                state = controller.state(),
     2156                                selection = state.get( 'selection' ),
     2157                                attachment = selection.single();
     2158
     2159                            controller.close();
     2160
     2161                            controller.image.changeAttachment( attachment, state.display( attachment ) );
     2162
     2163                            // not sure if we want to use wp.media.string.image which will create a shortcode or
     2164                            // perhaps wp.html.string to at least to build the <img />
     2165                            state.trigger( 'replace', controller.image.toJSON() );
     2166
     2167                            // Restore and reset the default state.
     2168                            controller.setState( controller.options.state );
     2169                            controller.reset();
     2170                        }
     2171                    }
     2172                }
     2173            }) );
     2174        }
     2175
     2176    });
     2177
    19282178
    19292179    /**
     
    45564806
    45574807            if ( 'none' === linkTo || 'embed' === linkTo || ( ! attachment && 'custom' !== linkTo ) ) {
    4558                 $input.hide();
     4808                $input.addClass( 'hidden' );
    45594809                return;
    45604810            }
     
    45724822            }
    45734823
    4574             $input.show();
     4824            $input.removeClass( 'hidden' );
    45754825
    45764826            // If the input is visible, focus and select its contents.
     
    49335183        }
    49345184    });
     5185
     5186    media.view.ImageDetails = media.view.Settings.AttachmentDisplay.extend({
     5187        className: 'image-details',
     5188        template:  media.template('image-details'),
     5189
     5190        initialize: function() {
     5191            // used in AttachmentDisplay.prototype.updateLinkTo
     5192            this.options.attachment = this.model.attachment;
     5193            media.view.Settings.AttachmentDisplay.prototype.initialize.apply( this, arguments );
     5194        },
     5195
     5196        prepare: function() {
     5197            var attachment = false;
     5198
     5199            if ( this.model.attachment ) {
     5200                attachment = this.model.attachment.toJSON();
     5201            }
     5202            return _.defaults({
     5203                model: this.model.toJSON(),
     5204                attachment: attachment
     5205            }, this.options );
     5206        },
     5207
     5208
     5209        render: function() {
     5210            var self = this,
     5211                args = arguments;
     5212            if ( this.model.attachment && 'pending' === this.model.dfd.state() ) {
     5213                // should instead show a spinner when the attachment is new and then add a listener that updates on change
     5214                this.model.dfd.done( function() {
     5215                    media.view.Settings.AttachmentDisplay.prototype.render.apply( self, args );
     5216                    self.resetFocus();
     5217                } );
     5218            } else {
     5219                media.view.Settings.AttachmentDisplay.prototype.render.apply( this, arguments );
     5220                setTimeout( function() { self.resetFocus(); }, 10 );
     5221            }
     5222
     5223            return this;
     5224        },
     5225
     5226        resetFocus: function() {
     5227            this.$( '.caption textarea' ).focus();
     5228            this.$( '.embed-image-settings' ).scrollTop( 0 );
     5229        }
     5230    });
    49355231}(jQuery));
  • trunk/src/wp-includes/js/tinymce/plugins/wpeditimage/plugin.js

    r26942 r27050  
    100100            return out;
    101101        });
     102    }
     103
     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: false,
     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        }
    102272    }
    103273
     
    453623    });
    454624
     625    editor.on( 'mousedown', function( e ) {
     626        var imageNode, frame, callback;
     627        if ( e.target.nodeName === 'IMG' && editor.selection.getNode() === e.target ) {
     628            // Don't trigger on right-click
     629            if ( e.button !== 2 ) {
     630
     631                // Don't attempt to edit placeholders
     632                if ( editor.dom.hasClass( e.target, 'mceItem' ) || '1' === editor.dom.getAttrib( e.target, 'data-mce-placeholder' ) ) {
     633                    return;
     634                }
     635
     636                imageNode = e.target;
     637
     638                frame = wp.media({
     639                    frame: 'image',
     640                    state: 'image-details',
     641                    metadata: extractImageData( imageNode )
     642                } );
     643
     644                callback = function( imageData ) {
     645                    updateImage( imageNode, imageData );
     646                    editor.focus();
     647                };
     648
     649                frame.state('image-details').on( 'update', callback );
     650                frame.state('replace-image').on( 'replace', callback );
     651
     652                frame.open();
     653
     654
     655            }
     656        }
     657    } );
     658
    455659    editor.wpSetImgCaption = function( content ) {
    456660        return parseShortcode( content );
  • trunk/src/wp-includes/media-template.php

    r26400 r27050  
    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="setting 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                </div>
     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
  • trunk/src/wp-includes/media.php

    r26915 r27050  
    19681968        'select'      => __( 'Select' ),
    19691969        'cancel'      => __( 'Cancel' ),
     1970        'update'      => __( 'Update' ),
     1971        'replace'     => __( 'Replace' ),
    19701972        /* translators: This is a would-be plural string used in the media manager.
    19711973           If there is not a word you can use in your language to avoid issues with the
     
    20062008        'addToGalleryTitle'  => __( 'Add to Gallery' ),
    20072009        'reverseOrder'       => __( 'Reverse order' ),
     2010
     2011
     2012        // Edit Image
     2013        'imageDetailsTitle'     => __( 'Image Details' ),
     2014        'imageReplaceTitle'     => __( 'Replace Image' ),
     2015        'imageDetailsCancel'     => __( 'Cancel Edit' )
    20082016    );
    20092017
Note: See TracChangeset for help on using the changeset viewer.