WordPress.org

Make WordPress Core

Changeset 22046


Ignore:
Timestamp:
09/27/2012 06:53:54 AM (8 years ago)
Author:
koopersmith
Message:

Media JS: Use a custom Attachment views for both the media library and gallery screens.

To do so, the Attachment view code had to be shifted above the Workspace view code to ensure the subview is defined (preventing errors).

Also corrects an error in wp.media.view.Attachments.add where it was still using the default Attachment view.

see #21390, #21809.

Location:
trunk/wp-includes
Files:
2 edited

Legend:

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

    r21909 r22046  
    249249}
    250250
    251 .attachment.selected {
     251.attachment.library.selected {
    252252    border-color: #21759b;
    253253}
    254254
    255 .attachment.selected:after {
     255.attachment.library.selected:after {
    256256    content: '\2713';
    257257    display: block;
  • trunk/wp-includes/js/media-views.js

    r22045 r22046  
    368368
    369369    /**
    370      * wp.media.view.Workspace
    371      */
    372     media.view.Workspace = Backbone.View.extend({
    373         tagName:   'div',
    374         className: 'media-workspace',
    375         template:  media.template('media-workspace'),
    376 
    377         // The single `Attachment` view to be used in the `Attachments` view.
    378         AttachmentView: media.view.Attachment,
    379 
    380         events: {
    381             'dragenter':  'maybeInitUploader',
    382             'mouseenter': 'maybeInitUploader'
    383         },
    384 
    385         initialize: function() {
    386             this.controller = this.options.controller;
    387 
    388             _.defaults( this.options, {
    389                 selectOne: false,
    390                 uploader:  {}
    391             });
    392 
    393             this.$content = $('<div class="existing-attachments" />');
    394 
    395             this.attachmentsView = new media.view.Attachments({
    396                 controller: this.controller,
    397                 directions: this.controller.get('multiple') ? l10n.selectMediaMultiple : l10n.selectMediaSingular,
    398                 collection: this.collection,
    399 
    400                 AttachmentView: this.AttachmentView
    401             });
    402 
    403             this.$content.append( this.attachmentsView.$el );
    404 
    405             // Track uploading attachments.
    406             wp.Uploader.queue.on( 'add remove reset change:percent', this.renderUploadProgress, this );
    407             wp.Uploader.queue.on( 'add', this.selectUpload, this );
    408         },
    409 
    410         render: function() {
    411             this.$content.detach();
    412 
    413             this.attachmentsView.render();
    414             this.renderUploadProgress();
    415             this.$el.html( this.template( this.options ) ).append( this.$content );
    416             this.$bar = this.$('.upload-attachments .media-progress-bar div');
    417             return this;
    418         },
    419 
    420         maybeInitUploader: function() {
    421             var workspace = this;
    422 
    423             // If the uploader already exists or the body isn't in the DOM, bail.
    424             if ( this.uploader || ! this.$el.closest('body').length )
    425                 return;
    426 
    427             this.uploader = new wp.Uploader( _.extend({
    428                 container: this.$el,
    429                 dropzone:  this.$el,
    430                 browser:   this.$('.upload-attachments a')
    431             }, this.options.uploader ) );
    432         },
    433 
    434         selectUpload: function( attachment ) {
    435             this.controller.selection.add( attachment );
    436         },
    437 
    438         renderUploadProgress: function() {
    439             var queue = wp.Uploader.queue;
    440 
    441             this.$el.toggleClass( 'uploading', !! queue.length );
    442 
    443             if ( ! this.$bar || ! queue.length )
    444                 return;
    445 
    446             this.$bar.width( ( queue.reduce( function( memo, attachment ) {
    447                 if ( attachment.get('uploading') )
    448                     return memo + ( attachment.get('percent') || 0 );
    449                 else
    450                     return memo + 100;
    451             }, 0 ) / queue.length ) + '%' );
    452         }
    453     });
    454 
    455     /**
    456      * wp.media.view.Workspace.Library
    457      */
    458     media.view.Workspace.Library = media.view.Workspace.extend({
    459         // The single `Attachment` view to be used in the `Attachments` view.
    460         // AttachmentView: media.view.Attachment.Library,
    461 
    462         initialize: function() {
    463             media.view.Workspace.prototype.initialize.apply( this, arguments );
    464 
    465             // If this supports multiple attachments, initialize the sample toolbar view.
    466             if ( this.controller.get('multiple') )
    467                 this.initToolbarView();
    468         },
    469 
    470         // Initializes the toolbar view. Currently uses defaults set for
    471         // inserting media into a post. This should be pulled out into the
    472         // appropriate workflow when the time comes, but is currently here
    473         // to test multiple selections.
    474         initToolbarView: function() {
    475             var controller = this.controller;
    476 
    477             this.toolbarView = new media.view.Toolbar({
    478                 items: {
    479                     'selection-preview': new media.view.SelectionPreview({
    480                         controller: this.controller,
    481                         collection: this.controller.selection,
    482                         priority: -40
    483                     }),
    484 
    485                     'create-new-gallery': {
    486                         style:    'primary',
    487                         text:     l10n.createNewGallery,
    488                         priority: 40,
    489 
    490                         click: function() {
    491                             controller.render('gallery');
    492                         }
    493                     },
    494 
    495                     'insert-into-post': {
    496                         text:     l10n.insertIntoPost,
    497                         priority: 30,
    498                         click:    _.bind( controller.update, controller )
    499                     },
    500 
    501                     'add-to-gallery': {
    502                         text:     l10n.addToGallery,
    503                         priority: 20
    504                     }
    505                 }
    506             });
    507 
    508             this.controller.selection.on( 'add remove', function() {
    509                 var count = this.controller.selection.length,
    510                     showGallery;
    511 
    512                 this.$el.toggleClass( 'with-toolbar', !! count );
    513 
    514                 // Check if every attachment in the selection is an image.
    515                 showGallery = count > 1 && this.controller.selection.all( function( attachment ) {
    516                     return 'image' === attachment.get('type');
    517                 });
    518 
    519                 this.toolbarView.get('create-new-gallery').$el.toggle( showGallery );
    520                 insert = this.toolbarView.get('insert-into-post');
    521                 insert.model.set( 'style', showGallery ? '' : 'primary' );
    522             }, this );
    523 
    524             this.$content.append( this.toolbarView.$el );
    525         }
    526     });
    527 
    528     /**
    529      * wp.media.view.Workspace.Gallery
    530      */
    531     media.view.Workspace.Gallery = media.view.Workspace.extend({
    532         // The single `Attachment` view to be used in the `Attachments` view.
    533         // AttachmentView: media.view.Attachment.Gallery,
    534 
    535         initialize: function() {
    536             media.view.Workspace.prototype.initialize.apply( this, arguments );
    537             this.initToolbarView();
    538         },
    539 
    540         // Initializes the toolbar view. Currently uses defaults set for
    541         // inserting media into a post. This should be pulled out into the
    542         // appropriate workflow when the time comes, but is currently here
    543         // to test multiple selections.
    544         initToolbarView: function() {
    545             var controller = this.controller;
    546 
    547             this.toolbarView = new media.view.Toolbar({
    548                 items: {
    549                     'return-to-library': {
    550                         text:     l10n.returnToLibrary,
    551                         priority: -40,
    552 
    553                         click:  function() {
    554                             controller.render('library');
    555                         }
    556                     },
    557 
    558                     'insert-gallery-into-post': {
    559                         style:    'primary',
    560                         text:     l10n.insertGalleryIntoPost,
    561                         priority: 40,
    562                         click:    _.bind( controller.update, controller )
    563                     },
    564 
    565                     'add-images-from-library': {
    566                         text:     l10n.addImagesFromLibrary,
    567                         priority: 30
    568                     }
    569                 }
    570             });
    571 
    572             this.$el.addClass('with-toolbar');
    573             this.$content.append( this.toolbarView.$el );
    574         }
    575     });
    576 
    577 
    578     /**
    579      * wp.media.view.Attachments
    580      */
    581     media.view.Attachments = Backbone.View.extend({
    582         tagName:   'div',
    583         className: 'attachments',
    584         template:  media.template('attachments'),
    585 
    586         events: {
    587             'keyup input': 'search'
    588         },
    589 
    590         initialize: function() {
    591             this.controller = this.options.controller;
    592 
    593             _.defaults( this.options, {
    594                 refreshSensitivity: 200,
    595                 refreshThreshold:   3,
    596                 AttachmentView:     media.view.Attachment
    597             });
    598 
    599             _.each(['add','remove'], function( method ) {
    600                 this.collection.on( method, function( attachment, attachments, options ) {
    601                     this[ method ]( attachment, options.index );
    602                 }, this );
    603             }, this );
    604 
    605             this.collection.on( 'reset', this.refresh, this );
    606 
    607             this.$list = $('<ul />');
    608             this.list  = this.$list[0];
    609 
    610             this.scroll = _.chain( this.scroll ).bind( this ).throttle( this.options.refreshSensitivity ).value();
    611             this.$list.on( 'scroll.attachments', this.scroll );
    612         },
    613 
    614         render: function() {
    615             // Detach the list from the DOM to prevent event removal.
    616             this.$list.detach();
    617 
    618             this.$el.html( this.template( this.options ) ).append( this.$list );
    619             this.refresh();
    620             return this;
    621         },
    622 
    623         refresh: function() {
    624             // If there are no elements, load some.
    625             if ( ! this.collection.length ) {
    626                 this.collection.more();
    627                 this.$list.empty();
    628                 return this;
    629             }
    630 
    631             // Otherwise, create all of the Attachment views, and replace
    632             // the list in a single DOM operation.
    633             this.$list.html( this.collection.map( function( attachment ) {
    634                 return new this.options.AttachmentView({
    635                     controller: this.controller,
    636                     model:      attachment
    637                 }).render().$el;
    638             }, this ) );
    639 
    640             // Then, trigger the scroll event to check if we're within the
    641             // threshold to query for additional attachments.
    642             this.scroll();
    643             return this;
    644         },
    645 
    646         add: function( attachment, index ) {
    647             var view, children;
    648 
    649             view = new media.view.Attachment({
    650                 controller: this.controller,
    651                 model:      attachment
    652             }).render();
    653 
    654             children = this.$list.children();
    655 
    656             if ( children.length > index )
    657                 children.eq( index ).before( view.$el );
    658             else
    659                 this.$list.append( view.$el );
    660         },
    661 
    662         remove: function( attachment, index ) {
    663             var children = this.$list.children();
    664             if ( children.length )
    665                 children.eq( index ).detach();
    666         },
    667 
    668         scroll: function( event ) {
    669             // @todo: is this still necessary?
    670             if ( ! this.$list.is(':visible') )
    671                 return;
    672 
    673             if ( this.list.scrollHeight < this.list.scrollTop + ( this.list.clientHeight * this.options.refreshThreshold ) ) {
    674                 this.collection.more();
    675             }
    676         },
    677 
    678         search: function( event ) {
    679             var props = this.collection.props;
    680 
    681             if ( event.target.value )
    682                 props.set( 'search', event.target.value );
    683             else
    684                 props.unset('search');
    685         }
    686     });
    687 
    688 
    689     /**
    690370     * wp.media.view.Attachment
    691371     */
     
    770450
    771451    /**
     452     * wp.media.view.Attachment.Library
     453     */
     454    media.view.Attachment.Library = media.view.Attachment.extend({
     455        className: 'attachment library'
     456    });
     457
     458    /**
     459     * wp.media.view.Attachment.Gallery
     460     */
     461    media.view.Attachment.Gallery = media.view.Attachment.extend({
     462        events: {}
     463    });
     464
     465    /**
     466     * wp.media.view.Workspace
     467     */
     468    media.view.Workspace = Backbone.View.extend({
     469        tagName:   'div',
     470        className: 'media-workspace',
     471        template:  media.template('media-workspace'),
     472
     473        // The single `Attachment` view to be used in the `Attachments` view.
     474        AttachmentView: media.view.Attachment,
     475
     476        events: {
     477            'dragenter':  'maybeInitUploader',
     478            'mouseenter': 'maybeInitUploader'
     479        },
     480
     481        initialize: function() {
     482            this.controller = this.options.controller;
     483
     484            _.defaults( this.options, {
     485                selectOne: false,
     486                uploader:  {}
     487            });
     488
     489            this.$content = $('<div class="existing-attachments" />');
     490
     491            this.attachmentsView = new media.view.Attachments({
     492                controller: this.controller,
     493                directions: this.controller.get('multiple') ? l10n.selectMediaMultiple : l10n.selectMediaSingular,
     494                collection: this.collection,
     495
     496                AttachmentView: this.AttachmentView
     497            });
     498
     499            this.$content.append( this.attachmentsView.$el );
     500
     501            // Track uploading attachments.
     502            wp.Uploader.queue.on( 'add remove reset change:percent', this.renderUploadProgress, this );
     503            wp.Uploader.queue.on( 'add', this.selectUpload, this );
     504        },
     505
     506        render: function() {
     507            this.$content.detach();
     508
     509            this.attachmentsView.render();
     510            this.renderUploadProgress();
     511            this.$el.html( this.template( this.options ) ).append( this.$content );
     512            this.$bar = this.$('.upload-attachments .media-progress-bar div');
     513            return this;
     514        },
     515
     516        maybeInitUploader: function() {
     517            var workspace = this;
     518
     519            // If the uploader already exists or the body isn't in the DOM, bail.
     520            if ( this.uploader || ! this.$el.closest('body').length )
     521                return;
     522
     523            this.uploader = new wp.Uploader( _.extend({
     524                container: this.$el,
     525                dropzone:  this.$el,
     526                browser:   this.$('.upload-attachments a')
     527            }, this.options.uploader ) );
     528        },
     529
     530        selectUpload: function( attachment ) {
     531            this.controller.selection.add( attachment );
     532        },
     533
     534        renderUploadProgress: function() {
     535            var queue = wp.Uploader.queue;
     536
     537            this.$el.toggleClass( 'uploading', !! queue.length );
     538
     539            if ( ! this.$bar || ! queue.length )
     540                return;
     541
     542            this.$bar.width( ( queue.reduce( function( memo, attachment ) {
     543                if ( attachment.get('uploading') )
     544                    return memo + ( attachment.get('percent') || 0 );
     545                else
     546                    return memo + 100;
     547            }, 0 ) / queue.length ) + '%' );
     548        }
     549    });
     550
     551    /**
     552     * wp.media.view.Workspace.Library
     553     */
     554    media.view.Workspace.Library = media.view.Workspace.extend({
     555        // The single `Attachment` view to be used in the `Attachments` view.
     556        AttachmentView: media.view.Attachment.Library,
     557
     558        initialize: function() {
     559            media.view.Workspace.prototype.initialize.apply( this, arguments );
     560
     561            // If this supports multiple attachments, initialize the sample toolbar view.
     562            if ( this.controller.get('multiple') )
     563                this.initToolbarView();
     564        },
     565
     566        // Initializes the toolbar view. Currently uses defaults set for
     567        // inserting media into a post. This should be pulled out into the
     568        // appropriate workflow when the time comes, but is currently here
     569        // to test multiple selections.
     570        initToolbarView: function() {
     571            var controller = this.controller;
     572
     573            this.toolbarView = new media.view.Toolbar({
     574                items: {
     575                    'selection-preview': new media.view.SelectionPreview({
     576                        controller: this.controller,
     577                        collection: this.controller.selection,
     578                        priority: -40
     579                    }),
     580
     581                    'create-new-gallery': {
     582                        style:    'primary',
     583                        text:     l10n.createNewGallery,
     584                        priority: 40,
     585
     586                        click: function() {
     587                            controller.render('gallery');
     588                        }
     589                    },
     590
     591                    'insert-into-post': {
     592                        text:     l10n.insertIntoPost,
     593                        priority: 30,
     594                        click:    _.bind( controller.update, controller )
     595                    },
     596
     597                    'add-to-gallery': {
     598                        text:     l10n.addToGallery,
     599                        priority: 20
     600                    }
     601                }
     602            });
     603
     604            this.controller.selection.on( 'add remove', function() {
     605                var count = this.controller.selection.length,
     606                    showGallery;
     607
     608                this.$el.toggleClass( 'with-toolbar', !! count );
     609
     610                // Check if every attachment in the selection is an image.
     611                showGallery = count > 1 && this.controller.selection.all( function( attachment ) {
     612                    return 'image' === attachment.get('type');
     613                });
     614
     615                this.toolbarView.get('create-new-gallery').$el.toggle( showGallery );
     616                insert = this.toolbarView.get('insert-into-post');
     617                insert.model.set( 'style', showGallery ? '' : 'primary' );
     618            }, this );
     619
     620            this.$content.append( this.toolbarView.$el );
     621        }
     622    });
     623
     624    /**
     625     * wp.media.view.Workspace.Gallery
     626     */
     627    media.view.Workspace.Gallery = media.view.Workspace.extend({
     628        // The single `Attachment` view to be used in the `Attachments` view.
     629        AttachmentView: media.view.Attachment.Gallery,
     630
     631        initialize: function() {
     632            media.view.Workspace.prototype.initialize.apply( this, arguments );
     633            this.initToolbarView();
     634        },
     635
     636        // Initializes the toolbar view. Currently uses defaults set for
     637        // inserting media into a post. This should be pulled out into the
     638        // appropriate workflow when the time comes, but is currently here
     639        // to test multiple selections.
     640        initToolbarView: function() {
     641            var controller = this.controller;
     642
     643            this.toolbarView = new media.view.Toolbar({
     644                items: {
     645                    'return-to-library': {
     646                        text:     l10n.returnToLibrary,
     647                        priority: -40,
     648
     649                        click:  function() {
     650                            controller.render('library');
     651                        }
     652                    },
     653
     654                    'insert-gallery-into-post': {
     655                        style:    'primary',
     656                        text:     l10n.insertGalleryIntoPost,
     657                        priority: 40,
     658                        click:    _.bind( controller.update, controller )
     659                    },
     660
     661                    'add-images-from-library': {
     662                        text:     l10n.addImagesFromLibrary,
     663                        priority: 30
     664                    }
     665                }
     666            });
     667
     668            this.$el.addClass('with-toolbar');
     669            this.$content.append( this.toolbarView.$el );
     670        }
     671    });
     672
     673
     674    /**
     675     * wp.media.view.Attachments
     676     */
     677    media.view.Attachments = Backbone.View.extend({
     678        tagName:   'div',
     679        className: 'attachments',
     680        template:  media.template('attachments'),
     681
     682        events: {
     683            'keyup input': 'search'
     684        },
     685
     686        initialize: function() {
     687            this.controller = this.options.controller;
     688
     689            _.defaults( this.options, {
     690                refreshSensitivity: 200,
     691                refreshThreshold:   3,
     692                AttachmentView:     media.view.Attachment
     693            });
     694
     695            _.each(['add','remove'], function( method ) {
     696                this.collection.on( method, function( attachment, attachments, options ) {
     697                    this[ method ]( attachment, options.index );
     698                }, this );
     699            }, this );
     700
     701            this.collection.on( 'reset', this.refresh, this );
     702
     703            this.$list = $('<ul />');
     704            this.list  = this.$list[0];
     705
     706            this.scroll = _.chain( this.scroll ).bind( this ).throttle( this.options.refreshSensitivity ).value();
     707            this.$list.on( 'scroll.attachments', this.scroll );
     708        },
     709
     710        render: function() {
     711            // Detach the list from the DOM to prevent event removal.
     712            this.$list.detach();
     713
     714            this.$el.html( this.template( this.options ) ).append( this.$list );
     715            this.refresh();
     716            return this;
     717        },
     718
     719        refresh: function() {
     720            // If there are no elements, load some.
     721            if ( ! this.collection.length ) {
     722                this.collection.more();
     723                this.$list.empty();
     724                return this;
     725            }
     726
     727            // Otherwise, create all of the Attachment views, and replace
     728            // the list in a single DOM operation.
     729            this.$list.html( this.collection.map( function( attachment ) {
     730                return new this.options.AttachmentView({
     731                    controller: this.controller,
     732                    model:      attachment
     733                }).render().$el;
     734            }, this ) );
     735
     736            // Then, trigger the scroll event to check if we're within the
     737            // threshold to query for additional attachments.
     738            this.scroll();
     739            return this;
     740        },
     741
     742        add: function( attachment, index ) {
     743            var view, children;
     744
     745            view = new this.options.AttachmentView({
     746                controller: this.controller,
     747                model:      attachment
     748            }).render();
     749
     750            children = this.$list.children();
     751
     752            if ( children.length > index )
     753                children.eq( index ).before( view.$el );
     754            else
     755                this.$list.append( view.$el );
     756        },
     757
     758        remove: function( attachment, index ) {
     759            var children = this.$list.children();
     760            if ( children.length )
     761                children.eq( index ).detach();
     762        },
     763
     764        scroll: function( event ) {
     765            // @todo: is this still necessary?
     766            if ( ! this.$list.is(':visible') )
     767                return;
     768
     769            if ( this.list.scrollHeight < this.list.scrollTop + ( this.list.clientHeight * this.options.refreshThreshold ) ) {
     770                this.collection.more();
     771            }
     772        },
     773
     774        search: function( event ) {
     775            var props = this.collection.props;
     776
     777            if ( event.target.value )
     778                props.set( 'search', event.target.value );
     779            else
     780                props.unset('search');
     781        }
     782    });
     783
     784    /**
    772785     * wp.media.view.SelectionPreview
    773786     */
Note: See TracChangeset for help on using the changeset viewer.