| [ Index ] |
PHP Cross Reference of WordPress |
[Summary view] [Print] [Text view]
1 (function( exports, $ ){ 2 var api = wp.customize; 3 4 /* 5 * @param options 6 * - previewer - The Previewer instance to sync with. 7 * - transport - The transport to use for previewing. Supports 'refresh' and 'postMessage'. 8 */ 9 api.Setting = api.Value.extend({ 10 initialize: function( id, value, options ) { 11 var element; 12 13 api.Value.prototype.initialize.call( this, value, options ); 14 15 this.id = id; 16 this.transport = this.transport || 'refresh'; 17 18 this.bind( this.preview ); 19 }, 20 preview: function() { 21 switch ( this.transport ) { 22 case 'refresh': 23 return this.previewer.refresh(); 24 case 'postMessage': 25 return this.previewer.send( 'setting', [ this.id, this() ] ); 26 } 27 } 28 }); 29 30 api.Control = api.Class.extend({ 31 initialize: function( id, options ) { 32 var control = this, 33 nodes, radios, settings; 34 35 this.params = {}; 36 $.extend( this, options || {} ); 37 38 this.id = id; 39 this.selector = '#customize-control-' + id.replace( ']', '' ).replace( '[', '-' ); 40 this.container = $( this.selector ); 41 42 settings = $.map( this.params.settings, function( value ) { 43 return value; 44 }); 45 46 api.apply( api, settings.concat( function() { 47 var key; 48 49 control.settings = {}; 50 for ( key in control.params.settings ) { 51 control.settings[ key ] = api( control.params.settings[ key ] ); 52 } 53 54 control.setting = control.settings['default'] || null; 55 control.ready(); 56 }) ); 57 58 control.elements = []; 59 60 nodes = this.container.find('[data-customize-setting-link]'); 61 radios = {}; 62 63 nodes.each( function() { 64 var node = $(this), 65 name; 66 67 if ( node.is(':radio') ) { 68 name = node.prop('name'); 69 if ( radios[ name ] ) 70 return; 71 72 radios[ name ] = true; 73 node = nodes.filter( '[name="' + name + '"]' ); 74 } 75 76 api( node.data('customizeSettingLink'), function( setting ) { 77 var element = new api.Element( node ); 78 control.elements.push( element ); 79 element.sync( setting ); 80 element.set( setting() ); 81 }); 82 }); 83 }, 84 85 ready: function() {}, 86 87 dropdownInit: function() { 88 var control = this, 89 statuses = this.container.find('.dropdown-status'), 90 params = this.params, 91 update = function( to ) { 92 if ( typeof to === 'string' && params.statuses && params.statuses[ to ] ) 93 statuses.html( params.statuses[ to ] ).show(); 94 else 95 statuses.hide(); 96 }; 97 98 var toggleFreeze = false; 99 100 // Support the .dropdown class to open/close complex elements 101 this.container.on( 'click keydown', '.dropdown', function( event ) { 102 if ( event.type === 'keydown' && 13 !== event.which ) // enter 103 return; 104 105 event.preventDefault(); 106 107 if (!toggleFreeze) 108 control.container.toggleClass('open'); 109 110 if ( control.container.hasClass('open') ) 111 control.container.parent().parent().find('li.library-selected').focus(); 112 113 // Don't want to fire focus and click at same time 114 toggleFreeze = true; 115 setTimeout(function () { 116 toggleFreeze = false; 117 }, 400); 118 }); 119 120 this.setting.bind( update ); 121 update( this.setting() ); 122 } 123 }); 124 125 api.ColorControl = api.Control.extend({ 126 ready: function() { 127 var control = this, 128 picker = this.container.find('.color-picker-hex'); 129 130 picker.val( control.setting() ).wpColorPicker({ 131 change: function( event, options ) { 132 control.setting.set( picker.wpColorPicker('color') ); 133 }, 134 clear: function() { 135 control.setting.set( false ); 136 } 137 }); 138 } 139 }); 140 141 api.UploadControl = api.Control.extend({ 142 ready: function() { 143 var control = this; 144 145 this.params.removed = this.params.removed || ''; 146 147 this.success = $.proxy( this.success, this ); 148 149 this.uploader = $.extend({ 150 container: this.container, 151 browser: this.container.find('.upload'), 152 dropzone: this.container.find('.upload-dropzone'), 153 success: this.success, 154 plupload: {}, 155 params: {} 156 }, this.uploader || {} ); 157 158 if ( control.params.extensions ) { 159 control.uploader.plupload.filters = [{ 160 title: api.l10n.allowedFiles, 161 extensions: control.params.extensions 162 }]; 163 } 164 165 if ( control.params.context ) 166 control.uploader.params['post_data[context]'] = this.params.context; 167 168 if ( api.settings.theme.stylesheet ) 169 control.uploader.params['post_data[theme]'] = api.settings.theme.stylesheet; 170 171 this.uploader = new wp.Uploader( this.uploader ); 172 173 this.remover = this.container.find('.remove'); 174 this.remover.on( 'click keydown', function( event ) { 175 if ( event.type === 'keydown' && 13 !== event.which ) // enter 176 return; 177 178 control.setting.set( control.params.removed ); 179 event.preventDefault(); 180 }); 181 182 this.removerVisibility = $.proxy( this.removerVisibility, this ); 183 this.setting.bind( this.removerVisibility ); 184 this.removerVisibility( this.setting.get() ); 185 }, 186 success: function( attachment ) { 187 this.setting.set( attachment.get('url') ); 188 }, 189 removerVisibility: function( to ) { 190 this.remover.toggle( to != this.params.removed ); 191 } 192 }); 193 194 api.ImageControl = api.UploadControl.extend({ 195 ready: function() { 196 var control = this, 197 panels; 198 199 this.uploader = { 200 init: function( up ) { 201 var fallback, button; 202 203 if ( this.supports.dragdrop ) 204 return; 205 206 // Maintain references while wrapping the fallback button. 207 fallback = control.container.find( '.upload-fallback' ); 208 button = fallback.children().detach(); 209 210 this.browser.detach().empty().append( button ); 211 fallback.append( this.browser ).show(); 212 } 213 }; 214 215 api.UploadControl.prototype.ready.call( this ); 216 217 this.thumbnail = this.container.find('.preview-thumbnail img'); 218 this.thumbnailSrc = $.proxy( this.thumbnailSrc, this ); 219 this.setting.bind( this.thumbnailSrc ); 220 221 this.library = this.container.find('.library'); 222 223 // Generate tab objects 224 this.tabs = {}; 225 panels = this.library.find('.library-content'); 226 227 this.library.children('ul').children('li').each( function() { 228 var link = $(this), 229 id = link.data('customizeTab'), 230 panel = panels.filter('[data-customize-tab="' + id + '"]'); 231 232 control.tabs[ id ] = { 233 both: link.add( panel ), 234 link: link, 235 panel: panel 236 }; 237 }); 238 239 // Bind tab switch events 240 this.library.children('ul').on( 'click keydown', 'li', function( event ) { 241 if ( event.type === 'keydown' && 13 !== event.which ) // enter 242 return; 243 244 var id = $(this).data('customizeTab'), 245 tab = control.tabs[ id ]; 246 247 event.preventDefault(); 248 249 if ( tab.link.hasClass('library-selected') ) 250 return; 251 252 control.selected.both.removeClass('library-selected'); 253 control.selected = tab; 254 control.selected.both.addClass('library-selected'); 255 }); 256 257 // Bind events to switch image urls. 258 this.library.on( 'click keydown', 'a', function( event ) { 259 if ( event.type === 'keydown' && 13 !== event.which ) // enter 260 return; 261 262 var value = $(this).data('customizeImageValue'); 263 264 if ( value ) { 265 control.setting.set( value ); 266 event.preventDefault(); 267 } 268 }); 269 270 if ( this.tabs.uploaded ) { 271 this.tabs.uploaded.target = this.library.find('.uploaded-target'); 272 if ( ! this.tabs.uploaded.panel.find('.thumbnail').length ) 273 this.tabs.uploaded.both.addClass('hidden'); 274 } 275 276 // Select a tab 277 panels.each( function() { 278 var tab = control.tabs[ $(this).data('customizeTab') ]; 279 280 // Select the first visible tab. 281 if ( ! tab.link.hasClass('hidden') ) { 282 control.selected = tab; 283 tab.both.addClass('library-selected'); 284 return false; 285 } 286 }); 287 288 this.dropdownInit(); 289 }, 290 success: function( attachment ) { 291 api.UploadControl.prototype.success.call( this, attachment ); 292 293 // Add the uploaded image to the uploaded tab. 294 if ( this.tabs.uploaded && this.tabs.uploaded.target.length ) { 295 this.tabs.uploaded.both.removeClass('hidden'); 296 297 // @todo: Do NOT store this on the attachment model. That is bad. 298 attachment.element = $( '<a href="#" class="thumbnail"></a>' ) 299 .data( 'customizeImageValue', attachment.get('url') ) 300 .append( '<img src="' + attachment.get('url')+ '" />' ) 301 .appendTo( this.tabs.uploaded.target ); 302 } 303 }, 304 thumbnailSrc: function( to ) { 305 if ( /^(https?:)?\/\//.test( to ) ) 306 this.thumbnail.prop( 'src', to ).show(); 307 else 308 this.thumbnail.hide(); 309 } 310 }); 311 312 // Change objects contained within the main customize object to Settings. 313 api.defaultConstructor = api.Setting; 314 315 // Create the collection of Control objects. 316 api.control = new api.Values({ defaultConstructor: api.Control }); 317 318 api.PreviewFrame = api.Messenger.extend({ 319 sensitivity: 2000, 320 321 initialize: function( params, options ) { 322 var deferred = $.Deferred(), 323 self = this; 324 325 // This is the promise object. 326 deferred.promise( this ); 327 328 this.container = params.container; 329 this.signature = params.signature; 330 331 $.extend( params, { channel: api.PreviewFrame.uuid() }); 332 333 api.Messenger.prototype.initialize.call( this, params, options ); 334 335 this.add( 'previewUrl', params.previewUrl ); 336 337 this.query = $.extend( params.query || {}, { customize_messenger_channel: this.channel() }); 338 339 this.run( deferred ); 340 }, 341 342 run: function( deferred ) { 343 var self = this, 344 loaded = false, 345 ready = false; 346 347 if ( this._ready ) 348 this.unbind( 'ready', this._ready ); 349 350 this._ready = function() { 351 ready = true; 352 353 if ( loaded ) 354 deferred.resolveWith( self ); 355 }; 356 357 this.bind( 'ready', this._ready ); 358 359 this.request = $.ajax( this.previewUrl(), { 360 type: 'POST', 361 data: this.query, 362 xhrFields: { 363 withCredentials: true 364 } 365 } ); 366 367 this.request.fail( function() { 368 deferred.rejectWith( self, [ 'request failure' ] ); 369 }); 370 371 this.request.done( function( response ) { 372 var location = self.request.getResponseHeader('Location'), 373 signature = self.signature, 374 index; 375 376 // Check if the location response header differs from the current URL. 377 // If so, the request was redirected; try loading the requested page. 378 if ( location && location != self.previewUrl() ) { 379 deferred.rejectWith( self, [ 'redirect', location ] ); 380 return; 381 } 382 383 // Check if the user is not logged in. 384 if ( '0' === response ) { 385 self.login( deferred ); 386 return; 387 } 388 389 // Check for cheaters. 390 if ( '-1' === response ) { 391 deferred.rejectWith( self, [ 'cheatin' ] ); 392 return; 393 } 394 395 // Check for a signature in the request. 396 index = response.lastIndexOf( signature ); 397 if ( -1 === index || index < response.lastIndexOf('</html>') ) { 398 deferred.rejectWith( self, [ 'unsigned' ] ); 399 return; 400 } 401 402 // Strip the signature from the request. 403 response = response.slice( 0, index ) + response.slice( index + signature.length ); 404 405 // Create the iframe and inject the html content. 406 self.iframe = $('<iframe />').appendTo( self.container ); 407 408 // Bind load event after the iframe has been added to the page; 409 // otherwise it will fire when injected into the DOM. 410 self.iframe.one( 'load', function() { 411 loaded = true; 412 413 if ( ready ) { 414 deferred.resolveWith( self ); 415 } else { 416 setTimeout( function() { 417 deferred.rejectWith( self, [ 'ready timeout' ] ); 418 }, self.sensitivity ); 419 } 420 }); 421 422 self.targetWindow( self.iframe[0].contentWindow ); 423 424 self.targetWindow().document.open(); 425 self.targetWindow().document.write( response ); 426 self.targetWindow().document.close(); 427 }); 428 }, 429 430 login: function( deferred ) { 431 var self = this, 432 reject; 433 434 reject = function() { 435 deferred.rejectWith( self, [ 'logged out' ] ); 436 }; 437 438 if ( this.triedLogin ) 439 return reject(); 440 441 // Check if we have an admin cookie. 442 $.get( api.settings.url.ajax, { 443 action: 'logged-in' 444 }).fail( reject ).done( function( response ) { 445 var iframe; 446 447 if ( '1' !== response ) 448 reject(); 449 450 iframe = $('<iframe src="' + self.previewUrl() + '" />').hide(); 451 iframe.appendTo( self.container ); 452 iframe.load( function() { 453 self.triedLogin = true; 454 455 iframe.remove(); 456 self.run( deferred ); 457 }); 458 }); 459 }, 460 461 destroy: function() { 462 api.Messenger.prototype.destroy.call( this ); 463 this.request.abort(); 464 465 if ( this.iframe ) 466 this.iframe.remove(); 467 468 delete this.request; 469 delete this.iframe; 470 delete this.targetWindow; 471 } 472 }); 473 474 (function(){ 475 var uuid = 0; 476 api.PreviewFrame.uuid = function() { 477 return 'preview-' + uuid++; 478 }; 479 }()); 480 481 api.Previewer = api.Messenger.extend({ 482 refreshBuffer: 250, 483 484 /** 485 * Requires params: 486 * - container - a selector or jQuery element 487 * - previewUrl - the URL of preview frame 488 */ 489 initialize: function( params, options ) { 490 var self = this, 491 rscheme = /^https?/, 492 url; 493 494 $.extend( this, options || {} ); 495 496 /* 497 * Wrap this.refresh to prevent it from hammering the servers: 498 * 499 * If refresh is called once and no other refresh requests are 500 * loading, trigger the request immediately. 501 * 502 * If refresh is called while another refresh request is loading, 503 * debounce the refresh requests: 504 * 1. Stop the loading request (as it is instantly outdated). 505 * 2. Trigger the new request once refresh hasn't been called for 506 * self.refreshBuffer milliseconds. 507 */ 508 this.refresh = (function( self ) { 509 var refresh = self.refresh, 510 callback = function() { 511 timeout = null; 512 refresh.call( self ); 513 }, 514 timeout; 515 516 return function() { 517 if ( typeof timeout !== 'number' ) { 518 if ( self.loading ) { 519 self.abort(); 520 } else { 521 return callback(); 522 } 523 } 524 525 clearTimeout( timeout ); 526 timeout = setTimeout( callback, self.refreshBuffer ); 527 }; 528 })( this ); 529 530 this.container = api.ensure( params.container ); 531 this.allowedUrls = params.allowedUrls; 532 this.signature = params.signature; 533 534 params.url = window.location.href; 535 536 api.Messenger.prototype.initialize.call( this, params ); 537 538 this.add( 'scheme', this.origin() ).link( this.origin ).setter( function( to ) { 539 var match = to.match( rscheme ); 540 return match ? match[0] : ''; 541 }); 542 543 // Limit the URL to internal, front-end links. 544 // 545 // If the frontend and the admin are served from the same domain, load the 546 // preview over ssl if the customizer is being loaded over ssl. This avoids 547 // insecure content warnings. This is not attempted if the admin and frontend 548 // are on different domains to avoid the case where the frontend doesn't have 549 // ssl certs. 550 551 this.add( 'previewUrl', params.previewUrl ).setter( function( to ) { 552 var result; 553 554 // Check for URLs that include "/wp-admin/" or end in "/wp-admin". 555 // Strip hashes and query strings before testing. 556 if ( /\/wp-admin(\/|$)/.test( to.replace(/[#?].*$/, '') ) ) 557 return null; 558 559 // Attempt to match the URL to the control frame's scheme 560 // and check if it's allowed. If not, try the original URL. 561 $.each([ to.replace( rscheme, self.scheme() ), to ], function( i, url ) { 562 $.each( self.allowedUrls, function( i, allowed ) { 563 if ( 0 === url.indexOf( allowed ) ) { 564 result = url; 565 return false; 566 } 567 }); 568 if ( result ) 569 return false; 570 }); 571 572 // If we found a matching result, return it. If not, bail. 573 return result ? result : null; 574 }); 575 576 // Refresh the preview when the URL is changed (but not yet). 577 this.previewUrl.bind( this.refresh ); 578 579 this.scroll = 0; 580 this.bind( 'scroll', function( distance ) { 581 this.scroll = distance; 582 }); 583 584 // Update the URL when the iframe sends a URL message. 585 this.bind( 'url', this.previewUrl ); 586 }, 587 588 query: function() {}, 589 590 abort: function() { 591 if ( this.loading ) { 592 this.loading.destroy(); 593 delete this.loading; 594 } 595 }, 596 597 refresh: function() { 598 var self = this; 599 600 this.abort(); 601 602 this.loading = new api.PreviewFrame({ 603 url: this.url(), 604 previewUrl: this.previewUrl(), 605 query: this.query() || {}, 606 container: this.container, 607 signature: this.signature 608 }); 609 610 this.loading.done( function() { 611 // 'this' is the loading frame 612 this.bind( 'synced', function() { 613 if ( self.preview ) 614 self.preview.destroy(); 615 self.preview = this; 616 delete self.loading; 617 618 self.targetWindow( this.targetWindow() ); 619 self.channel( this.channel() ); 620 621 self.send( 'active' ); 622 }); 623 624 this.send( 'sync', { 625 scroll: self.scroll, 626 settings: api.get() 627 }); 628 }); 629 630 this.loading.fail( function( reason, location ) { 631 if ( 'redirect' === reason && location ) 632 self.previewUrl( location ); 633 634 if ( 'logged out' === reason ) { 635 if ( self.preview ) { 636 self.preview.destroy(); 637 delete self.preview; 638 } 639 640 self.login().done( self.refresh ); 641 } 642 643 if ( 'cheatin' === reason ) 644 self.cheatin(); 645 }); 646 }, 647 648 login: function() { 649 var previewer = this, 650 deferred, messenger, iframe; 651 652 if ( this._login ) 653 return this._login; 654 655 deferred = $.Deferred(); 656 this._login = deferred.promise(); 657 658 messenger = new api.Messenger({ 659 channel: 'login', 660 url: api.settings.url.login 661 }); 662 663 iframe = $('<iframe src="' + api.settings.url.login + '" />').appendTo( this.container ); 664 665 messenger.targetWindow( iframe[0].contentWindow ); 666 667 messenger.bind( 'login', function() { 668 iframe.remove(); 669 messenger.destroy(); 670 delete previewer._login; 671 deferred.resolve(); 672 }); 673 674 return this._login; 675 }, 676 677 cheatin: function() { 678 $( document.body ).empty().addClass('cheatin').append( '<p>' + api.l10n.cheatin + '</p>' ); 679 } 680 }); 681 682 /* ===================================================================== 683 * Ready. 684 * ===================================================================== */ 685 686 api.controlConstructor = { 687 color: api.ColorControl, 688 upload: api.UploadControl, 689 image: api.ImageControl 690 }; 691 692 $( function() { 693 api.settings = window._wpCustomizeSettings; 694 api.l10n = window._wpCustomizeControlsL10n; 695 696 // Check if we can run the customizer. 697 if ( ! api.settings ) 698 return; 699 700 // Redirect to the fallback preview if any incompatibilities are found. 701 if ( ! $.support.postMessage || ( ! $.support.cors && api.settings.isCrossDomain ) ) 702 return window.location = api.settings.url.fallback; 703 704 var body = $( document.body ), 705 overlay = body.children('.wp-full-overlay'), 706 query, previewer, parent; 707 708 // Prevent the form from saving when enter is pressed. 709 $('#customize-controls').on( 'keydown', function( e ) { 710 if ( $( e.target ).is('textarea') ) 711 return; 712 713 if ( 13 === e.which ) // Enter 714 e.preventDefault(); 715 }); 716 717 // Initialize Previewer 718 previewer = new api.Previewer({ 719 container: '#customize-preview', 720 form: '#customize-controls', 721 previewUrl: api.settings.url.preview, 722 allowedUrls: api.settings.url.allowed, 723 signature: 'WP_CUSTOMIZER_SIGNATURE' 724 }, { 725 726 nonce: api.settings.nonce, 727 728 query: function() { 729 return { 730 wp_customize: 'on', 731 theme: api.settings.theme.stylesheet, 732 customized: JSON.stringify( api.get() ), 733 nonce: this.nonce.preview 734 }; 735 }, 736 737 save: function() { 738 var self = this, 739 query = $.extend( this.query(), { 740 action: 'customize_save', 741 nonce: this.nonce.save 742 }), 743 request = $.post( api.settings.url.ajax, query ); 744 745 api.trigger( 'save', request ); 746 747 body.addClass('saving'); 748 749 request.always( function() { 750 body.removeClass('saving'); 751 }); 752 753 request.done( function( response ) { 754 // Check if the user is logged out. 755 if ( '0' === response ) { 756 self.preview.iframe.hide(); 757 self.login().done( function() { 758 self.save(); 759 self.preview.iframe.show(); 760 }); 761 return; 762 } 763 764 // Check for cheaters. 765 if ( '-1' === response ) { 766 self.cheatin(); 767 return; 768 } 769 770 api.trigger( 'saved' ); 771 }); 772 } 773 }); 774 775 // Refresh the nonces if the preview sends updated nonces over. 776 previewer.bind( 'nonce', function( nonce ) { 777 $.extend( this.nonce, nonce ); 778 }); 779 780 $.each( api.settings.settings, function( id, data ) { 781 api.create( id, id, data.value, { 782 transport: data.transport, 783 previewer: previewer 784 } ); 785 }); 786 787 $.each( api.settings.controls, function( id, data ) { 788 var constructor = api.controlConstructor[ data.type ] || api.Control, 789 control; 790 791 control = api.control.add( id, new constructor( id, { 792 params: data, 793 previewer: previewer 794 } ) ); 795 }); 796 797 // Check if preview url is valid and load the preview frame. 798 if ( previewer.previewUrl() ) 799 previewer.refresh(); 800 else 801 previewer.previewUrl( api.settings.url.home ); 802 803 // Save and activated states 804 (function() { 805 var state = new api.Values(), 806 saved = state.create('saved'), 807 activated = state.create('activated'); 808 809 state.bind( 'change', function() { 810 var save = $('#save'), 811 back = $('.back'); 812 813 if ( ! activated() ) { 814 save.val( api.l10n.activate ).prop( 'disabled', false ); 815 back.text( api.l10n.cancel ); 816 817 } else if ( saved() ) { 818 save.val( api.l10n.saved ).prop( 'disabled', true ); 819 back.text( api.l10n.close ); 820 821 } else { 822 save.val( api.l10n.save ).prop( 'disabled', false ); 823 back.text( api.l10n.cancel ); 824 } 825 }); 826 827 // Set default states. 828 saved( true ); 829 activated( api.settings.theme.active ); 830 831 api.bind( 'change', function() { 832 state('saved').set( false ); 833 }); 834 835 api.bind( 'saved', function() { 836 state('saved').set( true ); 837 state('activated').set( true ); 838 }); 839 840 activated.bind( function( to ) { 841 if ( to ) 842 api.trigger( 'activated' ); 843 }); 844 845 // Expose states to the API. 846 api.state = state; 847 }()); 848 849 // Button bindings. 850 $('#save').click( function( event ) { 851 previewer.save(); 852 event.preventDefault(); 853 }).keydown( function( event ) { 854 if ( 9 === event.which ) // tab 855 return; 856 if ( 13 === event.which ) // enter 857 previewer.save(); 858 event.preventDefault(); 859 }); 860 861 $('.back').keydown( function( event ) { 862 if ( 9 === event.which ) // tab 863 return; 864 if ( 13 === event.which ) // enter 865 parent.send( 'close' ); 866 event.preventDefault(); 867 }); 868 869 $('.upload-dropzone a.upload').keydown( function( event ) { 870 if ( 13 === event.which ) // enter 871 this.click(); 872 }); 873 874 $('.collapse-sidebar').on( 'click keydown', function( event ) { 875 if ( event.type === 'keydown' && 13 !== event.which ) // enter 876 return; 877 878 overlay.toggleClass( 'collapsed' ).toggleClass( 'expanded' ); 879 event.preventDefault(); 880 }); 881 882 // Create a potential postMessage connection with the parent frame. 883 parent = new api.Messenger({ 884 url: api.settings.url.parent, 885 channel: 'loader' 886 }); 887 888 // If we receive a 'back' event, we're inside an iframe. 889 // Send any clicks to the 'Return' link to the parent page. 890 parent.bind( 'back', function() { 891 $('.back').on( 'click.back', function( event ) { 892 event.preventDefault(); 893 parent.send( 'close' ); 894 }); 895 }); 896 897 // Pass events through to the parent. 898 api.bind( 'saved', function() { 899 parent.send( 'saved' ); 900 }); 901 902 // When activated, let the loader handle redirecting the page. 903 // If no loader exists, redirect the page ourselves (if a url exists). 904 api.bind( 'activated', function() { 905 if ( parent.targetWindow() ) 906 parent.send( 'activated', api.settings.url.activated ); 907 else if ( api.settings.url.activated ) 908 window.location = api.settings.url.activated; 909 }); 910 911 // Initialize the connection with the parent frame. 912 parent.send( 'ready' ); 913 914 // Control visibility for default controls 915 $.each({ 916 'background_image': { 917 controls: [ 'background_repeat', 'background_position_x', 'background_attachment' ], 918 callback: function( to ) { return !! to } 919 }, 920 'show_on_front': { 921 controls: [ 'page_on_front', 'page_for_posts' ], 922 callback: function( to ) { return 'page' === to } 923 }, 924 'header_textcolor': { 925 controls: [ 'header_textcolor' ], 926 callback: function( to ) { return 'blank' !== to } 927 } 928 }, function( settingId, o ) { 929 api( settingId, function( setting ) { 930 $.each( o.controls, function( i, controlId ) { 931 api.control( controlId, function( control ) { 932 var visibility = function( to ) { 933 control.container.toggle( o.callback( to ) ); 934 }; 935 936 visibility( setting.get() ); 937 setting.bind( visibility ); 938 }); 939 }); 940 }); 941 }); 942 943 // Juggle the two controls that use header_textcolor 944 api.control( 'display_header_text', function( control ) { 945 var last = ''; 946 947 control.elements[0].unsync( api( 'header_textcolor' ) ); 948 949 control.element = new api.Element( control.container.find('input') ); 950 control.element.set( 'blank' !== control.setting() ); 951 952 control.element.bind( function( to ) { 953 if ( ! to ) 954 last = api( 'header_textcolor' ).get(); 955 956 control.setting.set( to ? last : 'blank' ); 957 }); 958 959 control.setting.bind( function( to ) { 960 control.element.set( 'blank' !== to ); 961 }); 962 }); 963 964 // Handle header image data 965 api.control( 'header_image', function( control ) { 966 control.setting.bind( function( to ) { 967 if ( to === control.params.removed ) 968 control.settings.data.set( false ); 969 }); 970 971 control.library.on( 'click', 'a', function( event ) { 972 control.settings.data.set( $(this).data('customizeHeaderImageData') ); 973 }); 974 975 control.uploader.success = function( attachment ) { 976 var data; 977 978 api.ImageControl.prototype.success.call( control, attachment ); 979 980 data = { 981 attachment_id: attachment.get('id'), 982 url: attachment.get('url'), 983 thumbnail_url: attachment.get('url'), 984 height: attachment.get('height'), 985 width: attachment.get('width') 986 }; 987 988 attachment.element.data( 'customizeHeaderImageData', data ); 989 control.settings.data.set( data ); 990 }; 991 }); 992 993 api.trigger( 'ready' ); 994 995 // Make sure left column gets focus 996 var topFocus = $('.back'); 997 topFocus.focus(); 998 setTimeout(function () { 999 topFocus.focus(); 1000 }, 200); 1001 1002 }); 1003 1004 })( wp, jQuery );
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Jun 19 03:56:30 2013 | Hosted by follow the white rabbit. |