Make WordPress Core

Changeset 27445


Ignore:
Timestamp:
03/06/2014 10:54:32 PM (12 years ago)
Author:
helen
Message:

At long last, a first pass at bringing the image editor into the media modal. props gcorne, DH-Shredder, tomauger. see #21811.

Location:
trunk/src
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/js/image-edit.js

    r26425 r27445  
    66        hold : {},
    77        postid : '',
     8        _view : false,
    89
    910        intval : function(f) {
     
    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 ) {
     
    284292                        }
    285293
    286                         imageEdit.close(postid);
    287                 });
    288         },
    289 
    290         open : function(postid, nonce) {
     294                        if ( self._view ) {
     295                                self._view.save();
     296                        } else {
     297                                imageEdit.close(postid);
     298                        }
     299                });
     300        },
     301
     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');
     
    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({
     
    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;
     
    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
  • trunk/src/wp-includes/css/media-views.css

    r27438 r27445  
    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 */
     
    14891505        max-height: 200px;
    14901506        display: block;
     1507}
     1508
     1509.media-embed .edit-attachment {
     1510        margin-left: 10px;
    14911511}
    14921512
  • trunk/src/wp-includes/js/media-editor.js

    r27435 r27445  
    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
     
    709709                                        text: wp.media.view.l10n.setFeaturedImage
    710710                                });
     711                        }, this._frame );
     712
     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
    711722                        }, this._frame );
    712723
  • trunk/src/wp-includes/js/media-models.js

    r27435 r27445  
    372372                bindAttachmentListeners: function() {
    373373                        this.listenTo( this.attachment, 'sync', this.setLinkTypeFromUrl );
     374                        this.listenTo( this.attachment, 'change', this.updateSize );
    374375                },
    375376
  • trunk/src/wp-includes/js/media-views.js

    r27443 r27445  
    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
     
    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                /**
     
    734737                }
    735738        });
     739
     740        _.extend( media.controller.Library.prototype, media.selectionSync );
    736741
    737742        /**
     
    990995                        title:      l10n.setFeaturedImageTitle,
    991996                        priority:   60,
    992                         syncSelection: false
     997                        syncSelection: true
    993998                }, media.controller.Library.prototype.defaults ),
    994999
     
    10711076                        title:      l10n.replaceImageTitle,
    10721077                        priority:   60,
    1073                         syncSelection: false
     1078                        syncSelection: true
    10741079                }, media.controller.Library.prototype.defaults ),
    10751080
     
    11201125                }
    11211126        });
     1127
     1128        /**
     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 );
    11221184
    11231185        /**
     
    19281990                                // Embed states.
    19291991                                new media.controller.Embed(),
     1992
     1993                                new media.controller.EditImage( { selection: options.selection } ),
    19301994
    19311995                                // Gallery states.
     
    20442108                                content: {
    20452109                                        'embed':          'embedContent',
     2110                                        'edit-image':     'editImageContent',
    20462111                                        'edit-selection': 'editSelectionContent'
    20472112                                },
     
    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
     
    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 );
     
    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                },
     
    25752656
    25762657                },
     2658
     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
    25772684
    25782685                renderMenu: function( view ) {
     
    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                /**
     
    58765984                        this.model.fetch();
    58775985                }
     5986
    58785987        });
    58795988
     
    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                },
     
    61776291                        }, this.options );
    61786292                },
    6179 
    61806293
    61816294                render: function() {
     
    61996312                        this.$( '.caption textarea' ).focus();
    62006313                        this.$( '.embed-image-settings' ).scrollTop( 0 );
    6201                 }
     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                        });
     6368                }
     6369
    62026370        });
    62036371
  • trunk/src/wp-includes/media-template.php

    r27440 r27445  
    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">
     
    648651                        </div>
    649652                </div>
     653        </script>
     654
     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>
    650658        </script>
    651659
  • trunk/src/wp-includes/media.php

    r27411 r27445  
    21762176                        'update' => false,
    21772177                        'delete' => false,
     2178                        'edit'   => false
    21782179                ),
    21792180                'editLink'   => false,
     
    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        }
     
    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
     
    23812384                'imageReplaceTitle'     => __( 'Replace Image' ),
    23822385                'imageDetailsCancel'    => __( 'Cancel Edit' ),
     2386                'editImage'             => __( 'Edit Image' ),
    23832387
    23842388                // Edit Image
     
    24222426        wp_enqueue_script( 'media-editor' );
    24232427        wp_enqueue_style( 'media-views' );
     2428        wp_enqueue_style( 'imgareaselect' );
    24242429        wp_plupload_default_settings();
    24252430
  • trunk/src/wp-includes/script-loader.php

    r27411 r27445  
    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 );
  • trunk/src/wp-includes/version.php

    r27408 r27445  
    55 * @global string $wp_version
    66 */
    7 $wp_version = '3.9-alpha-27368-src';
     7$wp_version = '3.9-alpha-27445-src';
    88
    99/**
Note: See TracChangeset for help on using the changeset viewer.