WordPress.org

Make WordPress Core

Changeset 29490


Ignore:
Timestamp:
08/14/14 18:30:49 (3 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.