WordPress.org

Make WordPress Core

Changeset 22323


Ignore:
Timestamp:
10/29/2012 03:13:02 PM (8 years ago)
Author:
koopersmith
Message:

Add attachment details to the media sidebar.

  • Also moves most of the Frame view's createSelection method to a real Selection model (which inherits from the Attachments model).
  • Properly assigns the library within the Gallery state, allowing for the Gallery state to inherit from the Library state.

see #21390.

Location:
trunk/wp-includes
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/wp-includes/css/media-views.css

    r22322 r22323  
    308308}
    309309
    310 .attachment .thumbnail,
    311 .attachment .thumbnail img {
     310.attachment-preview .thumbnail,
     311.attachment-preview .thumbnail img {
    312312    -webkit-transition-property: width, height, top, left, right, bottom;
    313313    -moz-transition-property:    width, height, top, left, right, bottom;
     
    327327}
    328328
    329 .attachment .thumbnail {
     329.attachment-preview .thumbnail {
    330330    width: 199px;
    331331    height: 199px;
    332332}
    333333
    334 .attachment .thumbnail:after {
     334.attachment-preview .thumbnail:after {
    335335    content: '';
    336336    display: block;
     
    389389}
    390390
    391 .attachment .describe {
     391.media-frame .describe {
    392392    position: relative;
    393393    display: block;
     
    594594
    595595/**
     596 * Attachment Details
     597 */
     598
     599.attachment-details {
     600    padding-top: 20px;
     601}
     602
     603.attachment-details-preview {
     604    cursor: default;
     605}
     606
     607.attachment-details-preview,
     608.attachment-details-preview .thumbnail {
     609    width: auto;
     610    height: auto;
     611    float: left;
     612    position: relative;
     613}
     614
     615.attachment-details-preview .thumbnail img {
     616    max-width: 120px;
     617    max-height: 120px;
     618    display: block;
     619    margin: 0 auto;
     620}
     621
     622.attachment-details .describe {
     623    float: left;
     624    margin: 10px 0 0;
     625}
     626
     627/**
    596628 * Attachment Display Settings
    597629 */
  • trunk/wp-includes/js/media-models.js

    r22320 r22323  
    614614    });
    615615
     616    /**
     617     * wp.media.model.Selection
     618     *
     619     * Used to manage a selection of attachments in the views.
     620     */
     621    media.model.Selection = Attachments.extend({
     622        initialize: function( models, options ) {
     623            Attachments.prototype.initialize.apply( this, arguments );
     624            this.multiple = options && options.multiple;
     625        },
     626
     627        // Override the selection's add method.
     628        // If the workflow does not support multiple
     629        // selected attachments, reset the selection.
     630        add: function( models, options ) {
     631            if ( ! this.multiple ) {
     632                models = _.isArray( models ) ? _.first( models ) : models;
     633                this.clear( options );
     634            }
     635
     636            return Attachments.prototype.add.call( this, models, options );
     637        },
     638
     639        // Removes all models from the selection.
     640        clear: function( options ) {
     641            return this.remove( this.models, options );
     642        },
     643
     644        // Override the selection's reset method.
     645        // Always direct items through add and remove,
     646        // as we need them to fire.
     647        reset: function( models, options ) {
     648            return this.clear( options ).add( models, options );
     649        },
     650
     651        // Create selection.has, which determines if a model
     652        // exists in the collection based on cid and id,
     653        // instead of direct comparison.
     654        has: function( attachment ) {
     655            return !! ( this.getByCid( attachment.cid ) || this.get( attachment.id ) );
     656        }
     657    });
     658
    616659}(jQuery));
  • trunk/wp-includes/js/media-views.js

    r22322 r22323  
    119119
    120120        initialize: function() {
    121             if ( ! this.get('selection') )
    122                 this.set( 'selection', new Attachments() );
     121            if ( ! this.get('selection') ) {
     122                this.set( 'selection', new media.model.Selection( null, {
     123                    multiple: this.get('multiple')
     124                }) );
     125            }
    123126
    124127            if ( ! this.get('library') )
     
    126129
    127130            this.on( 'activate', this.activate, this );
     131            this.on( 'deactivate', this.deactivate, this );
     132            this.on( 'change:details', this.details, this );
    128133        },
    129134
    130135        activate: function() {
     136            this.toolbar();
     137            this.sidebar();
     138            this.content();
     139
     140            // If we're in a workflow that supports multiple attachments,
     141            // automatically select any uploading attachments.
     142            if ( this.get('multiple') )
     143                wp.Uploader.queue.on( 'add', this.selectUpload, this );
     144
     145            this.get('selection').on( 'add remove', this.toggleDetails, this );
     146        },
     147
     148        deactivate: function() {
     149            var toolbar = this._postLibraryToolbar;
     150            if ( toolbar )
     151                this.get('selection').off( 'add remove', toolbar.visibility, toolbar );
     152
     153            wp.Uploader.queue.off( 'add', this.selectUpload, this );
     154            this.get('selection').off( 'add remove', this.toggleDetails, this );
     155        },
     156
     157        toolbar: function() {
    131158            var frame = this.frame,
    132159                toolbar;
     
    140167            frame.toolbar( toolbar );
    141168            this.get('selection').on( 'add remove', toolbar.visibility, toolbar );
     169        },
     170
     171        sidebar: function() {
     172            var frame = this.frame;
    142173
    143174            // Sidebar.
    144175            frame.sidebar( new media.view.Sidebar({
    145                 controller: frame,
    146                 views: {
    147                     search: new media.view.Search({
    148                         controller: frame,
    149                         model:      this.get('library').props,
    150                         priority:   20
    151                     }),
    152 
    153                     selection: new media.view.SelectionPreview({
    154                         controller: frame,
    155                         collection: this.get('selection'),
    156                         priority:   40
    157                     })
    158                 }
     176                controller: frame
    159177            }) );
     178
     179            this.details({ silent: true });
     180            frame.sidebar().add({
     181                search: new media.view.Search({
     182                    controller: frame,
     183                    model:      this.get('library').props,
     184                    priority:   20
     185                }),
     186
     187                selection: new media.view.SelectionPreview({
     188                    controller: frame,
     189                    collection: this.get('selection'),
     190                    priority:   40
     191                })
     192            });
     193        },
     194
     195        content: function() {
     196            var frame = this.frame;
    160197
    161198            // Content.
     
    166203                AttachmentView: media.view.Attachment.Library
    167204            }).render() );
    168 
    169             // If we're in a workflow that supports multiple attachments,
    170             // automatically select any uploading attachments.
    171             if ( this.get('multiple') )
    172                 wp.Uploader.queue.on( 'add', this.selectUpload, this );
    173         },
    174 
    175         deactivate: function() {
    176             var toolbar = this._postLibraryToolbar;
    177 
    178             wp.Uploader.queue.off( 'add', this.selectUpload, this );
    179             this.get('selection').off( 'add remove', toolbar.visibility, toolbar );
    180205        },
    181206
    182207        selectUpload: function( attachment ) {
    183208            this.get('selection').add( attachment );
     209        },
     210
     211        details: function( options ) {
     212            var model = this.get('details'),
     213                view;
     214
     215            if ( model ) {
     216                view = new media.view.Attachment.Details({
     217                    controller: this.frame,
     218                    model:      model,
     219                    priority:   80
     220                });
     221            } else {
     222                view = new Backbone.View();
     223            }
     224
     225            if ( ! options || ! options.silent )
     226                view.render();
     227
     228            this.frame.sidebar().add( 'details', view, options );
     229        },
     230
     231        toggleDetails: function( model ) {
     232            var details = this.get('details'),
     233                selection = this.get('selection');
     234
     235            if ( selection.has( model ) )
     236                this.set( 'details', model );
     237            else if ( selection.length )
     238                this.set( 'details', selection.last() );
     239            else
     240                this.unset('details');
    184241        }
    185242    });
     
    187244    // wp.media.controller.Gallery
    188245    // ---------------------------
    189     media.controller.Gallery = Backbone.Model.extend({
     246    media.controller.Gallery = media.controller.Library.extend({
    190247        defaults: {
    191248            id:         'gallery',
    192             multiple:   true,
     249            multiple:   false,
    193250            describe:   true,
    194251            title:      l10n.createGallery
    195252        },
    196253
    197         initialize: function() {
    198             if ( ! this.get('selection') )
    199                 this.set( 'selection', new Attachments() );
    200 
    201             this.on( 'activate', this.activate, this );
    202         },
    203 
    204         activate: function() {
    205             var frame = this.frame;
    206 
    207             // Toolbar.
    208             frame.toolbar( new media.view.Toolbar.Gallery({
    209                 controller: frame,
     254        toolbar: function() {
     255            this.frame.toolbar( new media.view.Toolbar.Gallery({
     256                controller: this.frame,
    210257                state:      this
    211258            }) );
     259        },
     260
     261        sidebar: function() {
     262            var frame = this.frame;
    212263
    213264            // Sidebar.
    214265            frame.sidebar( new media.view.Sidebar({
    215266                controller: frame
    216             }).render() );
    217 
    218             // Content.
    219             frame.content( new media.view.Attachments({
    220                 controller: frame,
    221                 collection: this.get('selection'),
     267            }) );
     268
     269            this.details();
     270        },
     271
     272        content: function() {
     273            this.frame.content( new media.view.Attachments({
     274                controller: this.frame,
     275                collection: this.get('library'),
    222276                sortable:   true,
    223277                // The single `Attachment` view to be used in the `Attachments` view.
    224278                AttachmentView: media.view.Attachment.Gallery
    225279            }).render() );
    226 
    227             // Automatically select any uploading attachments.
    228             wp.Uploader.queue.on( 'add', this.selectUpload, this );
    229         },
    230 
    231         deactivate: function() {
    232             wp.Uploader.queue.off( 'add', this.selectUpload, this );
    233         },
    234 
    235         selectUpload: function( attachment ) {
    236             this.get('selection').add( attachment );
    237280        }
    238281    });
     
    289332                selection = this.options.selection;
    290333
    291             if ( ! (selection instanceof Attachments) )
    292                 selection = this.options.selection = new Attachments( selection );
    293 
    294             _.extend( selection, {
    295                 // Override the selection's add method.
    296                 // If the workflow does not support multiple
    297                 // selected attachments, reset the selection.
    298                 add: function( models, options ) {
    299                     if ( ! controller.state().get('multiple') ) {
    300                         models = _.isArray( models ) ? _.first( models ) : models;
    301                         this.clear( options );
    302                     }
    303 
    304                     return Attachments.prototype.add.call( this, models, options );
    305                 },
    306 
    307                 // Removes all models from the selection.
    308                 clear: function( options ) {
    309                     return this.remove( this.models, options );
    310                 },
    311 
    312                 // Override the selection's reset method.
    313                 // Always direct items through add and remove,
    314                 // as we need them to fire.
    315                 reset: function( models, options ) {
    316                     return this.clear( options ).add( models, options );
    317                 },
    318 
    319                 // Create selection.has, which determines if a model
    320                 // exists in the collection based on cid and id,
    321                 // instead of direct comparison.
    322                 has: function( attachment ) {
    323                     return !! ( this.getByCid( attachment.cid ) || this.get( attachment.id ) );
    324                 }
    325             });
     334            if ( ! (selection instanceof media.model.Selection) ) {
     335                selection = this.options.selection = new media.model.Selection( selection, {
     336                    multiple: this.options.multiple
     337                });
     338            }
    326339        },
    327340
     
    340353            this.states.add([
    341354                new media.controller.Library({
    342                     selection:  options.selection,
    343                     collection: media.query( options.library ),
    344                     multiple:   this.options.multiple
     355                    selection: options.selection,
     356                    library:  media.query( options.library ),
     357                    multiple:  this.options.multiple
    345358                }),
    346359                new media.controller.Gallery({
    347                     selection: options.selection
     360                    library: options.selection
    348361                })
    349362            ]);
     
    631644
    632645            if ( this.options.items )
    633                 this.add( this.options.items, { silent: true }).render();
     646                this.add( this.options.items, { silent: true });
     647
     648            if ( ! this.options.silent )
     649                this.render();
    634650        },
    635651
     
    651667
    652668        add: function( id, view, options ) {
     669            options = options || {};
     670
    653671            // Accept an object with an `id` : `view` mapping.
    654672            if ( _.isObject( id ) ) {
    655673                _.each( id, function( view, id ) {
    656                     this.add( id, view, options );
     674                    this.add( id, view, { silent: true });
    657675                }, this );
     676
     677                if ( ! options.silent )
     678                    this.render();
    658679                return this;
    659680            }
     
    667688
    668689            this._views[ id ] = view;
    669             if ( ! options || ! options.silent )
     690            if ( ! options.silent )
    670691                this.render();
    671692            return this;
     
    778799            var state = this.options.state,
    779800                editing = state.get('editing'),
    780                 selection = state.get('selection'),
     801                library = state.get('library'),
    781802                controller = this.options.controller;
    782803
     
    788809                    click:    function() {
    789810                        controller.close();
    790                         state.trigger( 'update', selection );
    791                         selection.clear();
     811                        state.trigger( 'update', library );
     812                        library.clear();
    792813                        controller.state('library');
    793814                    }
     
    922943
    923944            if ( this.options.views )
    924                 this.add( this.options.views, { silent: true }).render();
     945                this.add( this.options.views, { silent: true });
     946
     947            if ( ! this.options.silent )
     948                this.render();
    925949        },
    926950
     
    950974
    951975        add: function( id, view, options ) {
     976            options = options || {};
     977
    952978            // Accept an object with an `id` : `view` mapping.
    953979            if ( _.isObject( id ) ) {
    954980                _.each( id, function( view, id ) {
    955                     this.add( id, view, options );
     981                    this.add( id, view, { silent: true });
    956982                }, this );
     983
     984                if ( ! options.silent )
     985                    this.render();
    957986                return this;
    958987            }
     
    961990
    962991            this._views[ id ] = view;
    963             if ( ! options || ! options.silent )
     992            if ( ! options.silent )
    964993                this.render();
    965994            return this;
     
    9901019            'mouseenter .attachment-preview': 'shrink',
    9911020            'mouseleave .attachment-preview': 'expand',
    992             'change .describe':               'describe',
    993             'click .close':                   'toggleSelection'
     1021            'change .describe':               'describe'
    9941022        },
    9951023
     
    11831211        events: (function() {
    11841212            var events = _.clone( media.view.Attachment.prototype.events );
    1185             delete events['click .attachment-preview'];
     1213            events['click .close'] = 'removeFromGallery';
    11861214            return events;
    1187         }())
     1215        }()),
     1216
     1217        removeFromGallery: function() {
     1218            this.controller.state().get('library').remove( this.model );
     1219        }
    11881220    });
    11891221
     
    13771409        render: function() {
    13781410            var options = _.clone( this.options ),
    1379                 first, sizes, amount;
     1411                last, sizes, amount;
    13801412
    13811413            // If nothing is selected, display nothing.
     
    13861418
    13871419            options.count = this.collection.length;
    1388             first = this.collection.first();
    1389             sizes = first.get('sizes');
    1390 
    1391             if ( 'image' === first.get('type') )
    1392                 options.thumbnail = ( sizes && sizes.thumbnail ) ? sizes.thumbnail.url : first.get('url');
     1420            last  = this.collection.last();
     1421            sizes = last.get('sizes');
     1422
     1423            if ( 'image' === last.get('type') )
     1424                options.thumbnail = ( sizes && sizes.thumbnail ) ? sizes.thumbnail.url : last.get('url');
    13931425            else
    1394                 options.thumbnail =  first.get('icon');
     1426                options.thumbnail =  last.get('icon');
    13951427
    13961428            this.$el.html( this.template( options ) );
     
    14911523        }
    14921524    });
     1525
     1526    /**
     1527     * wp.media.view.Attachment.Details
     1528     */
     1529    media.view.Attachment.Details = media.view.Attachment.extend({
     1530        tagName:   'div',
     1531        className: 'attachment-details',
     1532        template:  media.template('attachment-details'),
     1533
     1534        events: {
     1535            'change .describe': 'describe'
     1536        }
     1537    });
    14931538}(jQuery));
  • trunk/wp-includes/media.php

    r22322 r22323  
    13061306    <script type="text/html" id="tmpl-uploader-window">
    13071307        <div class="uploader-window-content">
    1308             <h3><?php _e( 'Drop files here to upload' ); ?></h3>
     1308            <h3><?php _e( 'Drop files to upload' ); ?></h3>
    13091309        </div>
    13101310    </script>
     
    13591359    </script>
    13601360
     1361    <script type="text/html" id="tmpl-attachment-details">
     1362        <div class="attachment-preview attachment-details-preview type-<%- type %> subtype-<%- subtype %> <%- orientation %>">
     1363            <% if ( uploading ) { %>
     1364                <div class="media-progress-bar"><div></div></div>
     1365            <% } else if ( 'image' === type ) { %>
     1366                <div class="thumbnail">
     1367                    <img src="<%- url %>" draggable="false" />
     1368                </div>
     1369            <% } else { %>
     1370                <div class="icon-thumbnail">
     1371                    <img src="<%- icon %>" class="icon" draggable="false" />
     1372                    <div class="filename"><%- filename %></div>
     1373                </div>
     1374            <% } %>
     1375        </div>
     1376
     1377        <% if ( 'image' === type ) { %>
     1378            <textarea class="describe"
     1379                placeholder="<?php esc_attr_e('Describe this image&hellip;'); ?>"
     1380                ><%- caption %></textarea>
     1381        <% } else { %>
     1382            <textarea class="describe"
     1383                <% if ( 'video' === type ) { %>
     1384                    placeholder="<?php esc_attr_e('Describe this video&hellip;'); ?>"
     1385                <% } else if ( 'audio' === type ) { %>
     1386                    placeholder="<?php esc_attr_e('Describe this audio file&hellip;'); ?>"
     1387                <% } else { %>
     1388                    placeholder="<?php esc_attr_e('Describe this media file&hellip;'); ?>"
     1389                <% } %>
     1390                ><%- title %></textarea>
     1391        <% } %>
     1392    </script>
     1393
    13611394    <script type="text/html" id="tmpl-media-selection-preview">
    13621395        <div class="selected-img selected-count-<%- count %>">
Note: See TracChangeset for help on using the changeset viewer.