Make WordPress Core

Changeset 29490


Ignore:
Timestamp:
08/14/2014 06:30:49 PM (12 years ago)
Author:
wonderboymusic
Message:

Media Grid, support MEDIA_TRASH:

  • Add a setting to _wpMediaViewsL10n.settings: mediaTrash
  • In the attachment edit modal, properly toggle between Trash/Untrash
  • In media.view.Attachment, add a method for untrashAttachment
  • When creating the grid toolbar, switch the setting order of subviews so that media.view.DeleteSelectedButton can listen to the instance of media.view.AttachmentFilters.All to update the text in its UI.
  • Add a new filter to media.view.AttachmentFilters.All, trash, when settings.mediaTrash is true
  • Allow the cached queries in Query.get() to be flushed when race conditions exist and collections need to be refreshed. This is currently only being used when MEDIA_TRASH is set, to refresh the filtered/mirrored collections related to all, trash, and any already queried filter.
  • Cleanup the bootstrapping of media.view.MediaFrame.Manage
  • Allow wp_ajax_query_attachments() to return items from the trash when MEDIA_TRASH is true
  • Allow wp_ajax_save_attachment() to set post_status when MEDIA_TRASH is true. It allows wp_delete_post() to be called, which will trash the attachment instead of deleting when the flag is set.

Props koop for the knowledge sharing and thought partnership.
See #29145.

Location:
trunk/src
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/ajax-actions.php

    r29454 r29490  
    21622162
    21632163        $query['post_type'] = 'attachment';
    2164         $query['post_status'] = 'inherit';
     2164        if ( MEDIA_TRASH
     2165                && ! empty( $_REQUEST['query']['post_status'] )
     2166                && 'trash' === $_REQUEST['query']['post_status'] ) {
     2167                $query['post_status'] = 'trash';
     2168        } else {
     2169                $query['post_status'] = 'inherit';
     2170        }
     2171
    21652172        if ( current_user_can( get_post_type_object( 'attachment' )->cap->read_private_posts ) )
    21662173                $query['post_status'] .= ',private';
     
    22162223        if ( isset( $changes['description'] ) )
    22172224                $post['post_content'] = $changes['description'];
     2225
     2226        if ( MEDIA_TRASH && isset( $changes['status'] ) )
     2227                $post['post_status'] = $changes['status'];
    22182228
    22192229        if ( isset( $changes['alt'] ) ) {
     
    22442254        }
    22452255
    2246         wp_update_post( $post );
     2256        if ( MEDIA_TRASH && isset( $changes['status'] ) && 'trash' === $changes['status'] ) {
     2257                wp_delete_post( $id );
     2258        } else {
     2259                wp_update_post( $post );
     2260        }
     2261
    22472262        wp_send_json_success();
    22482263}
  • trunk/src/wp-includes/css/media-views.css

    r29489 r29490  
    16041604.attachment-info .refresh-attachment,
    16051605.attachment-info .delete-attachment,
    1606 .attachment-info .trash-attachment {
     1606.attachment-info .trash-attachment,
     1607.attachment-info .untrash-attachment {
    16071608        display: block;
    16081609        text-decoration: none;
     
    16211622
    16221623.media-modal .delete-attachment,
    1623 .media-modal .trash-attachment {
     1624.media-modal .trash-attachment,
     1625.media-modal .untrash-attachment {
    16241626        color: #bc0b0b;
    16251627}
    16261628
    16271629.media-modal .delete-attachment:hover,
    1628 .media-modal .trash-attachment:hover {
     1630.media-modal .trash-attachment:hover,
     1631.media-modal .untrash-attachment:hover {
    16291632        color: red;
    16301633}
     
    27442747}
    27452748
    2746 .edit-attachment-frame .delete-attachment {
     2749.edit-attachment-frame .delete-attachment,
     2750.edit-attachment-frame .trash-attachment,
     2751.edit-attachment-frame .untrash-attachment {
    27472752        float: right;
    27482753        margin-top: 7px;
  • trunk/src/wp-includes/js/media-grid.js

    r29489 r29490  
    184184                        wp.media( {
    185185                                frame:       'edit-attachments',
    186                                 gridRouter:  this.gridRouter,
     186                                controller:  this,
    187187                                library:     this.state().get('library'),
    188188                                model:       model
     
    231231
    232232                bindDeferred: function() {
     233                        if ( ! this.browserView.dfd ) {
     234                                return;
     235                        }
    233236                        this.browserView.dfd.done( _.bind( this.startHistory, this ) );
    234237                },
     
    353356
    354357                events: {
    355                         'click':                    'collapse',
    356                         'click .delete-media-item': 'deleteMediaItem',
    357358                        'click .left':              'previousMediaItem',
    358359                        'click .right':             'nextMediaItem'
     
    360361
    361362                initialize: function() {
    362                         var self = this;
    363 
    364363                        media.view.Frame.prototype.initialize.apply( this, arguments );
    365364
     
    369368                        });
    370369
    371                         this.gridRouter = this.options.gridRouter;
    372 
     370                        this.controller = this.options.controller;
     371                        this.gridRouter = this.controller.gridRouter;
    373372                        this.library = this.options.library;
    374373
     
    376375                                this.model = this.options.model;
    377376                        } else {
     377                                // this is a hack
    378378                                this.model = this.library.at( 0 );
    379379                        }
    380380
     381                        this.bindHandlers();
     382                        this.createStates();
     383                        this.createModal();
     384
     385                        this.title.mode( 'default' );
     386
     387                        this.options.hasPrevious = this.hasPrevious();
     388                        this.options.hasNext = this.hasNext();
     389                },
     390
     391                bindHandlers: function() {
     392                        // Bind default title creation.
     393                        this.on( 'title:create:default', this.createTitle, this );
     394
    381395                        // Close the modal if the attachment is deleted.
    382                         this.listenTo( this.model, 'destroy', this.close, this );
    383 
    384                         this.createStates();
     396                        this.listenTo( this.model, 'change:status destroy', this.close, this );
    385397
    386398                        this.on( 'content:create:edit-metadata', this.editMetadataMode, this );
     
    388400                        this.on( 'content:render:edit-image', this.editImageModeRender, this );
    389401                        this.on( 'close', this.detach );
    390 
    391                         // Bind default title creation.
    392                         this.on( 'title:create:default', this.createTitle, this );
    393                         this.title.mode( 'default' );
    394 
    395                         this.options.hasPrevious = this.hasPrevious();
    396                         this.options.hasNext = this.hasNext();
     402                },
     403
     404                createModal: function() {
     405                        var self = this;
    397406
    398407                        // Initialize modal container view.
     
    610619                initialize: function() {
    611620                        media.view.Button.prototype.initialize.apply( this, arguments );
     621                        if ( this.options.filters ) {
     622                                this.listenTo( this.options.filters.model, 'change', this.filterChange );
     623                        }
    612624                        this.listenTo( this.controller, 'selection:toggle', this.toggleDisabled );
    613625                },
    614626
     627                filterChange: function( model ) {
     628                        if ( 'trash' === model.get( 'status' ) ) {
     629                                this.model.set( 'text', l10n.untrashSelected );
     630                        } else if ( media.view.settings.mediaTrash ) {
     631                                this.model.set( 'text', l10n.trashSelected );
     632                        } else {
     633                                this.model.set( 'text', l10n.deleteSelected );
     634                        }
     635                },
     636
    615637                toggleDisabled: function() {
    616                         this.$el.attr( 'disabled', ! this.controller.state().get( 'selection' ).length );
     638                        this.model.set( 'disabled', ! this.controller.state().get( 'selection' ).length );
    617639                },
    618640
    619641                render: function() {
    620642                        media.view.Button.prototype.render.apply( this, arguments );
    621                         this.$el.addClass( 'delete-selected-button hidden' );
     643                        if ( this.controller.isModeActive( 'select' ) ) {
     644                                this.$el.addClass( 'delete-selected-button' );
     645                        } else {
     646                                this.$el.addClass( 'delete-selected-button hidden' );
     647                        }
    622648                        return this;
    623649                }
  • trunk/src/wp-includes/js/media-models.js

    r29076 r29490  
    825825                 * @access private
    826826                 */
    827                 _requery: function() {
     827                _requery: function( cache ) {
     828                        var props;
    828829                        if ( this.props.get('query') ) {
    829                                 this.mirror( Query.get( this.props.toJSON() ) );
     830                                props = this.props.toJSON();
     831                                props.cache = ( true !== cache );
     832                                this.mirror( Query.get( props ) );
    830833                        }
    831834                },
     
    948951
    949952                                return uploadedTo === attachment.get('uploadedTo');
     953                        },
     954                        /**
     955                         * @static
     956                         * @param {wp.media.model.Attachment} attachment
     957                         *
     958                         * @this wp.media.model.Attachments
     959                         *
     960                         * @returns {Boolean}
     961                         */
     962                        status: function( attachment ) {
     963                                var status = this.props.get('status');
     964                                if ( _.isUndefined( status ) ) {
     965                                        return true;
     966                                }
     967
     968                                return status === attachment.get('status');
    950969                        }
    951970                }
     
    11451164                        'perPage':   'posts_per_page',
    11461165                        'menuOrder': 'menu_order',
    1147                         'uploadedTo': 'post_parent'
     1166                        'uploadedTo': 'post_parent',
     1167                        'status':     'post_status'
    11481168                },
    11491169                /**
     
    11701190                                        orderby  = Query.orderby,
    11711191                                        defaults = Query.defaultProps,
    1172                                         query;
     1192                                        query,
     1193                                        cache    = !! props.cache;
    11731194
    11741195                                // Remove the `query` property. This isn't linked to a query,
    11751196                                // this *is* the query.
    11761197                                delete props.query;
     1198                                delete props.cache;
    11771199
    11781200                                // Fill default args.
     
    12081230
    12091231                                // Search the query cache for matches.
    1210                                 query = _.find( queries, function( query ) {
    1211                                         return _.isEqual( query.args, args );
    1212                                 });
     1232                                if ( cache ) {
     1233                                        query = _.find( queries, function( query ) {
     1234                                                return _.isEqual( query.args, args );
     1235                                        });
     1236                                } else {
     1237                                        queries = [];
     1238                                }
    12131239
    12141240                                // Otherwise, create a new query and add it to the cache.
  • trunk/src/wp-includes/js/media-views.js

    r29484 r29490  
    56725672                                        text: text,
    56735673                                        props: {
     5674                                                status:  null,
    56745675                                                type:    key,
    56755676                                                uploadedTo: null,
     
    56835684                                text:  l10n.allMediaItems,
    56845685                                props: {
     5686                                        status:  null,
    56855687                                        type:    null,
    56865688                                        uploadedTo: null,
     
    56955697                                        text:  l10n.uploadedToThisPost,
    56965698                                        props: {
     5699                                                status:  null,
    56975700                                                type:    null,
    56985701                                                uploadedTo: media.view.settings.post.id,
     
    57075710                                text:  l10n.unattached,
    57085711                                props: {
     5712                                        status:     null,
    57095713                                        uploadedTo: 0,
    57105714                                        type:       null,
     
    57145718                                priority: 50
    57155719                        };
     5720
     5721                        if ( media.view.settings.mediaTrash ) {
     5722                                filters.trash = {
     5723                                        text:  l10n.trash,
     5724                                        props: {
     5725                                                uploadedTo: null,
     5726                                                status:     'trash',
     5727                                                type:       null,
     5728                                                orderby:    'date',
     5729                                                order:      'DESC'
     5730                                        },
     5731                                        priority: 50
     5732                                };
     5733                        }
    57165734
    57175735                        this.filters = filters;
     
    57665784
    57675785                createToolbar: function() {
    5768                         var filters,
    5769                                 LibraryViewSwitcher,
    5770                                 FiltersConstructor;
     5786                        var LibraryViewSwitcher, Filters;
    57715787
    57725788                        /**
     
    57785794
    57795795                        this.views.add( this.toolbar );
     5796
     5797                        this.toolbar.set( 'spinner', new media.view.Spinner({
     5798                                priority: -60
     5799                        }) );
     5800
     5801                        if ( -1 !== $.inArray( this.options.filters, [ 'uploaded', 'all' ] ) ) {
     5802                                // "Filters" will return a <select>, need to render
     5803                                // screen reader text before
     5804                                this.toolbar.set( 'filtersLabel', new media.view.Label({
     5805                                        value: l10n.filterByType,
     5806                                        attributes: {
     5807                                                'for':  'media-attachment-filters'
     5808                                        },
     5809                                        priority:   -80
     5810                                }).render() );
     5811
     5812                                if ( 'uploaded' === this.options.filters ) {
     5813                                        this.toolbar.set( 'filters', new media.view.AttachmentFilters.Uploaded({
     5814                                                controller: this.controller,
     5815                                                model:      this.collection.props,
     5816                                                priority:   -80
     5817                                        }).render() );
     5818                                } else {
     5819                                        Filters = new media.view.AttachmentFilters.All({
     5820                                                controller: this.controller,
     5821                                                model:      this.collection.props,
     5822                                                priority:   -80
     5823                                        });
     5824
     5825                                        this.toolbar.set( 'filters', Filters.render() );
     5826                                }
     5827                        }
    57805828
    57815829                        // Feels odd to bring the global media library switcher into the Attachment
     
    58155863
    58165864                                this.toolbar.set( 'deleteSelectedButton', new media.view.DeleteSelectedButton({
     5865                                        filters: Filters,
    58175866                                        style: 'primary',
    58185867                                        disabled: true,
    5819                                         text: l10n.deleteSelected,
     5868                                        text: media.view.settings.mediaTrash ? l10n.trashSelected : l10n.deleteSelected,
    58205869                                        controller: this.controller,
    58215870                                        priority: -60,
    58225871                                        click: function() {
    5823                                                 while ( this.controller.state().get( 'selection' ).length > 0 ) {
    5824                                                         this.controller.state().get( 'selection' ).at( 0 ).destroy();
     5872                                                var model, changed = [],
     5873                                                        selection = this.controller.state().get( 'selection' ),
     5874                                                        library = this.controller.state().get( 'library' );
     5875
     5876                                                while ( selection.length > 0 ) {
     5877                                                        model = selection.at( 0 );
     5878                                                        if ( media.view.settings.mediaTrash && 'trash' === model.get( 'status' ) ) {
     5879                                                                model.set( 'status', 'inherit' );
     5880                                                                changed.push( model.save() );
     5881                                                                selection.remove( model );
     5882                                                        } else if ( media.view.settings.mediaTrash ) {
     5883                                                                model.set( 'status', 'trash' );
     5884                                                                changed.push( model.save() );
     5885                                                                selection.remove( model );
     5886                                                        } else {
     5887                                                                model.destroy();
     5888                                                        }
     5889                                                }
     5890
     5891                                                if ( changed.length ) {
     5892                                                        $.when( changed ).then( function() {
     5893                                                                library._requery( true );
     5894                                                        } );
    58255895                                                }
    58265896                                        }
    5827                                 }).render() );
    5828                         }
    5829 
    5830                         this.toolbar.set( 'spinner', new media.view.Spinner({
    5831                                 priority: -60
    5832                         }) );
    5833 
    5834                         filters = this.options.filters;
    5835                         if ( 'uploaded' === filters ) {
    5836                                 FiltersConstructor = media.view.AttachmentFilters.Uploaded;
    5837                         } else if ( 'all' === filters ) {
    5838                                 FiltersConstructor = media.view.AttachmentFilters.All;
    5839                         }
    5840 
    5841                         if ( FiltersConstructor ) {
    5842                                 // "FiltersConstructor" will return a <select>, need to render
    5843                                 // screen reader text before
    5844                                 this.toolbar.set( 'filtersLabel', new media.view.Label({
    5845                                         value: l10n.filterByType,
    5846                                         attributes: {
    5847                                                 'for':  'media-attachment-filters'
    5848                                         },
    5849                                         priority:   -80
    5850                                 }).render() );
    5851                                 this.toolbar.set( 'filters', new FiltersConstructor({
    5852                                         controller: this.controller,
    5853                                         model:      this.collection.props,
    5854                                         priority:   -80
    58555897                                }).render() );
    58565898                        }
     
    64216463                        'click .delete-attachment':       'deleteAttachment',
    64226464                        'click .trash-attachment':        'trashAttachment',
     6465                        'click .untrash-attachment':      'untrashAttachment',
    64236466                        'click .edit-attachment':         'editAttachment',
    64246467                        'click .refresh-attachment':      'refreshAttachment',
     
    64546497                 */
    64556498                trashAttachment: function( event ) {
     6499                        var library = this.controller.library;
    64566500                        event.preventDefault();
    64576501
    6458                         this.model.destroy();
     6502                        if ( media.view.settings.mediaTrash ) {
     6503                                this.model.set( 'status', 'trash' );
     6504                                this.model.save().done( function() {
     6505                                        library._requery( true );
     6506                                } );
     6507                        }  else {
     6508                                this.model.destroy();
     6509                        }
     6510                },
     6511                /**
     6512                 * @param {Object} event
     6513                 */
     6514                untrashAttachment: function( event ) {
     6515                        var library = this.controller.library;
     6516                        event.preventDefault();
     6517
     6518                        this.model.set( 'status', 'inherit' );
     6519                        this.model.save().done( function() {
     6520                                library._requery( true );
     6521                        } );
    64596522                },
    64606523                /**
  • trunk/src/wp-includes/media-template.php

    r29457 r29490  
    317317                                        <# if ( ! data.uploading && data.can.remove ) { #>
    318318                                                <?php if ( MEDIA_TRASH ): ?>
     319                                                <# if ( 'trash' === data.status ) { #>
     320                                                        <a class="untrash-attachment" href="#"><?php _e( 'Untrash' ); ?></a>
     321                                                <# } else { #>
    319322                                                        <a class="trash-attachment" href="#"><?php _e( 'Trash' ); ?></a>
     323                                                <# } #>
    320324                                                <?php else: ?>
    321325                                                        <a class="delete-attachment" href="#"><?php _e( 'Delete Permanently' ); ?></a>
  • trunk/src/wp-includes/media.php

    r29486 r29490  
    28702870                'contentWidth' => $content_width,
    28712871                'months'       => $months,
     2872                'mediaTrash'   => MEDIA_TRASH ? 1 : 0
    28722873        );
    28732874
     
    29322933                'insertIntoPost'         => $hier ? __( 'Insert into page' ) : __( 'Insert into post' ),
    29332934                'unattached'             => __( 'Unattached' ),
     2935                'trash'                  => __( 'Trash' ),
    29342936                'uploadedToThisPost'     => $hier ? __( 'Uploaded to this page' ) : __( 'Uploaded to this post' ),
    29352937                'warnDelete'             => __( "You are about to permanently delete this item.\n  'Cancel' to stop, 'OK' to delete." ),
     
    29372939                'bulkSelect'             => __( 'Bulk Select' ),
    29382940                'cancelSelection'        => __( 'Cancel Selection' ),
     2941                'trashSelected'          => __( 'Trash Selected' ),
     2942                'untrashSelected'        => __( 'Untrash Selected' ),
    29392943                'deleteSelected'         => __( 'Delete Selected' ),
    29402944                'deletePermanently'      => __( 'Delete Permanently' ),
Note: See TracChangeset for help on using the changeset viewer.