From 103694aa4f2f76495f439e3841dbb37d5be3add9 Mon Sep 17 00:00:00 2001 From: Daryl Koopersmith Date: Fri, 9 Nov 2012 01:23:20 +0000 Subject: [PATCH] Media JS: Add JIT composite library creation/destruction to states to allow for dynamically excluded Attachment models. see #21390. git-svn-id: http://core.svn.wordpress.org/trunk@22477 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/js/media-models.js | 17 ++++- wp-includes/js/media-views.js | 120 ++++++++++++++++++++++----------- 2 files changed, 94 insertions(+), 43 deletions(-) diff --git a/wp-includes/js/media-models.js b/wp-includes/js/media-models.js index 20095dbf60..6b31acb63c 100644 --- a/wp-includes/js/media-models.js +++ b/wp-includes/js/media-models.js @@ -741,16 +741,29 @@ window.wp = window.wp || {}; observe: function( attachments, options ) { var silent = options && options.silent; + this.observers = this.observers || []; + this.observers.push( attachments ); attachments.on( 'add remove', silent ? this._evaluateSilentHandler : this._evaluateHandler, this ); attachments.on( 'reset', silent ? this._evaluateAllSilentHandler : this._evaluateAllHandler, this ); this.evaluateAll( attachments, options ); + return this; }, unobserve: function( attachments ) { - attachments.off( 'add remove', this._evaluateHandler, this ); - attachments.off( 'reset', this._evaluateAllHandler, this ); + if ( attachments ) { + attachments.off( null, null, this ); + this.observers = _.without( this.observers, attachments ); + + } else { + _.each( this.observers, function( attachments ) { + attachments.off( null, null, this ); + }, this ); + delete this.observers; + } + + return this; }, _evaluateHandler: function( attachment, attachments, options ) { diff --git a/wp-includes/js/media-views.js b/wp-includes/js/media-views.js index 17e782e398..fa13dc8425 100644 --- a/wp-includes/js/media-views.js +++ b/wp-includes/js/media-views.js @@ -291,6 +291,11 @@ activate: function() { var selection = this.get('selection'); + this._excludeStateLibrary(); + this.buildComposite(); + this.on( 'change:library change:exclude', this.buildComposite, this ); + this.on( 'change:excludeState', this._excludeState, this ); + // If we're in a workflow that supports multiple attachments, // automatically select any uploading attachments. if ( this.get('multiple') ) @@ -306,6 +311,10 @@ }, deactivate: function() { + this.off( 'change:library change:exclude', this.buildComposite, this ); + this.off( 'change:excludeState', this._excludeState, this ); + this.destroyComposite(); + wp.Uploader.queue.off( 'add', this.selectUpload, this ); // Unbind all event handlers that use this state as the context @@ -375,6 +384,72 @@ } return this; + }, + + buildComposite: function() { + var original = this.get('_library'), + exclude = this.get('exclude'), + composite; + + this.destroyComposite(); + if ( ! this.get('exclude') ) + return; + + // Remember the state's original library. + if ( ! original ) + this.set( '_library', original = this.get('library') ); + + // Create a composite library in its place. + composite = new media.model.Composite( null, { + props: _.pick( original.props.toJSON(), 'order', 'orderby' ) + }); + + // Accepts attachments that exist in the original library and + // that do not exist in the excluded library. + composite.validator = function( attachment ) { + return !! original.getByCid( attachment.cid ) && ! exclude.getByCid( attachment.cid ); + }; + + composite.observe( original ).observe( exclude ); + + // 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 ); + + this.set( 'library', composite ); + }, + + destroyComposite: function() { + var composite = this.get('library'), + original = this.get('_library'); + + if ( ! original ) + return; + + composite.unobserve(); + this.set( 'library', original ); + this.unset('_library'); + }, + + _excludeState: function() { + var current = this.get('excludeState'), + previous = this.previous('excludeState'); + + if ( previous ) + this.frame.get( previous ).off( 'change:library', this._excludeStateLibrary, this ); + + if ( current ) + this.frame.get( previous ).on( 'change:library', this._excludeStateLibrary, this ); + }, + + _excludeStateLibrary: function() { + var current = this.get('excludeState'); + + if ( ! current ) + return; + + this.set( 'exclude', this.frame.get( current ).get('library') ); } }); @@ -659,57 +734,20 @@ new media.controller.Library( _.defaults({ id: 'gallery-library', - library: media.query({ type: 'image' }) + library: media.query({ type: 'image' }), + excludeState: 'gallery-edit' }, gallery ) ), new media.controller.Upload( _.defaults({ - id: 'gallery-upload' + id: 'gallery-upload', + excludeState: 'gallery-edit' }, gallery ) ) ]); - this.get('gallery-edit').on( 'change:library', this.updateGalleryLibraries, this ).set({ - library: options.selection - }); - // Set the default state. this.state( options.state ); }, - updateGalleryLibraries: function() { - var editLibrary = this.get('gallery-edit').get('library'); - - _.each(['gallery-library','gallery-upload'], function( id ) { - var state = this.get( id ), - original = state.get('_library'), - composite; - - // Remember the state's original library. - if ( ! original ) - state.set( '_library', original = state.get('library') ); - - // Create a composite library in its place. - composite = new media.model.Composite( null, { - props: _.pick( original.props.toJSON(), 'order', 'orderby' ) - }); - - // 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 ); - }; - - composite.observe( original ); - composite.observe( editLibrary ); - - // 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 ); - - state.set( 'library', composite ); - }, this ); - }, - // Menus mainMenu: function() { this.menu.view( new media.view.Menu({