[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-admin/js/ -> customize-controls.dev.js (source)

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


Generated: Wed Aug 22 03:56:18 2012 Hosted by follow the white rabbit.