Make WordPress Core

Ticket #21811: 21811-08.patch

File 21811-08.patch, 19.2 KB (added by gcorne, 10 years ago)
  • src/wp-admin/js/image-edit.js

    diff --git src/wp-admin/js/image-edit.js src/wp-admin/js/image-edit.js
    index 9eaf51b..af908d5 100644
    var imageEdit = window.imageEdit = { 
    55        iasapi : {},
    66        hold : {},
    77        postid : '',
     8        _view : false,
    89
    910        intval : function(f) {
    1011                return f | 0;
    var imageEdit = window.imageEdit = { 
    241242                $.post(ajaxurl, data, function(r) {
    242243                        $('#image-editor-' + postid).empty().append(r);
    243244                        t.toggleEditor(postid, 0);
     245                        // refresh the attachment model so that changes propagate
     246                        if ( this._view ) {
     247                                this._view.refresh();
     248                        }
    244249                });
    245250        },
    246251
    247252        save : function(postid, nonce) {
    248                 var data, target = this.getTarget(postid), history = this.filterHistory(postid, 0);
     253                var data,
     254                        target = this.getTarget(postid),
     255                        history = this.filterHistory(postid, 0),
     256                        self = this;
    249257
    250258                if ( '' === history ) {
    251259                        return false;
    var imageEdit = window.imageEdit = { 
    283291                                $('#imgedit-response-' + postid).html('<div class="updated"><p>' + ret.msg + '</p></div>');
    284292                        }
    285293
    286                         imageEdit.close(postid);
     294                        if ( self._view ) {
     295                                self._view.save();
     296                        } else {
     297                                imageEdit.close(postid);
     298                        }
    287299                });
    288300        },
    289301
    290         open : function(postid, nonce) {
     302        open : function( postid, nonce, view ) {
     303                this._view = view;
     304
    291305                var data, elem = $('#image-editor-' + postid), head = $('#media-head-' + postid),
    292306                        btn = $('#imgedit-open-btn-' + postid), spin = btn.siblings('.spinner');
    293307
    var imageEdit = window.imageEdit = { 
    319333        },
    320334
    321335        initCrop : function(postid, image, parent) {
    322                 var t = this, selW = $('#imgedit-sel-width-' + postid),
    323                         selH = $('#imgedit-sel-height-' + postid);
     336                var t = this,
     337                        selW = $('#imgedit-sel-width-' + postid),
     338                        selH = $('#imgedit-sel-height-' + postid),
     339                        $img;
    324340
    325341                t.iasapi = $(image).imgAreaSelect({
    326342                        parent: parent,
    var imageEdit = window.imageEdit = { 
    330346                        minWidth: 3,
    331347                        minHeight: 3,
    332348
    333                         onInit: function() {
     349                        onInit: function( img ) {
     350                                // Ensure that the imgareaselect wrapper elements are position:absolute
     351                                // (even if we're in a position:fixed modal)
     352                                $img = $( img );
     353                                $img.next().css( 'position', 'absolute' )
     354                                        .nextAll( '.imgareaselect-outer' ).css( 'position', 'absolute' );
     355
    334356                                parent.children().mousedown(function(e){
    335357                                        var ratio = false, sel, defRatio;
    336358
    var imageEdit = window.imageEdit = { 
    397419
    398420                this.iasapi = {};
    399421                this.hold = {};
    400                 $('#image-editor-' + postid).fadeOut('fast', function() {
    401                         $('#media-head-' + postid).fadeIn('fast');
    402                         $(this).empty();
    403                 });
     422
     423                // If we've loaded the editor in the context of a Media Modal, then switch to the previous view,
     424                // whatever that might have been.
     425                if ( this._view ){
     426                        this._view.back();
     427                }
     428
     429                // In case we are not accessing the image editor in the context of a View, close the editor the old-skool way
     430                else {
     431                        $('#image-editor-' + postid).fadeOut('fast', function() {
     432                                $('#media-head-' + postid).fadeIn('fast');
     433                                $(this).empty();
     434                        });
     435                }
     436
     437
    404438        },
    405439
    406440        notsaved : function(postid) {
  • src/wp-includes/css/media-views.css

    diff --git src/wp-includes/css/media-views.css src/wp-includes/css/media-views.css
    index b653be5..3e9a512 100644
     
    14321432}
    14331433
    14341434/**
     1435 * Image Editor
     1436 */
     1437
     1438.media-frame .image-editor {
     1439        padding: 16px;
     1440}
     1441
     1442.media-frame .imgedit-wrap table td {
     1443        vertical-align: top;
     1444        padding-top: 0;
     1445}
     1446
     1447.media-frame .imgedit-wrap table td.imgedit-settings {
     1448        width: 250px;
     1449}
     1450/**
    14351451 * Embed from URL and Image Details
    14361452 */
    14371453.embed-url {
     
    14901506        display: block;
    14911507}
    14921508
     1509.media-embed .edit-attachment {
     1510        margin-left: 10px;
     1511}
     1512
    14931513.media-embed .thumbnail:after {
    14941514        content: '';
    14951515        display: block;
  • src/wp-includes/js/media-editor.js

    diff --git src/wp-includes/js/media-editor.js src/wp-includes/js/media-editor.js
    index a0cb52e..f065c0e 100644
     
    698698
    699699                        this._frame = wp.media({
    700700                                state: 'featured-image',
    701                                 states: [ new wp.media.controller.FeaturedImage() ]
     701                                states: [ new wp.media.controller.FeaturedImage() , new wp.media.controller.EditImage() ]
    702702                        });
    703703
    704704                        this._frame.on( 'toolbar:create:featured-image', function( toolbar ) {
     
    710710                                });
    711711                        }, this._frame );
    712712
     713                        this._frame.on( 'content:render:edit-image', function() {
     714                                var selection = this.state('featured-image').get('selection'),
     715                                        view = new wp.media.view.EditImage( { model: selection.single(), controller: this } ).render();
     716
     717                                this.content.set( view );
     718
     719                                // after bringing in the frame, load the actual editor via an ajax call
     720                                view.loadEditor();
     721
     722                        }, this._frame );
     723
    713724                        this._frame.state('featured-image').on( 'select', this.select );
    714725                        return this._frame;
    715726                },
  • src/wp-includes/js/media-models.js

    diff --git src/wp-includes/js/media-models.js src/wp-includes/js/media-models.js
    index adbbca2..ea3fed8 100644
    window.wp = window.wp || {}; 
    371371
    372372                bindAttachmentListeners: function() {
    373373                        this.listenTo( this.attachment, 'sync', this.setLinkTypeFromUrl );
     374                        this.listenTo( this.attachment, 'change', this.updateSize );
    374375                },
    375376
    376377                changeAttachment: function( attachment, props ) {
  • src/wp-includes/js/media-views.js

    diff --git src/wp-includes/js/media-views.js src/wp-includes/js/media-views.js
    index 862ec7b..8c1d1e5 100644
     
    483483                };
    484484        });
    485485
     486        media.selectionSync = {
     487                syncSelection: function() {
     488                        var selection = this.get('selection'),
     489                                manager = this.frame._selection;
     490
     491                        if ( ! this.get('syncSelection') || ! manager || ! selection ) {
     492                                return;
     493                        }
     494
     495                        // If the selection supports multiple items, validate the stored
     496                        // attachments based on the new selection's conditions. Record
     497                        // the attachments that are not included; we'll maintain a
     498                        // reference to those. Other attachments are considered in flux.
     499                        if ( selection.multiple ) {
     500                                selection.reset( [], { silent: true });
     501                                selection.validateAll( manager.attachments );
     502                                manager.difference = _.difference( manager.attachments.models, selection.models );
     503                        }
     504
     505                        // Sync the selection's single item with the master.
     506                        selection.single( manager.single );
     507                },
     508
     509                /**
     510                 * Record the currently active attachments, which is a combination
     511                 * of the selection's attachments and the set of selected
     512                 * attachments that this specific selection considered invalid.
     513                 * Reset the difference and record the single attachment.
     514                 */
     515                recordSelection: function() {
     516                        var selection = this.get('selection'),
     517                                manager = this.frame._selection;
     518
     519                        if ( ! this.get('syncSelection') || ! manager || ! selection ) {
     520                                return;
     521                        }
     522
     523                        if ( selection.multiple ) {
     524                                manager.attachments.reset( selection.toArray().concat( manager.difference ) );
     525                                manager.difference = [];
     526                        } else {
     527                                manager.attachments.add( selection.toArray() );
     528                        }
     529
     530                        manager.single = selection._single;
     531                }
     532        };
     533
    486534        /**
    487535         * wp.media.controller.Library
    488536         *
     
    635683                        return _.contains( media.view.settings.embedExts, attachment.get('filename').split('.').pop() );
    636684                },
    637685
    638                 syncSelection: function() {
    639                         var selection = this.get('selection'),
    640                                 manager = this.frame._selection;
    641 
    642                         if ( ! this.get('syncSelection') || ! manager || ! selection ) {
    643                                 return;
    644                         }
    645 
    646                         // If the selection supports multiple items, validate the stored
    647                         // attachments based on the new selection's conditions. Record
    648                         // the attachments that are not included; we'll maintain a
    649                         // reference to those. Other attachments are considered in flux.
    650                         if ( selection.multiple ) {
    651                                 selection.reset( [], { silent: true });
    652                                 selection.validateAll( manager.attachments );
    653                                 manager.difference = _.difference( manager.attachments.models, selection.models );
    654                         }
    655 
    656                         // Sync the selection's single item with the master.
    657                         selection.single( manager.single );
    658                 },
    659 
    660                 /**
    661                  * Record the currently active attachments, which is a combination
    662                  * of the selection's attachments and the set of selected
    663                  * attachments that this specific selection considered invalid.
    664                  * Reset the difference and record the single attachment.
    665                  */
    666                 recordSelection: function() {
    667                         var selection = this.get('selection'),
    668                                 manager = this.frame._selection;
    669 
    670                         if ( ! this.get('syncSelection') || ! manager || ! selection ) {
    671                                 return;
    672                         }
    673 
    674                         if ( selection.multiple ) {
    675                                 manager.attachments.reset( selection.toArray().concat( manager.difference ) );
    676                                 manager.difference = [];
    677                         } else {
    678                                 manager.attachments.add( selection.toArray() );
    679                         }
    680 
    681                         manager.single = selection._single;
    682                 },
    683686
    684687                /**
    685688                 * If the state is active, no items are selected, and the current
     
    734737                }
    735738        });
    736739
     740        _.extend( media.controller.Library.prototype, media.selectionSync );
     741
    737742        /**
    738743         * wp.media.controller.ImageDetails
    739744         *
     
    989994                        toolbar:    'featured-image',
    990995                        title:      l10n.setFeaturedImageTitle,
    991996                        priority:   60,
    992                         syncSelection: false
     997                        syncSelection: true
    993998                }, media.controller.Library.prototype.defaults ),
    994999
    9951000                initialize: function() {
     
    10701075                        toolbar:    'replace',
    10711076                        title:      l10n.replaceImageTitle,
    10721077                        priority:   60,
    1073                         syncSelection: false
     1078                        syncSelection: true
    10741079                }, media.controller.Library.prototype.defaults ),
    10751080
    10761081                initialize: function( options ) {
     
    11211126        });
    11221127
    11231128        /**
     1129         * wp.media.controller.EditImage
     1130         *
     1131         * @constructor
     1132         * @augments wp.media.controller.State
     1133         * @augments Backbone.Model
     1134         */
     1135        media.controller.EditImage = media.controller.State.extend({
     1136                defaults: {
     1137                        id: 'edit-image',
     1138                        url: '',
     1139                        menu: false,
     1140                        toolbar: 'edit-image',
     1141                        title: l10n.editImage,
     1142                        content: 'edit-image',
     1143                        syncSelection: true
     1144                },
     1145
     1146                activate: function() {
     1147                        if ( ! this.get('selection') ) {
     1148                                this.set( 'selection', new media.model.Selection() );
     1149                        }
     1150                        this.listenTo( this.frame, 'toolbar:render:edit-image', this.toolbar );
     1151                        this.syncSelection();
     1152                },
     1153
     1154                deactivate: function() {
     1155                        this.stopListening( this.frame );
     1156                },
     1157
     1158                toolbar: function() {
     1159                        var frame = this.frame,
     1160                                lastState = frame.lastState(),
     1161                                previous = lastState && lastState.id;
     1162
     1163                        frame.toolbar.set( new media.view.Toolbar({
     1164                                controller: frame,
     1165                                items: {
     1166                                        back: {
     1167                                                style: 'primary',
     1168                                                text:     l10n.back,
     1169                                                priority: 20,
     1170                                                click:    function() {
     1171                                                        if ( previous ) {
     1172                                                                frame.setState( previous );
     1173                                                        } else {
     1174                                                                frame.close();
     1175                                                        }
     1176                                                }
     1177                                        }
     1178                                }
     1179                        }) );
     1180                }
     1181        });
     1182
     1183        _.extend( media.controller.EditImage.prototype, media.selectionSync );
     1184
     1185        /**
    11241186         * wp.media.controller.ReplaceVideo
    11251187         *
    11261188         * Replace a selected single video
     
    19281990                                // Embed states.
    19291991                                new media.controller.Embed(),
    19301992
     1993                                new media.controller.EditImage( { selection: options.selection } ),
     1994
    19311995                                // Gallery states.
    19321996                                new media.controller.CollectionEdit({
    19331997                                        type:           'image',
     
    20432107
    20442108                                content: {
    20452109                                        'embed':          'embedContent',
     2110                                        'edit-image':     'editImageContent',
    20462111                                        'edit-selection': 'editSelectionContent'
    20472112                                },
    20482113
     
    21952260                        this.content.set( view );
    21962261                },
    21972262
     2263                editImageContent: function() {
     2264                        var selection = this.state().get('selection'),
     2265                                view = new media.view.EditImage( { model: selection.single(), controller: this } ).render();
     2266
     2267                        this.content.set( view );
     2268
     2269                        // after creating the wrapper view, load the actual editor via an ajax call
     2270                        view.loadEditor();
     2271
     2272                },
     2273
    21982274                // Toolbars
    21992275
    22002276                /**
     
    25372613                        media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
    25382614                        this.on( 'menu:create:image-details', this.createMenu, this );
    25392615                        this.on( 'content:render:image-details', this.renderImageDetailsContent, this );
     2616                        this.on( 'content:render:edit-image', this.editImageContent, this );
    25402617                        this.on( 'menu:render:image-details', this.renderMenu, this );
    25412618                        this.on( 'toolbar:render:image-details', this.renderImageDetailsToolbar, this );
    25422619                        // override the select toolbar
     
    25602637                                        toolbar: 'replace',
    25612638                                        priority:  80,
    25622639                                        displaySettings: true
    2563                                 })
     2640                                }),
     2641                                new media.controller.EditImage( {
     2642                                        image: this.image,
     2643                                        selection: this.options.selection
     2644                                } )
    25642645                        ]);
    25652646                },
    25662647
     
    25752656
    25762657                },
    25772658
     2659                editImageContent: function() {
     2660                        var state = this.state(),
     2661                                attachment = state.get('image').attachment,
     2662                                model,
     2663                                view;
     2664
     2665                        if ( ! attachment ) {
     2666                                return;
     2667                        }
     2668
     2669                        model = state.get('selection').single();
     2670
     2671                        if ( ! model ) {
     2672                                model = attachment;
     2673                        }
     2674
     2675                        view = new media.view.EditImage( { model: model, controller: this } ).render();
     2676
     2677                        this.content.set( view );
     2678
     2679                        // after bringing in the frame, load the actual editor via an ajax call
     2680                        view.loadEditor();
     2681
     2682                },
     2683
     2684
    25782685                renderMenu: function( view ) {
    25792686                        var lastState = this.lastState(),
    25802687                                previous = lastState && lastState.id,
     
    58645971                        }
    58655972                },
    58665973
    5867                 editAttachment: function() {
    5868                         this.$el.addClass('needs-refresh');
     5974                editAttachment: function( event ) {
     5975                        event.preventDefault();
     5976                        this.controller.setState( 'edit-image' );
    58695977                },
    58705978                /**
    58715979                 * @param {Object} event
     
    58755983                        event.preventDefault();
    58765984                        this.model.fetch();
    58775985                }
     5986
    58785987        });
    58795988
    58805989        /**
     
    61586267        media.view.ImageDetails = media.view.Settings.AttachmentDisplay.extend({
    61596268                className: 'image-details',
    61606269                template:  media.template('image-details'),
    6161 
     6270                events: _.defaults( media.view.Settings.AttachmentDisplay.prototype.events, {
     6271                        'click .edit-attachment': 'editAttachment'
     6272                } ),
    61626273                initialize: function() {
    61636274                        // used in AttachmentDisplay.prototype.updateLinkTo
    61646275                        this.options.attachment = this.model.attachment;
     6276                        if ( this.model.attachment ) {
     6277                                this.listenTo( this.model.attachment, 'change:url', this.updateUrl );
     6278                        }
    61656279                        media.view.Settings.AttachmentDisplay.prototype.initialize.apply( this, arguments );
    61666280                },
    61676281
     
    61776291                        }, this.options );
    61786292                },
    61796293
    6180 
    61816294                render: function() {
    61826295                        var self = this,
    61836296                                args = arguments;
     
    61986311                resetFocus: function() {
    61996312                        this.$( '.caption textarea' ).focus();
    62006313                        this.$( '.embed-image-settings' ).scrollTop( 0 );
     6314                },
     6315
     6316                updateUrl: function() {
     6317                        this.$( '.thumbnail img' ).attr( 'src', this.model.get('url' ) );
     6318                        this.$( '.url' ).val( this.model.get('url' ) );
     6319                },
     6320
     6321                editAttachment: function( event ) {
     6322                        event.preventDefault();
     6323                        this.controller.setState( 'edit-image' );
     6324                }
     6325        });
     6326
     6327
     6328        media.view.EditImage = media.View.extend({
     6329
     6330                className: 'image-editor',
     6331                template: media.template('image-editor'),
     6332
     6333                initialize: function( options ) {
     6334                        this.editor = window.imageEdit;
     6335                        this.controller = options.controller;
     6336                        media.View.prototype.initialize.apply( this, arguments );
     6337                },
     6338
     6339                prepare: function() {
     6340                        return this.model.toJSON();
     6341                },
     6342
     6343                render: function() {
     6344                        media.View.prototype.render.apply( this, arguments );
     6345                        return this;
     6346                },
     6347
     6348                loadEditor: function() {
     6349                        this.editor.open( this.model.get('id'), this.model.get('nonces').edit, this );
     6350                },
     6351
     6352                back: function() {
     6353                        var lastState = this.controller.lastState();
     6354                        this.controller.setState( lastState );
     6355                },
     6356
     6357                refresh: function() {
     6358                        this.model.fetch();
     6359                },
     6360
     6361                save: function() {
     6362                        var self = this,
     6363                                lastState = this.controller.lastState();
     6364
     6365                        this.model.fetch().done( function() {
     6366                                self.controller.setState( lastState );
     6367                        });
    62016368                }
     6369
    62026370        });
    62036371
    62046372        /**
  • src/wp-includes/media-template.php

    diff --git src/wp-includes/media-template.php src/wp-includes/media-template.php
    index 8fcbb08..54b9780 100644
    function wp_print_media_templates() { 
    559559                                <div class="thumbnail">
    560560                                        <img src="{{ data.model.url }}" draggable="false" />
    561561                                </div>
     562                                <# if ( data.attachment ) { #>
     563                                        <input type="button" class="edit-attachment button" value="<?php esc_attr_e( 'Edit Image' ); ?>" />
     564                                <# } #>
    562565
    563566                                <div class="setting url">
    564567                                        <?php // might want to make the url editable if it isn't an attachment ?>
    function wp_print_media_templates() { 
    649652                </div>
    650653        </script>
    651654
     655        <script type="text/html" id="tmpl-image-editor">
     656                <div id="media-head-{{{ data.id }}}"></div>
     657                <div id="image-editor-{{{ data.id }}}"></div>
     658        </script>
     659
    652660        <script type="text/html" id="tmpl-audio-details">
    653661                <?php // reusing .media-embed to pick up the styles for now
    654662                ?><# var rendered = false; #>
  • src/wp-includes/media.php

    diff --git src/wp-includes/media.php src/wp-includes/media.php
    index 843e3d4..e62753a 100644
    function wp_prepare_attachment_for_js( $attachment ) { 
    21752175                'nonces'      => array(
    21762176                        'update' => false,
    21772177                        'delete' => false,
     2178                        'edit'   => false
    21782179                ),
    21792180                'editLink'   => false,
    21802181        );
    21812182
    21822183        if ( current_user_can( 'edit_post', $attachment->ID ) ) {
    21832184                $response['nonces']['update'] = wp_create_nonce( 'update-post_' . $attachment->ID );
     2185                $response['nonces']['edit'] = wp_create_nonce( 'image_editor-' . $attachment->ID );
    21842186                $response['editLink'] = get_edit_post_link( $attachment->ID, 'raw' );
    21852187        }
    21862188
    function wp_enqueue_media( $args = array() ) { 
    23352337                'cancel'      => __( 'Cancel' ),
    23362338                'update'      => __( 'Update' ),
    23372339                'replace'     => __( 'Replace' ),
     2340                'back'     => __( 'Back' ),
    23382341                /* translators: This is a would-be plural string used in the media manager.
    23392342                   If there is not a word you can use in your language to avoid issues with the
    23402343                   lack of plural support here, turn it into "selected: %d" then translate it.
    function wp_enqueue_media( $args = array() ) { 
    23802383                'imageDetailsTitle'     => __( 'Image Details' ),
    23812384                'imageReplaceTitle'     => __( 'Replace Image' ),
    23822385                'imageDetailsCancel'    => __( 'Cancel Edit' ),
     2386                'editImage'             => __( 'Edit Image' ),
    23832387
    23842388                // Edit Image
    23852389                'audioDetailsTitle'     => __( 'Audio Details' ),
    function wp_enqueue_media( $args = array() ) { 
    24212425
    24222426        wp_enqueue_script( 'media-editor' );
    24232427        wp_enqueue_style( 'media-views' );
     2428        wp_enqueue_style( 'imgareaselect' );
    24242429        wp_plupload_default_settings();
    24252430
    24262431        require_once ABSPATH . WPINC . '/media-template.php';
  • src/wp-includes/script-loader.php

    diff --git src/wp-includes/script-loader.php src/wp-includes/script-loader.php
    index 70b9735..9c7787f 100644
    function wp_default_scripts( &$scripts ) { 
    389389
    390390        // To enqueue media-views or media-editor, call wp_enqueue_media().
    391391        // Both rely on numerous settings, styles, and templates to operate correctly.
    392         $scripts->add( 'media-views',  "/wp-includes/js/media-views$suffix.js",  array( 'utils', 'media-models', 'wp-plupload', 'jquery-ui-sortable', 'wp-mediaelement' ), false, 1 );
     392        $scripts->add( 'media-views',  "/wp-includes/js/media-views$suffix.js",  array( 'utils', 'media-models', 'wp-plupload', 'jquery-ui-sortable', 'wp-mediaelement', 'image-edit' ), false, 1 );
    393393        $scripts->add( 'media-editor', "/wp-includes/js/media-editor$suffix.js", array( 'shortcode', 'media-views' ), false, 1 );
    394394        $scripts->add( 'mce-view', "/wp-includes/js/mce-view$suffix.js", array( 'shortcode', 'media-models' ), false, 1 );
    395395