WordPress.org

Make WordPress Core

Changeset 22692


Ignore:
Timestamp:
11/20/2012 12:53:02 AM (8 years ago)
Author:
koopersmith
Message:

Media: Detect when views are added to the DOM and fire a ready event. see #21390.

File:
1 edited

Legend:

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

    r22690 r22692  
    633633        // `options.at`. By default, `views` are added to the end of the array.
    634634        set: function( selector, views, options ) {
    635             var $selector, els, existing, method;
     635            var existing, next;
    636636
    637637            if ( ! _.isString( selector ) ) {
     
    645645            existing = this.get( selector );
    646646            next     = views;
    647             method   = options.add ? 'insert' : 'replace';
    648647
    649648            if ( existing ) {
     
    673672            this._views[ selector ] = next;
    674673
    675             $selector = selector ? this.view.$( selector ) : this.view.$el;
    676             els = _.pluck( views, 'el' );
    677 
    678674            _.each( views, function( subview ) {
    679675                var constructor = subview.Views || media.Views,
     
    683679            }, this );
    684680
    685             if ( ! options.silent ) {
    686                 _.each( views, this._maybeRender, this );
    687                 this[ method ]( $selector, els, options );
    688             }
     681            if ( ! options.silent )
     682                this._attach( selector, views, _.extend({ ready: this._isReady() }, options ) );
    689683
    690684            return this;
     
    756750        // Renders all subviews. Used in conjunction with `Views.detach()`.
    757751        render: function() {
    758             var root = this._views[''];
    759 
    760             _.each( this.all(), this._maybeRender, this );
    761 
    762             if ( root )
    763                 this.replace( this.view.$el, _.pluck( root, 'el' ) );
     752            var options = {
     753                    ready: this._isReady()
     754                };
    764755
    765756            _.each( this._views, function( views, selector ) {
    766                 if ( selector )
    767                     this.replace( this.view.$( selector ), _.pluck( views, 'el' ) );
     757                this._attach( selector, views, options );
    768758            }, this );
    769759
     
    821811        },
    822812
    823 
    824         // #### Internal. Maybe render a view.
    825         _maybeRender: function( view ) {
    826             if ( ! view.views || view.views.rendered )
    827                 return;
    828 
    829             view.render();
    830             view.views.rendered = true;
     813        // ### Trigger the ready event
     814        //
     815        // **Only use this method if you know what you're doing.**
     816        // For performance reasons, this method does not check if the view is
     817        // actually attached to the DOM. It's taking your word for it.
     818        //
     819        // Fires the ready event on the current view and all attached subviews.
     820        ready: function() {
     821            this.view.trigger('ready');
     822
     823            // Find all attached subviews, and call ready on them.
     824            _.chain( this.all() ).map( function( view ) {
     825                return view.views;
     826            }).flatten().where({ attached: true }).invoke('ready');
     827        },
     828
     829        // #### Internal. Attaches a series of views to a selector.
     830        //
     831        // Checks to see if a matching selector exists, renders the views,
     832        // performs the proper DOM operation, and then checks if the view is
     833        // attached to the document.
     834        _attach: function( selector, views, options ) {
     835            var $selector = selector ? this.view.$( selector ) : this.view.$el,
     836                managers;
     837
     838            // Check if we found a location to attach the views.
     839            if ( ! $selector.length )
     840                return this;
     841
     842            managers = _.chain( views ).pluck('views').flatten().value();
     843
     844            // Render the views if necessary.
     845            _.each( managers, function( manager ) {
     846                if ( manager.rendered )
     847                    return;
     848
     849                manager.view.render();
     850                manager.rendered = true;
     851            }, this );
     852
     853            // Insert or replace the views.
     854            this[ options.add ? 'insert' : 'replace' ]( $selector, _.pluck( views, 'el' ), options );
     855
     856            // Set attached and trigger ready if the current view is already
     857            // attached to the DOM.
     858            _.each( managers, function( manager ) {
     859                manager.attached = true;
     860
     861                if ( options.ready )
     862                    manager.ready();
     863            }, this );
     864
     865            return this;
     866        },
     867
     868        // #### Internal. Checks if the current view is in the DOM.
     869        _isReady: function() {
     870            var node = this.view.el;
     871            while ( node ) {
     872                if ( node === document.body )
     873                    return true;
     874                node = node.parentNode;
     875            }
     876
     877            return false;
    831878        }
    832879    });
     
    842889        constructor: function() {
    843890            this.views = new this.Views( this, this.views );
     891            this.on( 'ready', this.ready, this );
    844892            Backbone.View.apply( this, arguments );
    845893        },
     
    886934        prepare: function() {
    887935            return this.options;
    888         }
     936        },
     937
     938        ready: function() {}
    889939    });
    890940
     
    9681018                });
    9691019            }
     1020
     1021            this.on( 'attach', _.bind( this.views.ready, this.views ), this );
    9701022        },
    9711023
     
    10611113    _.each(['open','close','attach','detach'], function( method ) {
    10621114        media.view.MediaFrame.prototype[ method ] = function( view ) {
    1063             this.trigger( method );
    10641115            if ( this.modal )
    10651116                this.modal[ method ].apply( this.modal, arguments );
     1117            this.trigger( method );
    10661118            return this;
    10671119        };
     
    15931645        attach: function() {
    15941646            this.$el.appendTo( this.options.container );
    1595             this.controller.trigger( 'attach', this.controller );
     1647            this.trigger('attach');
    15961648            return this;
    15971649        },
     
    15991651        detach: function() {
    16001652            this.$el.detach();
    1601             this.controller.trigger( 'detach', this.controller );
     1653            this.trigger('detach');
    16021654            return this;
    16031655        },
     
    16051657        open: function() {
    16061658            this.$el.show();
    1607             this.controller.trigger( 'open', this.controller );
     1659            this.trigger('open');
    16081660            return this;
    16091661        },
     
    16111663        close: function() {
    16121664            this.$el.hide();
    1613             this.controller.trigger( 'close', this.controller );
     1665            this.trigger('close');
    16141666            return this;
    16151667        },
Note: See TracChangeset for help on using the changeset viewer.