WordPress.org

Make WordPress Core

Ticket #20811: 20811.2.diff

File 20811.2.diff, 14.4 KB (added by koopersmith, 23 months ago)
  • wp-includes/class-wp-customize-manager.php

     
    290290         */ 
    291291        public function customize_preview_settings() { 
    292292                $settings = array( 
    293                         'values' => array(), 
     293                        'values'  => array(), 
     294                        'channel' => esc_js( $_POST['customize_messenger_channel'] ), 
    294295                ); 
    295296 
    296297                foreach ( $this->settings as $id => $setting ) { 
  • wp-includes/js/customize-base.dev.js

     
    302302                        return this.add( id, new this.defaultConstructor( api.Class.applicator, slice.call( arguments, 1 ) ) ); 
    303303                }, 
    304304 
    305                 get: function() { 
    306                         var result = {}; 
     305                each: function( callback, context ) { 
     306                        context = typeof context === 'undefined' ? this : context; 
    307307 
    308308                        $.each( this._value, function( key, obj ) { 
    309                                 result[ key ] = obj.get(); 
    310                         } ); 
    311                         return result; 
     309                                callback.call( context, obj, key ); 
     310                        }); 
    312311                }, 
    313312 
    314313                remove: function( id ) { 
     
    481480                        return this[ key ] = new api.Value( initial, options ); 
    482481                }, 
    483482 
    484                 initialize: function( url, targetWindow, options ) { 
     483                /** 
     484                 * Initialize Messenger. 
     485                 * 
     486                 * @param  {object} params        Parameters to configure the messenger. 
     487                 *         {string} .url          The URL to communicate with. 
     488                 *         {window} .targetWindow The window instance to communicate with. Default window.parent. 
     489                 *         {string} .channel      If provided, will send the channel with each message and only accept messages a matching channel. 
     490                 * @param  {object} options       Extend any instance parameter or method with this object. 
     491                 */ 
     492                initialize: function( params, options ) { 
    485493                        // Target the parent frame by default, but only if a parent frame exists. 
    486494                        var defaultTarget = window.parent == window ? null : window.parent; 
    487495 
    488496                        $.extend( this, options || {} ); 
    489497 
    490                         url = this.add( 'url', url ); 
    491                         this.add( 'targetWindow', targetWindow || defaultTarget ); 
    492                         this.add( 'origin', url() ).link( url ).setter( function( to ) { 
     498                        this.add( 'channel', params.channel ); 
     499                        this.add( 'url', params.url ); 
     500                        this.add( 'targetWindow', params.targetWindow || defaultTarget ); 
     501                        this.add( 'origin', this.url() ).link( this.url ).setter( function( to ) { 
    493502                                return to.replace( /([^:]+:\/\/[^\/]+).*/, '$1' ); 
    494503                        }); 
    495504 
     505                        // Since we want jQuery to treat the receive function as unique 
     506                        // to this instance, we give the function a new guid. 
     507                        // 
     508                        // This will prevent every Messenger's receive function from being 
     509                        // unbound when calling $.off( 'message', this.receive ); 
    496510                        this.receive = $.proxy( this.receive, this ); 
     511                        this.receive.guid = $.guid++; 
     512 
    497513                        $( window ).on( 'message', this.receive ); 
    498514                }, 
    499515 
     
    515531 
    516532                        message = JSON.parse( event.data ); 
    517533 
    518                         if ( message && message.id && typeof message.data !== 'undefined' ) 
    519                                 this.trigger( message.id, message.data ); 
     534                        // Check required message properties. 
     535                        if ( ! message || ! message.id || typeof message.data === 'undefined' ) 
     536                                return; 
     537 
     538                        // Check if channel names match. 
     539                        if ( ( message.channel || this.channel() ) && this.channel() !== message.channel ) 
     540                                return; 
     541 
     542                        this.trigger( message.id, message.data ); 
    520543                }, 
    521544 
    522545                send: function( id, data ) { 
     
    527550                        if ( ! this.url() || ! this.targetWindow() ) 
    528551                                return; 
    529552 
    530                         message = JSON.stringify({ id: id, data: data }); 
    531                         this.targetWindow().postMessage( message, this.origin() ); 
     553                        message = { id: id, data: data }; 
     554                        if ( this.channel() ) 
     555                                message.channel = this.channel(); 
     556 
     557                        this.targetWindow().postMessage( JSON.stringify( message ), this.origin() ); 
    532558                } 
    533559        }); 
    534560 
     
    540566         * ===================================================================== */ 
    541567 
    542568        api = $.extend( new api.Values(), api ); 
     569        api.get = function() { 
     570                var result = {}; 
    543571 
     572                this.each( function( obj, key ) { 
     573                        result[ key ] = obj.get(); 
     574                }); 
     575 
     576                return result; 
     577        }; 
     578 
    544579        // Expose the API to the world. 
    545580        exports.customize = api; 
    546581})( wp, jQuery ); 
  • wp-includes/js/customize-preview.dev.js

     
    2121                /** 
    2222                 * Requires params: 
    2323                 *  - url    - the URL of preview frame 
    24                  * 
    25                  * @todo: Perhaps add a window.onbeforeunload dialog in case the theme 
    26                  *        somehow attempts to leave the page and we don't catch it 
    27                  *        (which really shouldn't happen). 
    2824                 */ 
    29                 initialize: function( url, options ) { 
     25                initialize: function( params, options ) { 
    3026                        var self = this; 
    3127 
    32                         api.Messenger.prototype.initialize.call( this, url, null, options ); 
     28                        api.Messenger.prototype.initialize.call( this, params, options ); 
    3329 
    3430                        this.body = $( document.body ); 
    3531                        this.body.on( 'click.preview', 'a', function( event ) { 
     
    3935                        }); 
    4036 
    4137                        // You cannot submit forms. 
    42                         // @todo: Namespace customizer settings so that we can mix the 
    43                         //        $_POST data with the customize setting $_POST data. 
     38                        // @todo: Allow form submissions by mixing $_POST data with the customize setting $_POST data. 
    4439                        this.body.on( 'submit.preview', 'form', function( event ) { 
    4540                                event.preventDefault(); 
    4641                        }); 
     
    6358 
    6459                var preview, bg; 
    6560 
    66                 preview = new api.Preview( window.location.href ); 
     61                preview = new api.Preview({ 
     62                        url: window.location.href, 
     63                        channel: api.settings.channel 
     64                }); 
    6765 
    68                 $.each( api.settings.values, function( id, value ) { 
    69                         api.create( id, value ); 
     66                preview.bind( 'settings', function( values ) { 
     67                        $.each( values, function( id, value ) { 
     68                                if ( api.has( id ) ) 
     69                                        api( id ).set( value ); 
     70                                else 
     71                                        api.create( id, value ); 
     72                        }); 
    7073                }); 
    7174 
     75                preview.trigger( 'settings', api.settings.values ); 
     76 
    7277                preview.bind( 'setting', function( args ) { 
    73                         var value = api( args.shift() ); 
    74                         if ( value ) 
     78                        var value; 
     79 
     80                        args = args.slice(); 
     81 
     82                        if ( value = api( args.shift() ) ) 
    7583                                value.set.apply( value, args ); 
    7684                }); 
    7785 
     86                preview.bind( 'sync', function( events ) { 
     87                        $.each( events, function( event, args ) { 
     88                                preview.trigger( event, args ); 
     89                        }); 
     90                        preview.send( 'synced' ); 
     91                }) 
     92 
     93                preview.send( 'ready' ); 
     94 
    7895                /* Custom Backgrounds */ 
    7996                bg = $.map(['color', 'image', 'position_x', 'repeat', 'attachment'], function( prop ) { 
    8097                        return 'background_' + prop; 
  • wp-includes/js/customize-loader.dev.js

     
    7777                        this.iframe.one( 'load', this.loaded ); 
    7878 
    7979                        // Create a postMessage connection with the iframe. 
    80                         this.messenger = new api.Messenger( src, this.iframe[0].contentWindow ); 
     80                        this.messenger = new api.Messenger({ 
     81                                url: src, 
     82                                channel: 'loader', 
     83                                targetWindow: this.iframe[0].contentWindow 
     84                        }); 
    8185 
    8286                        // Wait for the connection from the iframe before sending any postMessage events. 
    8387                        this.messenger.bind( 'ready', function() { 
  • wp-admin/js/customize-controls.dev.js

     
    281281        // Create the collection of Control objects. 
    282282        api.control = new api.Values({ defaultConstructor: api.Control }); 
    283283 
     284        api.PreviewFrame = api.Messenger.extend({ 
     285                sensitivity: 2000, 
     286 
     287                initialize: function( params, options ) { 
     288                        var loaded   = false, 
     289                                ready    = false, 
     290                                deferred = $.Deferred(), 
     291                                self     = this; 
     292 
     293                        // This is the promise object. 
     294                        deferred.promise( this ); 
     295 
     296                        this.previewer = params.previewer; 
     297 
     298                        $.extend( params, { channel: api.PreviewFrame.uuid() }); 
     299 
     300                        api.Messenger.prototype.initialize.call( this, params, options ); 
     301 
     302                        this.bind( 'ready', function() { 
     303                                ready = true; 
     304 
     305                                if ( loaded ) 
     306                                        deferred.resolveWith( self ); 
     307                        }); 
     308 
     309                        params.query = $.extend( params.query || {}, { customize_messenger_channel: this.channel() }); 
     310 
     311                        this.request = $.ajax( this.url(), { 
     312                                type: 'POST', 
     313                                data: params.query, 
     314                                xhrFields: { 
     315                                        withCredentials: true 
     316                                } 
     317                        } ); 
     318 
     319                        this.request.fail( function() { 
     320                                deferred.rejectWith( self, [ 'request failure' ] ); 
     321                        }); 
     322 
     323                        this.request.done( function( response ) { 
     324                                var location = self.request.getResponseHeader('Location'), 
     325                                        signature = 'WP_CUSTOMIZER_SIGNATURE', 
     326                                        index; 
     327 
     328                                // Check if the location response header differs from the current URL. 
     329                                // If so, the request was redirected; try loading the requested page. 
     330                                if ( location && location != self.url() ) { 
     331                                        deferred.rejectWith( self, [ 'redirect', location ] ); 
     332                                        return; 
     333                                } 
     334 
     335                                // Check for a signature in the request. 
     336                                index = response.lastIndexOf( signature ); 
     337                                if ( -1 === index || index < response.lastIndexOf('</html>') ) { 
     338                                        deferred.rejectWith( self, [ 'unsigned' ] ); 
     339                                        return; 
     340                                } 
     341 
     342                                // Strip the signature from the request. 
     343                                response = response.slice( 0, index ) + response.slice( index + signature.length ); 
     344 
     345                                // Create the iframe and inject the html content. 
     346                                // Strip the signature from the request. 
     347                                response = response.slice( 0, index ) + response.slice( index + signature.length ); 
     348 
     349                                // Create the iframe and inject the html content. 
     350                                self.iframe = $('<iframe />').appendTo( self.previewer.container ); 
     351 
     352                                // Bind load event after the iframe has been added to the page; 
     353                                // otherwise it will fire when injected into the DOM. 
     354                                self.iframe.one( 'load', function() { 
     355                                        loaded = true; 
     356 
     357                                        if ( ready ) { 
     358                                                deferred.resolveWith( self ); 
     359                                        } else { 
     360                                                setTimeout( function() { 
     361                                                        deferred.rejectWith( self, [ 'ready timeout' ] ); 
     362                                                }, self.sensitivity ); 
     363                                        } 
     364                                }); 
     365 
     366                                self.targetWindow( self.iframe[0].contentWindow ); 
     367 
     368                                self.targetWindow().document.open(); 
     369                                self.targetWindow().document.write( response ); 
     370                                self.targetWindow().document.close(); 
     371                        }); 
     372                }, 
     373 
     374                destroy: function() { 
     375                        api.Messenger.prototype.destroy.call( this ); 
     376                        this.request.abort(); 
     377 
     378                        if ( this.iframe ) 
     379                                this.iframe.remove(); 
     380 
     381                        delete this.request; 
     382                        delete this.iframe; 
     383                        delete this.targetWindow; 
     384                } 
     385        }); 
     386 
     387        (function(){ 
     388                var uuid = 0; 
     389                api.PreviewFrame.uuid = function() { 
     390                        return 'preview-' + uuid++; 
     391                }; 
     392        }()); 
     393 
    284394        api.Previewer = api.Messenger.extend({ 
    285395                refreshBuffer: 250, 
    286396 
     
    295405 
    296406                        $.extend( this, options || {} ); 
    297407 
    298                         this.loaded = $.proxy( this.loaded, this ); 
    299  
    300408                        /* 
    301409                         * Wrap this.refresh to prevent it from hammering the servers: 
    302410                         * 
     
    320428                                return function() { 
    321429                                        if ( typeof timeout !== 'number' ) { 
    322430                                                if ( self.loading ) { 
    323                                                         self.loading.remove(); 
    324                                                         delete self.loading; 
    325                                                         self.loader(); 
     431                                                        self.abort(); 
    326432                                                } else { 
    327433                                                        return callback(); 
    328434                                                } 
     
    336442                        this.container   = api.ensure( params.container ); 
    337443                        this.allowedUrls = params.allowedUrls; 
    338444 
    339                         api.Messenger.prototype.initialize.call( this, params.url ); 
     445                        api.Messenger.prototype.initialize.call( this, params ); 
    340446 
    341447                        // We're dynamically generating the iframe, so the origin is set 
    342448                        // to the current window's location, not the url's. 
     
    391497                        // Update the URL when the iframe sends a URL message. 
    392498                        this.bind( 'url', this.url ); 
    393499                }, 
    394                 loader: function() { 
    395                         if ( this.loading ) 
    396                                 return this.loading; 
    397500 
    398                         this.loading = $('<iframe />').appendTo( this.container ); 
     501                query: function() {}, 
    399502 
    400                         return this.loading; 
     503                abort: function() { 
     504                        if ( this.loading ) { 
     505                                this.loading.destroy(); 
     506                                delete this.loading; 
     507                        } 
    401508                }, 
    402                 loaded: function() { 
    403                         if ( this.iframe ) 
    404                                 this.iframe.remove(); 
    405509 
    406                         this.iframe = this.loading; 
    407                         delete this.loading; 
    408  
    409                         this.targetWindow( this.iframe[0].contentWindow ); 
    410                         this.send( 'scroll', this.scroll ); 
    411                 }, 
    412                 query: function() {}, 
    413510                refresh: function() { 
    414511                        var self = this; 
    415512 
    416                         if ( this.request ) 
    417                                 this.request.abort(); 
     513                        this.abort(); 
    418514 
    419                         this.request = $.ajax( this.url(), { 
    420                                 type: 'POST', 
    421                                 data: this.query() || {}, 
    422                                 success: function( response ) { 
    423                                         var iframe = self.loader()[0].contentWindow, 
    424                                                 location = self.request.getResponseHeader('Location'), 
    425                                                 signature = 'WP_CUSTOMIZER_SIGNATURE', 
    426                                                 index; 
     515                        this.loading = new api.PreviewFrame({ 
     516                                url:       this.url(), 
     517                                query:     this.query() || {}, 
     518                                previewer: this 
     519                        }); 
    427520 
    428                                         // Check if the location response header differs from the current URL. 
    429                                         // If so, the request was redirected; try loading the requested page. 
    430                                         if ( location && location != self.url() ) { 
    431                                                 self.url( location ); 
    432                                                 return; 
    433                                         } 
     521                        this.loading.done( function() { 
     522                                // 'this' is the loading frame 
     523                                this.bind( 'synced', function() { 
     524                                        if ( self.iframe ) 
     525                                                self.iframe.destroy(); 
     526                                        self.iframe = this; 
     527                                        delete self.loading; 
    434528 
    435                                         // Check for a signature in the request. 
    436                                         index = response.lastIndexOf( signature ); 
    437                                         if ( -1 === index || index < response.lastIndexOf('</html>') ) 
    438                                                 return; 
     529                                        self.targetWindow( this.targetWindow() ); 
     530                                        self.channel( this.channel() ); 
     531                                }); 
    439532 
    440                                         // Strip the signature from the request. 
    441                                         response = response.slice( 0, index ) + response.slice( index + signature.length ); 
     533                                this.send( 'sync', { 
     534                                        scroll:   self.scroll, 
     535                                        settings: api.get() 
     536                                }); 
     537                        }); 
    442538 
    443                                         self.loader().one( 'load', self.loaded ); 
    444  
    445                                         iframe.document.open(); 
    446                                         iframe.document.write( response ); 
    447                                         iframe.document.close(); 
    448                                 }, 
    449                                 xhrFields: { 
    450                                         withCredentials: true 
    451                                 } 
    452                         } ); 
     539                        this.loading.fail( function( reason, location ) { 
     540                                if ( 'redirect' === reason && location ) 
     541                                        self.url( location ); 
     542                        }); 
    453543                } 
    454544        }); 
    455545 
     
    617707                }); 
    618708 
    619709                // Create a potential postMessage connection with the parent frame. 
    620                 parent = new api.Messenger( api.settings.url.parent ); 
     710                parent = new api.Messenger({ 
     711                        url: api.settings.url.parent, 
     712                        channel: 'loader' 
     713                }); 
    621714 
    622715                // If we receive a 'back' event, we're inside an iframe. 
    623716                // Send any clicks to the 'Return' link to the parent page.