WordPress.org

Make WordPress Core

Changeset 27445


Ignore:
Timestamp:
03/06/2014 10:54:32 PM (6 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.