[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/ -> customize-loader.js (source)

   1  /**
   2   * @output wp-includes/js/customize-loader.js
   3   */
   4  
   5  /* global _wpCustomizeLoaderSettings */
   6  
   7  /**
   8   * Expose a public API that allows the customizer to be
   9   * loaded on any page.
  10   *
  11   * @namespace wp
  12   */
  13  window.wp = window.wp || {};
  14  
  15  /**
  16   * The WordPress Customizer loader API.
  17   *
  18   * @param {Object}       wp The WordPress global object.
  19   * @param {JQueryStatic} $  The jQuery object.
  20   */
  21  (function( wp, $ ){
  22      var api = wp.customize,
  23          Loader;
  24  
  25      $.extend( $.support, {
  26          history: !! ( window.history && history.pushState ),
  27          hashchange: ('onhashchange' in window) && (document.documentMode === undefined || document.documentMode > 7)
  28      });
  29  
  30      /**
  31       * Allows the Customizer to be overlaid on any page.
  32       *
  33       * By default, any element in the body with the load-customize class will open
  34       * an iframe overlay with the URL specified.
  35       *
  36       * e.g. <a class="load-customize" href="<?php echo wp_customize_url(); ?>">Open Customizer</a>
  37       *
  38       * @memberOf wp.customize
  39       *
  40       * @class
  41       * @augments wp.customize.Events
  42       */
  43      Loader = $.extend( {}, api.Events,/** @lends wp.customize.Loader.prototype */{
  44          /**
  45           * Setup the Loader; triggered on document#ready.
  46           */
  47          initialize: function() {
  48              this.body = $( document.body );
  49  
  50              // Ensure the loader is supported.
  51              // Check for settings, postMessage support, and whether we require CORS support.
  52              if ( ! Loader.settings || ! $.support.postMessage || ( ! $.support.cors && Loader.settings.isCrossDomain ) ) {
  53                  return;
  54              }
  55  
  56              this.window  = $( window );
  57              this.element = $( '<div id="customize-container" />' ).appendTo( this.body );
  58  
  59              // Bind events for opening and closing the overlay.
  60              this.bind( 'open', this.overlay.show );
  61              this.bind( 'close', this.overlay.hide );
  62  
  63              // Any element in the body with the `load-customize` class opens
  64              // the Customizer.
  65              $('#wpbody').on( 'click', '.load-customize', function( event ) {
  66                  event.preventDefault();
  67  
  68                  // Store a reference to the link that opened the Customizer.
  69                  Loader.link = $(this);
  70                  // Load the theme.
  71                  Loader.open( Loader.link.attr('href') );
  72              });
  73  
  74              // Add navigation listeners.
  75              if ( $.support.history ) {
  76                  this.window.on( 'popstate', Loader.popstate );
  77              }
  78  
  79              if ( $.support.hashchange ) {
  80                  this.window.on( 'hashchange', Loader.hashchange );
  81                  this.window.triggerHandler( 'hashchange' );
  82              }
  83          },
  84  
  85          /**
  86           * Handle popstate event.
  87           *
  88           * @param {JQuery.Event} e The popstate event.
  89           * @return {void}
  90           */
  91          popstate: function( e ) {
  92              var state = e.originalEvent.state;
  93              if ( state && state.customize ) {
  94                  Loader.open( state.customize );
  95              } else if ( Loader.active ) {
  96                  Loader.close();
  97              }
  98          },
  99  
 100          /**
 101           * Handle hashchange event.
 102           */
 103          hashchange: function() {
 104              var hash = window.location.toString().split('#')[1];
 105  
 106              if ( hash && 0 === hash.indexOf( 'wp_customize=on' ) ) {
 107                  Loader.open( Loader.settings.url + '?' + hash );
 108              }
 109  
 110              if ( ! hash && ! $.support.history ) {
 111                  Loader.close();
 112              }
 113          },
 114  
 115          /**
 116           * Handle beforeunload event.
 117           *
 118           * @return {string|void} Confirmation message if there are unsaved changes.
 119           */
 120          beforeunload: function () {
 121              if ( ! Loader.saved() ) {
 122                  return Loader.settings.l10n.saveAlert;
 123              }
 124          },
 125  
 126          /**
 127           * Open the Customizer overlay for a specific URL.
 128           *
 129           * @param {string} src URL to load in the Customizer.
 130           * @return {string|void} The URL, when navigating to it directly on mobile.
 131           */
 132          open: function( src ) {
 133  
 134              if ( this.active ) {
 135                  return;
 136              }
 137  
 138              // Load the full page on mobile devices.
 139              if ( Loader.settings.browser.mobile ) {
 140                  return window.location = src;
 141              }
 142  
 143              // Store the document title prior to opening the Live Preview.
 144              this.originalDocumentTitle = document.title;
 145  
 146              this.active = true;
 147              this.body.addClass('customize-loading');
 148  
 149              /*
 150               * Track the dirtiness state (whether the drafted changes have been published)
 151               * of the Customizer in the iframe. This is used to decide whether to display
 152               * an AYS alert if the user tries to close the window before saving changes.
 153               */
 154              this.saved = new api.Value( true );
 155  
 156              this.iframe = $( '<iframe />', { 'src': src, 'title': Loader.settings.l10n.mainIframeTitle } ).appendTo( this.element );
 157              this.iframe.one( 'load', this.loaded );
 158  
 159              // Create a postMessage connection with the iframe.
 160              this.messenger = new api.Messenger({
 161                  url: src,
 162                  channel: 'loader',
 163                  targetWindow: this.iframe[0].contentWindow
 164              });
 165  
 166              // Expose the changeset UUID on the parent window's URL so that the customized state can survive a refresh.
 167              if ( history.replaceState ) {
 168                  this.messenger.bind( 'changeset-uuid', function( changesetUuid ) {
 169                      var urlParser = document.createElement( 'a' );
 170                      urlParser.href = location.href;
 171                      urlParser.search = $.param( _.extend(
 172                          api.utils.parseQueryString( urlParser.search.substr( 1 ) ),
 173                          { changeset_uuid: changesetUuid }
 174                      ) );
 175                      history.replaceState( { customize: urlParser.href }, '', urlParser.href );
 176                  } );
 177              }
 178  
 179              // Wait for the connection from the iframe before sending any postMessage events.
 180              this.messenger.bind( 'ready', function() {
 181                  Loader.messenger.send( 'back' );
 182              });
 183  
 184              this.messenger.bind( 'close', function() {
 185                  if ( $.support.history ) {
 186                      history.back();
 187                  } else if ( $.support.hashchange ) {
 188                      window.location.hash = '';
 189                  } else {
 190                      Loader.close();
 191                  }
 192              });
 193  
 194              // Prompt AYS dialog when navigating away.
 195              $( window ).on( 'beforeunload', this.beforeunload );
 196  
 197              this.messenger.bind( 'saved', function () {
 198                  Loader.saved( true );
 199              } );
 200              this.messenger.bind( 'change', function () {
 201                  Loader.saved( false );
 202              } );
 203  
 204              this.messenger.bind( 'title', function( newTitle ){
 205                  window.document.title = newTitle;
 206              });
 207  
 208              this.pushState( src );
 209  
 210              this.trigger( 'open' );
 211          },
 212  
 213          /**
 214           * Push the state of the Customizer onto the history stack.
 215           *
 216           * @param {string} src URL to push.
 217           */
 218          pushState: function ( src ) {
 219              var hash = src.split( '?' )[1];
 220  
 221              // Ensure we don't call pushState if the user hit the forward button.
 222              if ( $.support.history && window.location.href !== src ) {
 223                  history.pushState( { customize: src }, '', src );
 224              } else if ( ! $.support.history && $.support.hashchange && hash ) {
 225                  window.location.hash = 'wp_customize=on&' + hash;
 226              }
 227  
 228              this.trigger( 'open' );
 229          },
 230  
 231          /**
 232           * Callback after the Customizer has been opened.
 233           */
 234          opened: function() {
 235              Loader.body.addClass( 'customize-active full-overlay-active' ).attr( 'aria-busy', 'true' );
 236          },
 237  
 238          /**
 239           * Close the Customizer overlay.
 240           */
 241          close: function() {
 242              var self = this, onConfirmClose;
 243              if ( ! self.active ) {
 244                  return;
 245              }
 246  
 247              onConfirmClose = function( confirmed ) {
 248                  if ( confirmed ) {
 249                      self.active = false;
 250                      self.trigger( 'close' );
 251  
 252                      // Restore document title prior to opening the Live Preview.
 253                      if ( self.originalDocumentTitle ) {
 254                          document.title = self.originalDocumentTitle;
 255                      }
 256                  } else {
 257  
 258                      // Go forward since Customizer is exited by history.back().
 259                      history.forward();
 260                  }
 261                  self.messenger.unbind( 'confirmed-close', onConfirmClose );
 262              };
 263              self.messenger.bind( 'confirmed-close', onConfirmClose );
 264  
 265              Loader.messenger.send( 'confirm-close' );
 266          },
 267  
 268          /**
 269           * Callback after the Customizer has been closed.
 270           */
 271          closed: function() {
 272              Loader.iframe.remove();
 273              Loader.messenger.destroy();
 274              Loader.iframe    = null;
 275              Loader.messenger = null;
 276              Loader.saved     = null;
 277              Loader.body.removeClass( 'customize-active full-overlay-active' ).removeClass( 'customize-loading' );
 278              $( window ).off( 'beforeunload', Loader.beforeunload );
 279              /*
 280               * Return focus to the link that opened the Customizer overlay after
 281               * the body element visibility is restored.
 282               */
 283              if ( Loader.link ) {
 284                  Loader.link.focus();
 285              }
 286          },
 287  
 288          /**
 289           * Callback for the `load` event on the Customizer iframe.
 290           */
 291          loaded: function() {
 292              Loader.body.removeClass( 'customize-loading' ).attr( 'aria-busy', 'false' );
 293          },
 294  
 295          /**
 296           * Overlay hide/show utility methods.
 297           */
 298          overlay: {
 299              /**
 300               * Show the overlay.
 301               */
 302              show: function() {
 303                  this.element.fadeIn( 200, Loader.opened );
 304              },
 305  
 306              /**
 307               * Hide the overlay.
 308               */
 309              hide: function() {
 310                  this.element.fadeOut( 200, Loader.closed );
 311              }
 312          }
 313      });
 314  
 315      // Bootstrap the Loader on document#ready.
 316      $( function() {
 317          Loader.settings = _wpCustomizeLoaderSettings;
 318          Loader.initialize();
 319      });
 320  
 321      // Expose the API publicly on window.wp.customize.Loader.
 322      api.Loader = Loader;
 323  })( wp, jQuery );


Generated : Sat Sep 12 08:20:32 2026 Cross-referenced by PHPXref