diff --git a/wp-includes/js/media-models.js b/wp-includes/js/media-models.js index 2e924ac89d..20095dbf60 100644 --- a/wp-includes/js/media-models.js +++ b/wp-includes/js/media-models.js @@ -697,4 +697,77 @@ window.wp = window.wp || {}; } }); + /** + * wp.media.model.Composite + * + * Creates a model that can simultaneously pull from two or more collections. + */ + media.model.Composite = Attachments.extend({ + initialize: function( models, options ) { + this.observe( this, { silent: true }); + Attachments.prototype.initialize.apply( this, arguments ); + }, + + evaluate: function( attachment, options ) { + var valid = this.validator( attachment ), + hasAttachment = !! this.getByCid( attachment.cid ); + + if ( ! valid && hasAttachment ) { + this.remove( attachment, options ); + } else if ( valid && ! hasAttachment ) { + this.add( attachment, options ); + + // If we haven't been silenced, resort the collection. + if ( this.comparator && ( ! options || ! options.silent ) ) + this.sort({ silent: true }); + } + + return this; + }, + + validator: function() { + return true; + }, + + evaluateAll: function( attachments, options ) { + _.each( attachments.models, function( attachment ) { + this.evaluate( attachment, { silent: true }); + }, this ); + + if ( this.comparator ) + this.sort( options ); + return this; + }, + + observe: function( attachments, options ) { + var silent = options && options.silent; + + attachments.on( 'add remove', silent ? this._evaluateSilentHandler : this._evaluateHandler, this ); + attachments.on( 'reset', silent ? this._evaluateAllSilentHandler : this._evaluateAllHandler, this ); + + this.evaluateAll( attachments, options ); + }, + + unobserve: function( attachments ) { + attachments.off( 'add remove', this._evaluateHandler, this ); + attachments.off( 'reset', this._evaluateAllHandler, this ); + }, + + _evaluateHandler: function( attachment, attachments, options ) { + return this.evaluate( attachment, options ); + }, + + _evaluateAllHandler: function( attachments, options ) { + return this.evaluateAll( attachments, options ); + }, + + _evaluateSilentHandler: function( attachment, attachments, options ) { + return this.evaluate( attachment, _.defaults({ silent: true }, options ) ); + }, + + _evaluateAllSilentHandler: function( attachments, options ) { + return this.evaluateAll( attachments, _.defaults({ silent: true }, options ) ); + } + }); + }(jQuery)); \ No newline at end of file diff --git a/wp-includes/js/media-views.js b/wp-includes/js/media-views.js index 0ff3493d58..17e782e398 100644 --- a/wp-includes/js/media-views.js +++ b/wp-includes/js/media-views.js @@ -681,52 +681,32 @@ _.each(['gallery-library','gallery-upload'], function( id ) { var state = this.get( id ), original = state.get('_library'), - skeleton; + composite; // Remember the state's original library. if ( ! original ) state.set( '_library', original = state.get('library') ); - // Create a skeleton library in its place. - skeleton = new Attachments( null, { + // Create a composite library in its place. + composite = new media.model.Composite( null, { props: _.pick( original.props.toJSON(), 'order', 'orderby' ) }); - // Rejects attachments that do not exist in the original library - // or that do exist edit state's library. - skeleton.filters.difference = function( attachment ) { - return ! original.getByCid( attachment.cid ) || !! editLibrary.getByCid( attachment.cid ); + // Accepts attachments that exist in the original library and + // that do not exist in the state's library. + composite.validator = function( attachment ) { + return !! original.getByCid( attachment.cid ) && ! editLibrary.getByCid( attachment.cid ); }; - skeleton.evaluate = function( attachment ) { - var valid = ! this.validator( attachment ), - inSkeleton = !! this.getByCid( attachment.cid ); + composite.observe( original ); + composite.observe( editLibrary ); - if ( ! valid && inSkeleton ) - this.remove( attachment ); - else if ( valid && ! inSkeleton ) - this.add( attachment ).sort(); + // When `more()` is triggered on the composite collection, + // pass the command over to the `original`, which will + // populate the query. + composite.more = _.bind( original.more, original ); - return this; - }; - - skeleton.evaluateAll = function ( attachments ) { - _.each( attachments.models, this.evaluate, this ); - return this; - }; - - skeleton.on( 'add remove', skeleton.evaluate, skeleton ); - skeleton.on( 'reset', skeleton.evaluateAll, skeleton ); - editLibrary.on( 'add remove', skeleton.evaluate, skeleton ); - editLibrary.on( 'reset', skeleton.evaluateAll, skeleton ); - - // Mirror the original library. - skeleton.mirror( original ); - - // Ensure we've evaluated everything in the edit library. - skeleton.evaluateAll( editLibrary ); - - state.set( 'library', skeleton ); + state.set( 'library', composite ); }, this ); },