WordPress.org

Make WordPress Core

Ticket #21811: 21811-07.patch

File 21811-07.patch, 17.7 KB (added by gcorne, 6 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..90016c1 100644
    var imageEdit = window.imageEdit = { 
    55        iasapi : {},
    66        hold : {},
    77        postid : '',
     8        _view : {},
    89
    910        intval : function(f) {
    1011                return f | 0;
    var imageEdit = window.imageEdit = { 
    245246        },
    246247
    247248        save : function(postid, nonce) {
    248                 var data, target = this.getTarget(postid), history = this.filterHistory(postid, 0);
     249                var data,
     250                        target = this.getTarget(postid),
     251                        history = this.filterHistory(postid, 0),
     252                        self = this;
    249253
    250254                if ( '' === history ) {
    251255                        return false;
    var imageEdit = window.imageEdit = { 
    283287                                $('#imgedit-response-' + postid).html('<div class="updated"><p>' + ret.msg + '</p></div>');
    284288                        }
    285289
    286                         imageEdit.close(postid);
     290                        if ( self._view ) {
     291                                self._view.save();
     292                        } else {
     293                                imageEdit.close(postid);
     294                        }
    287295                });
    288296        },
    289297
    290         open : function(postid, nonce) {
     298        open : function( postid, nonce, view ) {
     299                this._view = view;
     300
    291301                var data, elem = $('#image-editor-' + postid), head = $('#media-head-' + postid),
    292302                        btn = $('#imgedit-open-btn-' + postid), spin = btn.siblings('.spinner');
    293303
    var imageEdit = window.imageEdit = { 
    319329        },
    320330
    321331        initCrop : function(postid, image, parent) {
    322                 var t = this, selW = $('#imgedit-sel-width-' + postid),
    323                         selH = $('#imgedit-sel-height-' + postid);
     332                var t = this,
     333                        selW = $('#imgedit-sel-width-' + postid),
     334                        selH = $('#imgedit-sel-height-' + postid),
     335                        $img;
    324336
    325337                t.iasapi = $(image).imgAreaSelect({
    326338                        parent: parent,
    var imageEdit = window.imageEdit = { 
    330342                        minWidth: 3,
    331343                        minHeight: 3,
    332344
    333                         onInit: function() {
     345                        onInit: function( img ) {
     346                                // Ensure that the imgareaselect wrapper elements are position:absolute
     347                                // (even if we're in a position:fixed modal)
     348                                $img = $( img );
     349                                $img.next().css( 'position', 'absolute' )
     350                                        .nextAll( '.imgareaselect-outer' ).css( 'position', 'absolute' );
     351
    334352                                parent.children().mousedown(function(e){
    335353                                        var ratio = false, sel, defRatio;
    336354
    var imageEdit = window.imageEdit = { 
    397415
    398416                this.iasapi = {};
    399417                this.hold = {};
    400                 $('#image-editor-' + postid).fadeOut('fast', function() {
    401                         $('#media-head-' + postid).fadeIn('fast');
    402                         $(this).empty();
    403                 });
     418
     419                // If we've loaded the editor in the context of a Media Modal, then switch to the previous view,
     420                // whatever that might have been.
     421                if ( this._view && 'object' === typeof this._view ){
     422                        this._view.back();
     423                }
     424
     425                // In case we are not accessing the image editor in the context of a View, close the editor the old-skool way
     426                else {
     427                        $('#image-editor-' + postid).fadeOut('fast', function() {
     428                                $('#media-head-' + postid).fadeIn('fast');
     429                                $(this).empty();
     430                        });
     431                }
     432
     433
    404434        },
    405435
    406436        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 6d9d9b0..3259fd2 100644
     
    14861486        display: block;
    14871487}
    14881488
     1489.media-embed .edit-attachment {
     1490        margin-left: 10px;
     1491}
     1492
    14891493.media-embed .thumbnail:after {
    14901494        content: '';
    14911495        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 ec13796..b2dfd15 100644
     
    648648
    649649                        this._frame = wp.media({
    650650                                state: 'featured-image',
    651                                 states: [ new wp.media.controller.FeaturedImage() ]
     651                                states: [ new wp.media.controller.FeaturedImage() , new wp.media.controller.EditImage() ]
    652652                        });
    653653
    654654                        this._frame.on( 'toolbar:create:featured-image', function( toolbar ) {
     
    660660                                });
    661661                        }, this._frame );
    662662
     663                        this._frame.on( 'content:render:edit-image', function() {
     664                                var selection = this.state('featured-image').get('selection'),
     665                                        view = new wp.media.view.EditImage( { model: selection.single(), controller: this } ).render();
     666
     667                                this.content.set( view );
     668
     669                                // after bringing in the frame, load the actual editor via an ajax call
     670                                view.loadEditor();
     671
     672                        }, this._frame );
     673
    663674                        this._frame.state('featured-image').on( 'select', this.select );
    664675                        return this._frame;
    665676                },
  • src/wp-includes/js/media-models.js

    diff --git src/wp-includes/js/media-models.js src/wp-includes/js/media-models.js
    index 5363ffe..2580793 100644
    window.wp = window.wp || {}; 
    367367
    368368                bindAttachmentListeners: function() {
    369369                        this.listenTo( this.attachment, 'sync', this.setLinkTypeFromUrl );
     370                        this.listenTo( this.attachment, 'change', this.updateSize );
    370371                },
    371372
    372373                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 db5ea30..6662c73 100644
     
    482482                };
    483483        });
    484484
     485        media.selectionSync = {
     486                syncSelection: function() {
     487                        var selection = this.get('selection'),
     488                                manager = this.frame._selection;
     489
     490                        if ( ! this.get('syncSelection') || ! manager || ! selection ) {
     491                                return;
     492                        }
     493
     494                        // If the selection supports multiple items, validate the stored
     495                        // attachments based on the new selection's conditions. Record
     496                        // the attachments that are not included; we'll maintain a
     497                        // reference to those. Other attachments are considered in flux.
     498                        if ( selection.multiple ) {
     499                                selection.reset( [], { silent: true });
     500                                selection.validateAll( manager.attachments );
     501                                manager.difference = _.difference( manager.attachments.models, selection.models );
     502                        }
     503
     504                        // Sync the selection's single item with the master.
     505                        selection.single( manager.single );
     506                },
     507
     508                /**
     509                 * Record the currently active attachments, which is a combination
     510                 * of the selection's attachments and the set of selected
     511                 * attachments that this specific selection considered invalid.
     512                 * Reset the difference and record the single attachment.
     513                 */
     514                recordSelection: function() {
     515                        var selection = this.get('selection'),
     516                                manager = this.frame._selection;
     517
     518                        if ( ! this.get('syncSelection') || ! manager || ! selection ) {
     519                                return;
     520                        }
     521
     522                        if ( selection.multiple ) {
     523                                manager.attachments.reset( selection.toArray().concat( manager.difference ) );
     524                                manager.difference = [];
     525                        } else {
     526                                manager.attachments.add( selection.toArray() );
     527                        }
     528
     529                        manager.single = selection._single;
     530                }
     531        };
     532
    485533        /**
    486534         * wp.media.controller.Library
    487535         *
     
    634682                        return _.contains( media.view.settings.embedExts, attachment.get('filename').split('.').pop() );
    635683                },
    636684
    637                 syncSelection: function() {
    638                         var selection = this.get('selection'),
    639                                 manager = this.frame._selection;
    640 
    641                         if ( ! this.get('syncSelection') || ! manager || ! selection ) {
    642                                 return;
    643                         }
    644 
    645                         // If the selection supports multiple items, validate the stored
    646                         // attachments based on the new selection's conditions. Record
    647                         // the attachments that are not included; we'll maintain a
    648                         // reference to those. Other attachments are considered in flux.
    649                         if ( selection.multiple ) {
    650                                 selection.reset( [], { silent: true });
    651                                 selection.validateAll( manager.attachments );
    652                                 manager.difference = _.difference( manager.attachments.models, selection.models );
    653                         }
    654 
    655                         // Sync the selection's single item with the master.
    656                         selection.single( manager.single );
    657                 },
    658 
    659                 /**
    660                  * Record the currently active attachments, which is a combination
    661                  * of the selection's attachments and the set of selected
    662                  * attachments that this specific selection considered invalid.
    663                  * Reset the difference and record the single attachment.
    664                  */
    665                 recordSelection: function() {
    666                         var selection = this.get('selection'),
    667                                 manager = this.frame._selection;
    668 
    669                         if ( ! this.get('syncSelection') || ! manager || ! selection ) {
    670                                 return;
    671                         }
    672 
    673                         if ( selection.multiple ) {
    674                                 manager.attachments.reset( selection.toArray().concat( manager.difference ) );
    675                                 manager.difference = [];
    676                         } else {
    677                                 manager.attachments.add( selection.toArray() );
    678                         }
    679 
    680                         manager.single = selection._single;
    681                 },
    682685
    683686                /**
    684687                 * If the state is active, no items are selected, and the current
     
    733736                }
    734737        });
    735738
     739        _.extend( media.controller.Library.prototype, media.selectionSync );
     740
    736741        /**
    737742         * wp.media.controller.ImageDetails
    738743         *
     
    10001005                        toolbar:    'featured-image',
    10011006                        title:      l10n.setFeaturedImageTitle,
    10021007                        priority:   60,
    1003                         syncSelection: false
     1008                        syncSelection: true
    10041009                }, media.controller.Library.prototype.defaults ),
    10051010
    10061011                initialize: function() {
     
    10811086                        toolbar:    'replace',
    10821087                        title:      l10n.replaceImageTitle,
    10831088                        priority:   60,
    1084                         syncSelection: false
     1089                        syncSelection: true
    10851090                }, media.controller.Library.prototype.defaults ),
    10861091
    10871092                initialize: function( options ) {
     
    11321137        });
    11331138
    11341139        /**
     1140         * wp.media.controller.EditImage
     1141         *
     1142         * @constructor
     1143         * @augments wp.media.controller.State
     1144         * @augments Backbone.Model
     1145         */
     1146        media.controller.EditImage = media.controller.State.extend({
     1147                defaults: {
     1148                        id: 'edit-image',
     1149                        url: '',
     1150                        menu: false,
     1151                        title: l10n.editImage,
     1152                        content: 'edit-image',
     1153                        syncSelection: true
     1154                },
     1155
     1156                activate: function() {
     1157                        if ( ! this.get('selection') ) {
     1158                                this.set( 'selection', new media.model.Selection() );
     1159                        }
     1160                        this.syncSelection();
     1161                }
     1162        });
     1163
     1164        _.extend( media.controller.EditImage.prototype, media.selectionSync );
     1165
     1166
     1167        /**
    11351168         * wp.media.controller.Embed
    11361169         *
    11371170         * @constructor
     
    18031836                                // Embed states.
    18041837                                new media.controller.Embed(),
    18051838
     1839                                new media.controller.EditImage( { selection: options.selection } ),
     1840
    18061841                                // Gallery states.
    18071842                                new media.controller.GalleryEdit({
    18081843                                        library: options.selection,
     
    18901925
    18911926                                content: {
    18921927                                        'embed':          'embedContent',
     1928                                        'edit-image':     'editImageContent',
    18931929                                        'edit-selection': 'editSelectionContent'
    18941930                                },
    18951931
     
    20402076                        this.content.set( view );
    20412077                },
    20422078
     2079                editImageContent: function() {
     2080                        var selection = this.state().get('selection'),
     2081                                view = new media.view.EditImage( { model: selection.single(), controller: this } ).render();
     2082
     2083                        this.content.set( view );
     2084
     2085                        // after bringing in the frame, load the actual editor via an ajax call
     2086                        view.loadEditor();
     2087
     2088                },
     2089
    20432090                // Toolbars
    20442091
    20452092                /**
     
    23702417                        media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
    23712418                        this.on( 'menu:create:image-details', this.createMenu, this );
    23722419                        this.on( 'content:render:image-details', this.renderImageDetailsContent, this );
     2420                        this.on( 'content:render:edit-image', this.editImageContent, this );
    23732421                        this.on( 'menu:render:image-details', this.renderMenu, this );
    23742422                        this.on( 'toolbar:render:image-details', this.renderImageDetailsToolbar, this );
    23752423                        // override the select toolbar
     
    23872435                                        id: 'replace-image',
    23882436                                        library:   media.query( { type: 'image' } ),
    23892437                                        image: this.image,
     2438                                        selection: this.options.selection,
    23902439                                        multiple:  false,
    23912440                                        title:     l10n.imageReplaceTitle,
    23922441                                        menu: 'image-details',
    23932442                                        toolbar: 'replace',
    23942443                                        priority:  80,
    23952444                                        displaySettings: true
    2396                                 })
     2445                                }),
     2446                                new media.controller.EditImage( { image: this.image, selection: this.options.selection } )
    23972447                        ]);
    23982448                },
    23992449
     
    24332483
    24342484                },
    24352485
     2486                editImageContent: function() {
     2487                        var state = this.state(),
     2488                                attachment = state.get('image').attachment,
     2489                                model,
     2490                                view;
     2491
     2492                        if ( ! attachment ) {
     2493                                return;
     2494                        }
     2495
     2496                        model = state.get('selection').single();
     2497
     2498                        if ( ! model ) {
     2499                                model = attachment;
     2500                        }
     2501
     2502                        view = new media.view.EditImage( { model: model, controller: this } ).render();
     2503
     2504                        this.content.set( view );
     2505
     2506                        // after bringing in the frame, load the actual editor via an ajax call
     2507                        view.loadEditor();
     2508
     2509                },
     2510
    24362511                renderImageDetailsToolbar: function() {
    24372512                        this.toolbar.set( new media.view.Toolbar({
    24382513                                controller: this,
     
    52505325                        }
    52515326                },
    52525327
    5253                 editAttachment: function() {
    5254                         this.$el.addClass('needs-refresh');
     5328                editAttachment: function( event ) {
     5329                        event.preventDefault();
     5330                        this.controller.setState( 'edit-image' );
    52555331                },
    52565332                /**
    52575333                 * @param {Object} event
     
    52615337                        event.preventDefault();
    52625338                        this.model.fetch();
    52635339                }
     5340
    52645341        });
    52655342
    52665343        /**
     
    55345611        media.view.ImageDetails = media.view.Settings.AttachmentDisplay.extend({
    55355612                className: 'image-details',
    55365613                template:  media.template('image-details'),
    5537 
     5614                events: _.defaults( media.view.Settings.AttachmentDisplay.prototype.events, {
     5615                        'click .edit-attachment': 'editAttachment'
     5616                } ),
    55385617                initialize: function() {
    55395618                        // used in AttachmentDisplay.prototype.updateLinkTo
    55405619                        this.options.attachment = this.model.attachment;
     5620                        if ( this.model.attachment ) {
     5621                                this.listenTo( this.model.attachment, 'change:url', this.updateUrl );
     5622                        }
    55415623                        media.view.Settings.AttachmentDisplay.prototype.initialize.apply( this, arguments );
    55425624                },
    55435625
     
    55535635                        }, this.options );
    55545636                },
    55555637
    5556 
    55575638                render: function() {
    55585639                        var self = this,
    55595640                                args = arguments;
     
    55745655                resetFocus: function() {
    55755656                        this.$( '.caption textarea' ).focus();
    55765657                        this.$( '.embed-image-settings' ).scrollTop( 0 );
     5658                },
     5659
     5660                updateUrl: function() {
     5661                        this.$( '.thumbnail img' ).attr( 'src', this.model.get('url' ) );
     5662                        this.$( '.url' ).val( this.model.get('url' ) );
     5663                },
     5664
     5665                editAttachment: function( event ) {
     5666                        event.preventDefault();
     5667                        this.controller.setState( 'edit-image' );
    55775668                }
    55785669        });
     5670
     5671
     5672        media.view.EditImage = media.View.extend({
     5673
     5674                className: 'image-editor',
     5675                template: media.template('image-editor'),
     5676
     5677                initialize: function( options ) {
     5678                        this.editor = window.imageEdit;
     5679                        this.controller = options.controller;
     5680                        media.View.prototype.initialize.apply( this, arguments );
     5681                },
     5682
     5683                prepare: function() {
     5684                        return this.model.toJSON();
     5685                },
     5686
     5687                render: function() {
     5688                        media.View.prototype.render.apply( this, arguments );
     5689                        return this;
     5690                },
     5691
     5692                loadEditor: function() {
     5693                        this.editor.open( this.model.get('id'), this.model.get('nonces').edit, this );
     5694                },
     5695
     5696                back: function() {
     5697                        var lastState = this.controller.lastState();
     5698                        this.controller.setState( lastState );
     5699                },
     5700
     5701                save: function() {
     5702                        var self = this,
     5703                                lastState = this.controller.lastState();
     5704
     5705                        this.model.fetch().done( function() {
     5706                                self.controller.setState( lastState );
     5707                        });
     5708                }
     5709
     5710        });
     5711
    55795712}(jQuery));
  • src/wp-includes/media-template.php

    diff --git src/wp-includes/media-template.php src/wp-includes/media-template.php
    index daf8c29..752502c 100644
    function wp_print_media_templates() { 
    560560                                <div class="thumbnail">
    561561                                        <img src="{{ data.model.url }}" draggable="false" />
    562562                                </div>
     563                                <# if ( data.attachment ) { #>
     564                                        <input type="button" class="edit-attachment button" value="<?php esc_attr_e( 'Edit Image' ); ?>" />
     565                                <# } #>
    563566
    564567                                <div class="setting url">
    565568                                        <?php // might want to make the url editable if it isn't an attachment ?>
    function wp_print_media_templates() { 
    649652                        </div>
    650653                </div>
    651654        </script>
     655
     656        <script type="text/html" id="tmpl-image-editor">
     657                <div id="media-head-{{{ data.id }}}"></div>
     658                <div id="image-editor-{{{ data.id }}}"></div>
     659        </script>
    652660        <?php
    653661
    654662        /**
  • src/wp-includes/media.php

    diff --git src/wp-includes/media.php src/wp-includes/media.php
    index ebcfa0e..6b09bc3 100644
    function wp_prepare_attachment_for_js( $attachment ) { 
    21352135                'nonces'      => array(
    21362136                        'update' => false,
    21372137                        'delete' => false,
     2138                        'edit'   => false
    21382139                ),
    21392140                'editLink'   => false,
    21402141        );
    21412142
    21422143        if ( current_user_can( 'edit_post', $attachment->ID ) ) {
    21432144                $response['nonces']['update'] = wp_create_nonce( 'update-post_' . $attachment->ID );
     2145                $response['nonces']['edit'] = wp_create_nonce( 'image_editor-' . $attachment->ID );
    21442146                $response['editLink'] = get_edit_post_link( $attachment->ID, 'raw' );
    21452147        }
    21462148
    function wp_enqueue_media( $args = array() ) { 
    23402342                'imageDetailsTitle'     => __( 'Image Details' ),
    23412343                'imageReplaceTitle'     => __( 'Replace Image' ),
    23422344                'imageDetailsCancel'    => __( 'Cancel Edit' ),
     2345                'editImage'             => __( 'Edit Image' ),
    23432346
    23442347                // Playlist
    23452348                'playlistDragInfo'    => __( 'Drag and drop to reorder tracks.' ),
    function wp_enqueue_media( $args = array() ) { 
    23712374
    23722375        wp_enqueue_script( 'media-editor' );
    23732376        wp_enqueue_style( 'media-views' );
     2377        wp_enqueue_style( 'imgareaselect' );
    23742378        wp_plupload_default_settings();
    23752379
    23762380        require_once ABSPATH . WPINC . '/media-template.php';
    function theme_supports_thumbnails( $post ) { 
    25902594        }
    25912595
    25922596        return current_theme_supports( 'post-thumbnails', $post->post_type );
    2593 }
    2594  No newline at end of file
     2597}
  • src/wp-includes/script-loader.php

    diff --git src/wp-includes/script-loader.php src/wp-includes/script-loader.php
    index d696b13..a3dc3b7 100644
    function wp_default_scripts( &$scripts ) { 
    395395        // To enqueue media-views or media-editor, call wp_enqueue_media().
    396396        // Both rely on numerous settings, styles, and templates to operate correctly.
    397397        $scripts->add( 'media-views',  "/wp-includes/js/media-views$suffix.js",  array( 'utils', 'media-models', 'wp-plupload', 'jquery-ui-sortable' ), false, 1 );
    398         $scripts->add( 'media-editor', "/wp-includes/js/media-editor$suffix.js", array( 'shortcode', 'media-views' ), false, 1 );
     398        $scripts->add( 'media-editor', "/wp-includes/js/media-editor$suffix.js", array( 'shortcode', 'media-views', 'image-edit' ), false, 1 );
    399399        $scripts->add( 'mce-view', "/wp-includes/js/mce-view$suffix.js", array( 'shortcode', 'media-models' ), false, 1 );
    400400
    401401        if ( is_admin() ) {