[ Index ] |
WordPress Cross Reference |
[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 api.Value.prototype.initialize.call( this, value, options ); 12 13 this.id = id; 14 this.transport = this.transport || 'refresh'; 15 16 this.bind( this.preview ); 17 }, 18 preview: function() { 19 switch ( this.transport ) { 20 case 'refresh': 21 return this.previewer.refresh(); 22 case 'postMessage': 23 return this.previewer.send( 'setting', [ this.id, this() ] ); 24 } 25 } 26 }); 27 28 api.Control = api.Class.extend({ 29 initialize: function( id, options ) { 30 var control = this, 31 nodes, radios, settings; 32 33 this.params = {}; 34 $.extend( this, options || {} ); 35 36 this.id = id; 37 this.selector = '#customize-control-' + id.replace( /\]/g, '' ).replace( /\[/g, '-' ); 38 this.container = $( this.selector ); 39 40 settings = $.map( this.params.settings, function( value ) { 41 return value; 42 }); 43 44 api.apply( api, settings.concat( function() { 45 var key; 46 47 control.settings = {}; 48 for ( key in control.params.settings ) { 49 control.settings[ key ] = api( control.params.settings[ key ] ); 50 } 51 52 control.setting = control.settings['default'] || null; 53 control.ready(); 54 }) ); 55 56 control.elements = []; 57 58 nodes = this.container.find('[data-customize-setting-link]'); 59 radios = {}; 60 61 nodes.each( function() { 62 var node = $(this), 63 name; 64 65 if ( node.is(':radio') ) { 66 name = node.prop('name'); 67 if ( radios[ name ] ) 68 return; 69 70 radios[ name ] = true; 71 node = nodes.filter( '[name="' + name + '"]' ); 72 } 73 74 api( node.data('customizeSettingLink'), function( setting ) { 75 var element = new api.Element( node ); 76 control.elements.push( element ); 77 element.sync( setting ); 78 element.set( setting() ); 79 }); 80 }); 81 }, 82 83 ready: function() {}, 84 85 dropdownInit: function() { 86 var control = this, 87 statuses = this.container.find('.dropdown-status'), 88 params = this.params, 89 toggleFreeze = false, 90 update = function( to ) { 91 if ( typeof to === 'string' && params.statuses && params.statuses[ to ] ) 92 statuses.html( params.statuses[ to ] ).show(); 93 else 94 statuses.hide(); 95 }; 96 97 // Support the .dropdown class to open/close complex elements 98 this.container.on( 'click keydown', '.dropdown', function( event ) { 99 if ( event.type === 'keydown' && 13 !== event.which ) // enter 100 return; 101 102 event.preventDefault(); 103 104 if (!toggleFreeze) 105 control.container.toggleClass('open'); 106 107 if ( control.container.hasClass('open') ) 108 control.container.parent().parent().find('li.library-selected').focus(); 109 110 // Don't want to fire focus and click at same time 111 toggleFreeze = true; 112 setTimeout(function () { 113 toggleFreeze = false; 114 }, 400); 115 }); 116 117 this.setting.bind( update ); 118 update( this.setting() ); 119 } 120 }); 121 122 api.ColorControl = api.Control.extend({ 123 ready: function() { 124 var control = this, 125 picker = this.container.find('.color-picker-hex'); 126 127 picker.val( control.setting() ).wpColorPicker({ 128 change: function() { 129 control.setting.set( picker.wpColorPicker('color') ); 130 }, 131 clear: function() { 132 control.setting.set( false ); 133 } 134 }); 135 } 136 }); 137 138 api.UploadControl = api.Control.extend({ 139 ready: function() { 140 var control = this; 141 142 this.params.removed = this.params.removed || ''; 143 144 this.success = $.proxy( this.success, this ); 145 146 this.uploader = $.extend({ 147 container: this.container, 148 browser: this.container.find('.upload'), 149 dropzone: this.container.find('.upload-dropzone'), 150 success: this.success, 151 plupload: {}, 152 params: {} 153 }, this.uploader || {} ); 154 155 if ( control.params.extensions ) { 156 control.uploader.plupload.filters = [{ 157 title: api.l10n.allowedFiles, 158 extensions: control.params.extensions 159 }]; 160 } 161 162 if ( control.params.context ) 163 control.uploader.params['post_data[context]'] = this.params.context; 164 165 if ( api.settings.theme.stylesheet ) 166 control.uploader.params['post_data[theme]'] = api.settings.theme.stylesheet; 167 168 this.uploader = new wp.Uploader( this.uploader ); 169 170 this.remover = this.container.find('.remove'); 171 this.remover.on( 'click keydown', function( event ) { 172 if ( event.type === 'keydown' && 13 !== event.which ) // enter 173 return; 174 175 control.setting.set( control.params.removed ); 176 event.preventDefault(); 177 }); 178 179 this.removerVisibility = $.proxy( this.removerVisibility, this ); 180 this.setting.bind( this.removerVisibility ); 181 this.removerVisibility( this.setting.get() ); 182 }, 183 success: function( attachment ) { 184 this.setting.set( attachment.get('url') ); 185 }, 186 removerVisibility: function( to ) { 187 this.remover.toggle( to != this.params.removed ); 188 } 189 }); 190 191 api.ImageControl = api.UploadControl.extend({ 192 ready: function() { 193 var control = this, 194 panels; 195 196 this.uploader = { 197 init: function() { 198 var fallback, button; 199 200 if ( this.supports.dragdrop ) 201 return; 202 203 // Maintain references while wrapping the fallback button. 204 fallback = control.container.find( '.upload-fallback' ); 205 button = fallback.children().detach(); 206 207 this.browser.detach().empty().append( button ); 208 fallback.append( this.browser ).show(); 209 } 210 }; 211 212 api.UploadControl.prototype.ready.call( this ); 213 214 this.thumbnail = this.container.find('.preview-thumbnail img'); 215 this.thumbnailSrc = $.proxy( this.thumbnailSrc, this ); 216 this.setting.bind( this.thumbnailSrc ); 217 218 this.library = this.container.find('.library'); 219 220 // Generate tab objects 221 this.tabs = {}; 222 panels = this.library.find('.library-content'); 223 224 this.library.children('ul').children('li').each( function() { 225 var link = $(this), 226 id = link.data('customizeTab'), 227 panel = panels.filter('[data-customize-tab="' + id + '"]'); 228 229 control.tabs[ id ] = { 230 both: link.add( panel ), 231 link: link, 232 panel: panel 233 }; 234 }); 235 236 // Bind tab switch events 237 this.library.children('ul').on( 'click keydown', 'li', function( event ) { 238 if ( event.type === 'keydown' && 13 !== event.which ) // enter 239 return; 240 241 var id = $(this).data('customizeTab'), 242 tab = control.tabs[ id ]; 243 244 event.preventDefault(); 245 246 if ( tab.link.hasClass('library-selected') ) 247 return; 248 249 control.selected.both.removeClass('library-selected'); 250 control.selected = tab; 251 control.selected.both.addClass('library-selected'); 252 }); 253 254 // Bind events to switch image urls. 255 this.library.on( 'click keydown', 'a', function( event ) { 256 if ( event.type === 'keydown' && 13 !== event.which ) // enter 257 return; 258 259 var value = $(this).data('customizeImageValue'); 260 261 if ( value ) { 262 control.setting.set( value ); 263 event.preventDefault(); 264 } 265 }); 266 267 if ( this.tabs.uploaded ) { 268 this.tabs.uploaded.target = this.library.find('.uploaded-target'); 269 if ( ! this.tabs.uploaded.panel.find('.thumbnail').length ) 270 this.tabs.uploaded.both.addClass('hidden'); 271 } 272 273 // Select a tab 274 panels.each( function() { 275 var tab = control.tabs[ $(this).data('customizeTab') ]; 276 277 // Select the first visible tab. 278 if ( ! tab.link.hasClass('hidden') ) { 279 control.selected = tab; 280 tab.both.addClass('library-selected'); 281 return false; 282 } 283 }); 284 285 this.dropdownInit(); 286 }, 287 success: function( attachment ) { 288 api.UploadControl.prototype.success.call( this, attachment ); 289 290 // Add the uploaded image to the uploaded tab. 291 if ( this.tabs.uploaded && this.tabs.uploaded.target.length ) { 292 this.tabs.uploaded.both.removeClass('hidden'); 293 294 // @todo: Do NOT store this on the attachment model. That is bad. 295 attachment.element = $( '<a href="#" class="thumbnail"></a>' ) 296 .data( 'customizeImageValue', attachment.get('url') ) 297 .append( '<img src="' + attachment.get('url')+ '" />' ) 298 .appendTo( this.tabs.uploaded.target ); 299 } 300 }, 301 thumbnailSrc: function( to ) { 302 if ( /^(https?:)?\/\//.test( to ) ) 303 this.thumbnail.prop( 'src', to ).show(); 304 else 305 this.thumbnail.hide(); 306 } 307 }); 308 309 // Change objects contained within the main customize object to Settings. 310 api.defaultConstructor = api.Setting; 311 312 // Create the collection of Control objects. 313 api.control = new api.Values({ defaultConstructor: api.Control }); 314 315 api.PreviewFrame = api.Messenger.extend({ 316 sensitivity: 2000, 317 318 initialize: function( params, options ) { 319 var deferred = $.Deferred(); 320 321 // This is the promise object. 322 deferred.promise( this ); 323 324 this.container = params.container; 325 this.signature = params.signature; 326 327 $.extend( params, { channel: api.PreviewFrame.uuid() }); 328 329 api.Messenger.prototype.initialize.call( this, params, options ); 330 331 this.add( 'previewUrl', params.previewUrl ); 332 333 this.query = $.extend( params.query || {}, { customize_messenger_channel: this.channel() }); 334 335 this.run( deferred ); 336 }, 337 338 run: function( deferred ) { 339 var self = this, 340 loaded = false, 341 ready = false; 342 343 if ( this._ready ) 344 this.unbind( 'ready', this._ready ); 345 346 this._ready = function() { 347 ready = true; 348 349 if ( loaded ) 350 deferred.resolveWith( self ); 351 }; 352 353 this.bind( 'ready', this._ready ); 354 355 this.request = $.ajax( this.previewUrl(), { 356 type: 'POST', 357 data: this.query, 358 xhrFields: { 359 withCredentials: true 360 } 361 } ); 362 363 this.request.fail( function() { 364 deferred.rejectWith( self, [ 'request failure' ] ); 365 }); 366 367 this.request.done( function( response ) { 368 var location = self.request.getResponseHeader('Location'), 369 signature = self.signature, 370 index; 371 372 // Check if the location response header differs from the current URL. 373 // If so, the request was redirected; try loading the requested page. 374 if ( location && location != self.previewUrl() ) { 375 deferred.rejectWith( self, [ 'redirect', location ] ); 376 return; 377 } 378 379 // Check if the user is not logged in. 380 if ( '0' === response ) { 381 self.login( deferred ); 382 return; 383 } 384 385 // Check for cheaters. 386 if ( '-1' === response ) { 387 deferred.rejectWith( self, [ 'cheatin' ] ); 388 return; 389 } 390 391 // Check for a signature in the request. 392 index = response.lastIndexOf( signature ); 393 if ( -1 === index || index < response.lastIndexOf('</html>') ) { 394 deferred.rejectWith( self, [ 'unsigned' ] ); 395 return; 396 } 397 398 // Strip the signature from the request. 399 response = response.slice( 0, index ) + response.slice( index + signature.length ); 400 401 // Create the iframe and inject the html content. 402 self.iframe = $('<iframe />').appendTo( self.container ); 403 404 // Bind load event after the iframe has been added to the page; 405 // otherwise it will fire when injected into the DOM. 406 self.iframe.one( 'load', function() { 407 loaded = true; 408 409 if ( ready ) { 410 deferred.resolveWith( self ); 411 } else { 412 setTimeout( function() { 413 deferred.rejectWith( self, [ 'ready timeout' ] ); 414 }, self.sensitivity ); 415 } 416 }); 417 418 self.targetWindow( self.iframe[0].contentWindow ); 419 420 self.targetWindow().document.open(); 421 self.targetWindow().document.write( response ); 422 self.targetWindow().document.close(); 423 }); 424 }, 425 426 login: function( deferred ) { 427 var self = this, 428 reject; 429 430 reject = function() { 431 deferred.rejectWith( self, [ 'logged out' ] ); 432 }; 433 434 if ( this.triedLogin ) 435 return reject(); 436 437 // Check if we have an admin cookie. 438 $.get( api.settings.url.ajax, { 439 action: 'logged-in' 440 }).fail( reject ).done( function( response ) { 441 var iframe; 442 443 if ( '1' !== response ) 444 reject(); 445 446 iframe = $('<iframe src="' + self.previewUrl() + '" />').hide(); 447 iframe.appendTo( self.container ); 448 iframe.load( function() { 449 self.triedLogin = true; 450 451 iframe.remove(); 452 self.run( deferred ); 453 }); 454 }); 455 }, 456 457 destroy: function() { 458 api.Messenger.prototype.destroy.call( this ); 459 this.request.abort(); 460 461 if ( this.iframe ) 462 this.iframe.remove(); 463 464 delete this.request; 465 delete this.iframe; 466 delete this.targetWindow; 467 } 468 }); 469 470 (function(){ 471 var uuid = 0; 472 api.PreviewFrame.uuid = function() { 473 return 'preview-' + uuid++; 474 }; 475 }()); 476 477 api.Previewer = api.Messenger.extend({ 478 refreshBuffer: 250, 479 480 /** 481 * Requires params: 482 * - container - a selector or jQuery element 483 * - previewUrl - the URL of preview frame 484 */ 485 initialize: function( params, options ) { 486 var self = this, 487 rscheme = /^https?/; 488 489 $.extend( this, options || {} ); 490 491 /* 492 * Wrap this.refresh to prevent it from hammering the servers: 493 * 494 * If refresh is called once and no other refresh requests are 495 * loading, trigger the request immediately. 496 * 497 * If refresh is called while another refresh request is loading, 498 * debounce the refresh requests: 499 * 1. Stop the loading request (as it is instantly outdated). 500 * 2. Trigger the new request once refresh hasn't been called for 501 * self.refreshBuffer milliseconds. 502 */ 503 this.refresh = (function( self ) { 504 var refresh = self.refresh, 505 callback = function() { 506 timeout = null; 507 refresh.call( self ); 508 }, 509 timeout; 510 511 return function() { 512 if ( typeof timeout !== 'number' ) { 513 if ( self.loading ) { 514 self.abort(); 515 } else { 516 return callback(); 517 } 518 } 519 520 clearTimeout( timeout ); 521 timeout = setTimeout( callback, self.refreshBuffer ); 522 }; 523 })( this ); 524 525 this.container = api.ensure( params.container ); 526 this.allowedUrls = params.allowedUrls; 527 this.signature = params.signature; 528 529 params.url = window.location.href; 530 531 api.Messenger.prototype.initialize.call( this, params ); 532 533 this.add( 'scheme', this.origin() ).link( this.origin ).setter( function( to ) { 534 var match = to.match( rscheme ); 535 return match ? match[0] : ''; 536 }); 537 538 // Limit the URL to internal, front-end links. 539 // 540 // If the frontend and the admin are served from the same domain, load the 541 // preview over ssl if the customizer is being loaded over ssl. This avoids 542 // insecure content warnings. This is not attempted if the admin and frontend 543 // are on different domains to avoid the case where the frontend doesn't have 544 // ssl certs. 545 546 this.add( 'previewUrl', params.previewUrl ).setter( function( to ) { 547 var result; 548 549 // Check for URLs that include "/wp-admin/" or end in "/wp-admin". 550 // Strip hashes and query strings before testing. 551 if ( /\/wp-admin(\/|$)/.test( to.replace( /[#?].*$/, '' ) ) ) 552 return null; 553 554 // Attempt to match the URL to the control frame's scheme 555 // and check if it's allowed. If not, try the original URL. 556 $.each([ to.replace( rscheme, self.scheme() ), to ], function( i, url ) { 557 $.each( self.allowedUrls, function( i, allowed ) { 558 var path; 559 560 allowed = allowed.replace( /\/+$/, '' ); 561 path = url.replace( allowed, '' ); 562 563 if ( 0 === url.indexOf( allowed ) && /^([/#?]|$)/.test( path ) ) { 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 previewer, parent, topFocus, 705 body = $( document.body ), 706 overlay = body.children('.wp-full-overlay'); 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 this.click(); 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() { 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 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: Tue Mar 25 01:41:18 2014 | WordPress honlapkészítés: online1.hu |