Ticket #20811: 20811.2.diff
File 20811.2.diff, 14.4 KB (added by , 13 years ago) |
---|
-
wp-includes/class-wp-customize-manager.php
290 290 */ 291 291 public function customize_preview_settings() { 292 292 $settings = array( 293 'values' => array(), 293 'values' => array(), 294 'channel' => esc_js( $_POST['customize_messenger_channel'] ), 294 295 ); 295 296 296 297 foreach ( $this->settings as $id => $setting ) { -
wp-includes/js/customize-base.dev.js
302 302 return this.add( id, new this.defaultConstructor( api.Class.applicator, slice.call( arguments, 1 ) ) ); 303 303 }, 304 304 305 get: function() {306 var result = {};305 each: function( callback, context ) { 306 context = typeof context === 'undefined' ? this : context; 307 307 308 308 $.each( this._value, function( key, obj ) { 309 result[ key ] = obj.get(); 310 } ); 311 return result; 309 callback.call( context, obj, key ); 310 }); 312 311 }, 313 312 314 313 remove: function( id ) { … … 481 480 return this[ key ] = new api.Value( initial, options ); 482 481 }, 483 482 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 ) { 485 493 // Target the parent frame by default, but only if a parent frame exists. 486 494 var defaultTarget = window.parent == window ? null : window.parent; 487 495 488 496 $.extend( this, options || {} ); 489 497 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 ) { 493 502 return to.replace( /([^:]+:\/\/[^\/]+).*/, '$1' ); 494 503 }); 495 504 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 ); 496 510 this.receive = $.proxy( this.receive, this ); 511 this.receive.guid = $.guid++; 512 497 513 $( window ).on( 'message', this.receive ); 498 514 }, 499 515 … … 515 531 516 532 message = JSON.parse( event.data ); 517 533 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 ); 520 543 }, 521 544 522 545 send: function( id, data ) { … … 527 550 if ( ! this.url() || ! this.targetWindow() ) 528 551 return; 529 552 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() ); 532 558 } 533 559 }); 534 560 … … 540 566 * ===================================================================== */ 541 567 542 568 api = $.extend( new api.Values(), api ); 569 api.get = function() { 570 var result = {}; 543 571 572 this.each( function( obj, key ) { 573 result[ key ] = obj.get(); 574 }); 575 576 return result; 577 }; 578 544 579 // Expose the API to the world. 545 580 exports.customize = api; 546 581 })( wp, jQuery ); -
wp-includes/js/customize-preview.dev.js
21 21 /** 22 22 * Requires params: 23 23 * - url - the URL of preview frame 24 *25 * @todo: Perhaps add a window.onbeforeunload dialog in case the theme26 * somehow attempts to leave the page and we don't catch it27 * (which really shouldn't happen).28 24 */ 29 initialize: function( url, options ) {25 initialize: function( params, options ) { 30 26 var self = this; 31 27 32 api.Messenger.prototype.initialize.call( this, url, null, options );28 api.Messenger.prototype.initialize.call( this, params, options ); 33 29 34 30 this.body = $( document.body ); 35 31 this.body.on( 'click.preview', 'a', function( event ) { … … 39 35 }); 40 36 41 37 // 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. 44 39 this.body.on( 'submit.preview', 'form', function( event ) { 45 40 event.preventDefault(); 46 41 }); … … 63 58 64 59 var preview, bg; 65 60 66 preview = new api.Preview( window.location.href ); 61 preview = new api.Preview({ 62 url: window.location.href, 63 channel: api.settings.channel 64 }); 67 65 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 }); 70 73 }); 71 74 75 preview.trigger( 'settings', api.settings.values ); 76 72 77 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() ) ) 75 83 value.set.apply( value, args ); 76 84 }); 77 85 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 78 95 /* Custom Backgrounds */ 79 96 bg = $.map(['color', 'image', 'position_x', 'repeat', 'attachment'], function( prop ) { 80 97 return 'background_' + prop; -
wp-includes/js/customize-loader.dev.js
77 77 this.iframe.one( 'load', this.loaded ); 78 78 79 79 // 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 }); 81 85 82 86 // Wait for the connection from the iframe before sending any postMessage events. 83 87 this.messenger.bind( 'ready', function() { -
wp-admin/js/customize-controls.dev.js
281 281 // Create the collection of Control objects. 282 282 api.control = new api.Values({ defaultConstructor: api.Control }); 283 283 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 284 394 api.Previewer = api.Messenger.extend({ 285 395 refreshBuffer: 250, 286 396 … … 295 405 296 406 $.extend( this, options || {} ); 297 407 298 this.loaded = $.proxy( this.loaded, this );299 300 408 /* 301 409 * Wrap this.refresh to prevent it from hammering the servers: 302 410 * … … 320 428 return function() { 321 429 if ( typeof timeout !== 'number' ) { 322 430 if ( self.loading ) { 323 self.loading.remove(); 324 delete self.loading; 325 self.loader(); 431 self.abort(); 326 432 } else { 327 433 return callback(); 328 434 } … … 336 442 this.container = api.ensure( params.container ); 337 443 this.allowedUrls = params.allowedUrls; 338 444 339 api.Messenger.prototype.initialize.call( this, params .url);445 api.Messenger.prototype.initialize.call( this, params ); 340 446 341 447 // We're dynamically generating the iframe, so the origin is set 342 448 // to the current window's location, not the url's. … … 391 497 // Update the URL when the iframe sends a URL message. 392 498 this.bind( 'url', this.url ); 393 499 }, 394 loader: function() {395 if ( this.loading )396 return this.loading;397 500 398 this.loading = $('<iframe />').appendTo( this.container );501 query: function() {}, 399 502 400 return this.loading; 503 abort: function() { 504 if ( this.loading ) { 505 this.loading.destroy(); 506 delete this.loading; 507 } 401 508 }, 402 loaded: function() {403 if ( this.iframe )404 this.iframe.remove();405 509 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() {},413 510 refresh: function() { 414 511 var self = this; 415 512 416 if ( this.request ) 417 this.request.abort(); 513 this.abort(); 418 514 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 }); 427 520 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; 434 528 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 }); 439 532 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 }); 442 538 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 }); 453 543 } 454 544 }); 455 545 … … 617 707 }); 618 708 619 709 // 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 }); 621 714 622 715 // If we receive a 'back' event, we're inside an iframe. 623 716 // Send any clicks to the 'Return' link to the parent page.