Make WordPress Core

Ticket #20811: 20811.diff

File 20811.diff, 14.1 KB (added by koopersmith, 13 years 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                                self.iframe = $('<iframe />').one( 'load', function() {
     347                                        loaded = true;
     348
     349                                        if ( ready ) {
     350                                                deferred.resolveWith( self );
     351                                        } else {
     352                                                setTimeout( function() {
     353                                                        deferred.rejectWith( self, [ 'ready timeout' ] );
     354                                                }, self.sensitivity );
     355                                        }
     356                                });
     357
     358                                self.iframe.appendTo( self.previewer.container );
     359                                self.targetWindow( self.iframe[0].contentWindow );
     360
     361                                self.targetWindow().document.open();
     362                                self.targetWindow().document.write( response );
     363                                self.targetWindow().document.close();
     364                        });
     365                },
     366
     367                destroy: function() {
     368                        api.Messenger.prototype.destroy.call( this );
     369                        this.request.abort();
     370
     371                        if ( this.iframe )
     372                                this.iframe.remove();
     373
     374                        delete this.request;
     375                        delete this.iframe;
     376                        delete this.targetWindow;
     377                }
     378        });
     379
     380        (function(){
     381                var uuid = 0;
     382                api.PreviewFrame.uuid = function() {
     383                        return 'preview-' + uuid++;
     384                };
     385        }());
     386
    284387        api.Previewer = api.Messenger.extend({
    285388                refreshBuffer: 250,
    286389
     
    295398
    296399                        $.extend( this, options || {} );
    297400
    298                         this.loaded = $.proxy( this.loaded, this );
    299 
    300401                        /*
    301402                         * Wrap this.refresh to prevent it from hammering the servers:
    302403                         *
     
    320421                                return function() {
    321422                                        if ( typeof timeout !== 'number' ) {
    322423                                                if ( self.loading ) {
    323                                                         self.loading.remove();
    324                                                         delete self.loading;
    325                                                         self.loader();
     424                                                        self.abort();
    326425                                                } else {
    327426                                                        return callback();
    328427                                                }
     
    336435                        this.container   = api.ensure( params.container );
    337436                        this.allowedUrls = params.allowedUrls;
    338437
    339                         api.Messenger.prototype.initialize.call( this, params.url );
     438                        api.Messenger.prototype.initialize.call( this, params );
    340439
    341440                        // We're dynamically generating the iframe, so the origin is set
    342441                        // to the current window's location, not the url's.
     
    391490                        // Update the URL when the iframe sends a URL message.
    392491                        this.bind( 'url', this.url );
    393492                },
    394                 loader: function() {
    395                         if ( this.loading )
    396                                 return this.loading;
    397493
    398                         this.loading = $('<iframe />').appendTo( this.container );
     494                query: function() {},
    399495
    400                         return this.loading;
     496                abort: function() {
     497                        if ( this.loading ) {
     498                                this.loading.destroy();
     499                                delete this.loading;
     500                        }
    401501                },
    402                 loaded: function() {
    403                         if ( this.iframe )
    404                                 this.iframe.remove();
    405502
    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() {},
    413503                refresh: function() {
    414504                        var self = this;
    415505
    416                         if ( this.request )
    417                                 this.request.abort();
     506                        this.abort();
    418507
    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;
     508                        this.loading = new api.PreviewFrame({
     509                                url:       this.url(),
     510                                query:     this.query() || {},
     511                                previewer: this
     512                        });
    427513
    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                                         }
     514                        this.loading.done( function() {
     515                                // 'this' is the loading frame
     516                                this.bind( 'synced', function() {
     517                                        if ( self.iframe )
     518                                                self.iframe.destroy();
     519                                        self.iframe = this;
     520                                        delete self.loading;
    434521
    435                                         // Check for a signature in the request.
    436                                         index = response.lastIndexOf( signature );
    437                                         if ( -1 === index || index < response.lastIndexOf('</html>') )
    438                                                 return;
     522                                        self.targetWindow( this.targetWindow() );
     523                                        self.channel( this.channel() );
     524                                });
    439525
    440                                         // Strip the signature from the request.
    441                                         response = response.slice( 0, index ) + response.slice( index + signature.length );
     526                                this.send( 'sync', {
     527                                        scroll:   self.scroll,
     528                                        settings: api.get()
     529                                });
     530                        });
    442531
    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                         } );
     532                        this.loading.fail( function( reason, location ) {
     533                                if ( 'redirect' === reason && location )
     534                                        self.url( location );
     535                        });
    453536                }
    454537        });
    455538
     
    617700                });
    618701
    619702                // Create a potential postMessage connection with the parent frame.
    620                 parent = new api.Messenger( api.settings.url.parent );
     703                parent = new api.Messenger({
     704                        url: api.settings.url.parent,
     705                        channel: 'loader'
     706                });
    621707
    622708                // If we receive a 'back' event, we're inside an iframe.
    623709                // Send any clicks to the 'Return' link to the parent page.