wp/wp-includes/js/customize-loader.js
changeset 7 cf61fcea0001
parent 5 5e2f62d02dcd
child 9 177826044cd9
equal deleted inserted replaced
6:490d5cc509ed 7:cf61fcea0001
     1 /* global _wpCustomizeLoaderSettings, confirm */
     1 /* global _wpCustomizeLoaderSettings */
       
     2 /**
       
     3  * Expose a public API that allows the customizer to be
       
     4  * loaded on any page.
       
     5  *
       
     6  * @namespace wp
       
     7  */
     2 window.wp = window.wp || {};
     8 window.wp = window.wp || {};
     3 
     9 
     4 (function( exports, $ ){
    10 (function( exports, $ ){
     5 	var api = wp.customize,
    11 	var api = wp.customize,
     6 		Loader;
    12 		Loader;
    16 	 * By default, any element in the body with the load-customize class will open
    22 	 * By default, any element in the body with the load-customize class will open
    17 	 * an iframe overlay with the URL specified.
    23 	 * an iframe overlay with the URL specified.
    18 	 *
    24 	 *
    19 	 *     e.g. <a class="load-customize" href="<?php echo wp_customize_url(); ?>">Open Customizer</a>
    25 	 *     e.g. <a class="load-customize" href="<?php echo wp_customize_url(); ?>">Open Customizer</a>
    20 	 *
    26 	 *
       
    27 	 * @memberOf wp.customize
       
    28 	 *
       
    29 	 * @class
    21 	 * @augments wp.customize.Events
    30 	 * @augments wp.customize.Events
    22 	 */
    31 	 */
    23 	Loader = $.extend( {}, api.Events, {
    32 	Loader = $.extend( {}, api.Events,/** @lends wp.customize.Loader.prototype */{
    24 		/**
    33 		/**
    25 		 * Setup the Loader; triggered on document#ready.
    34 		 * Setup the Loader; triggered on document#ready.
    26 		 */
    35 		 */
    27 		initialize: function() {
    36 		initialize: function() {
    28 			this.body = $( document.body );
    37 			this.body = $( document.body );
   109 			this.originalDocumentTitle = document.title;
   118 			this.originalDocumentTitle = document.title;
   110 
   119 
   111 			this.active = true;
   120 			this.active = true;
   112 			this.body.addClass('customize-loading');
   121 			this.body.addClass('customize-loading');
   113 
   122 
   114 			// Dirty state of Customizer in iframe
   123 			/*
       
   124 			 * Track the dirtiness state (whether the drafted changes have been published)
       
   125 			 * of the Customizer in the iframe. This is used to decide whether to display
       
   126 			 * an AYS alert if the user tries to close the window before saving changes.
       
   127 			 */
   115 			this.saved = new api.Value( true );
   128 			this.saved = new api.Value( true );
   116 
   129 
   117 			this.iframe = $( '<iframe />', { 'src': src, 'title': Loader.settings.l10n.mainIframeTitle } ).appendTo( this.element );
   130 			this.iframe = $( '<iframe />', { 'src': src, 'title': Loader.settings.l10n.mainIframeTitle } ).appendTo( this.element );
   118 			this.iframe.one( 'load', this.loaded );
   131 			this.iframe.one( 'load', this.loaded );
   119 
   132 
   121 			this.messenger = new api.Messenger({
   134 			this.messenger = new api.Messenger({
   122 				url: src,
   135 				url: src,
   123 				channel: 'loader',
   136 				channel: 'loader',
   124 				targetWindow: this.iframe[0].contentWindow
   137 				targetWindow: this.iframe[0].contentWindow
   125 			});
   138 			});
       
   139 
       
   140 			// Expose the changeset UUID on the parent window's URL so that the customized state can survive a refresh.
       
   141 			if ( history.replaceState ) {
       
   142 				this.messenger.bind( 'changeset-uuid', function( changesetUuid ) {
       
   143 					var urlParser = document.createElement( 'a' );
       
   144 					urlParser.href = location.href;
       
   145 					urlParser.search = $.param( _.extend(
       
   146 						api.utils.parseQueryString( urlParser.search.substr( 1 ) ),
       
   147 						{ changeset_uuid: changesetUuid }
       
   148 					) );
       
   149 					history.replaceState( { customize: urlParser.href }, '', urlParser.href );
       
   150 				} );
       
   151 			}
   126 
   152 
   127 			// Wait for the connection from the iframe before sending any postMessage events.
   153 			// Wait for the connection from the iframe before sending any postMessage events.
   128 			this.messenger.bind( 'ready', function() {
   154 			this.messenger.bind( 'ready', function() {
   129 				Loader.messenger.send( 'back' );
   155 				Loader.messenger.send( 'back' );
   130 			});
   156 			});
   140 			});
   166 			});
   141 
   167 
   142 			// Prompt AYS dialog when navigating away
   168 			// Prompt AYS dialog when navigating away
   143 			$( window ).on( 'beforeunload', this.beforeunload );
   169 			$( window ).on( 'beforeunload', this.beforeunload );
   144 
   170 
   145 			this.messenger.bind( 'activated', function( location ) {
       
   146 				if ( location ) {
       
   147 					window.location = location;
       
   148 				}
       
   149 			});
       
   150 
       
   151 			this.messenger.bind( 'saved', function () {
   171 			this.messenger.bind( 'saved', function () {
   152 				Loader.saved( true );
   172 				Loader.saved( true );
   153 			} );
   173 			} );
   154 			this.messenger.bind( 'change', function () {
   174 			this.messenger.bind( 'change', function () {
   155 				Loader.saved( false );
   175 				Loader.saved( false );
   179 
   199 
   180 		/**
   200 		/**
   181 		 * Callback after the Customizer has been opened.
   201 		 * Callback after the Customizer has been opened.
   182 		 */
   202 		 */
   183 		opened: function() {
   203 		opened: function() {
   184 			Loader.body.addClass( 'customize-active full-overlay-active' );
   204 			Loader.body.addClass( 'customize-active full-overlay-active' ).attr( 'aria-busy', 'true' );
   185 		},
   205 		},
   186 
   206 
   187 		/**
   207 		/**
   188 		 * Close the Customizer overlay and return focus to the link that opened it.
   208 		 * Close the Customizer overlay.
   189 		 */
   209 		 */
   190 		close: function() {
   210 		close: function() {
   191 			if ( ! this.active ) {
   211 			var self = this, onConfirmClose;
       
   212 			if ( ! self.active ) {
   192 				return;
   213 				return;
   193 			}
   214 			}
   194 
   215 
   195 			// Display AYS dialog if Customizer is dirty
   216 			onConfirmClose = function( confirmed ) {
   196 			if ( ! this.saved() && ! confirm( Loader.settings.l10n.saveAlert ) ) {
   217 				if ( confirmed ) {
   197 				// Go forward since Customizer is exited by history.back()
   218 					self.active = false;
   198 				history.forward();
   219 					self.trigger( 'close' );
   199 				return;
   220 
   200 			}
   221 					// Restore document title prior to opening the Live Preview
   201 
   222 					if ( self.originalDocumentTitle ) {
   202 			this.active = false;
   223 						document.title = self.originalDocumentTitle;
   203 
   224 					}
   204 			this.trigger( 'close' );
   225 				} else {
   205 
   226 
   206 			// Restore document title prior to opening the Live Preview
   227 					// Go forward since Customizer is exited by history.back()
   207 			if ( this.originalDocumentTitle ) {
   228 					history.forward();
   208 				document.title = this.originalDocumentTitle;
   229 				}
   209 			}
   230 				self.messenger.unbind( 'confirmed-close', onConfirmClose );
   210 
   231 			};
   211 			// Return focus to link that was originally clicked.
   232 			self.messenger.bind( 'confirmed-close', onConfirmClose );
   212 			if ( this.link ) {
   233 
   213 				this.link.focus();
   234 			Loader.messenger.send( 'confirm-close' );
   214 			}
       
   215 		},
   235 		},
   216 
   236 
   217 		/**
   237 		/**
   218 		 * Callback after the Customizer has been closed.
   238 		 * Callback after the Customizer has been closed.
   219 		 */
   239 		 */
   223 			Loader.iframe    = null;
   243 			Loader.iframe    = null;
   224 			Loader.messenger = null;
   244 			Loader.messenger = null;
   225 			Loader.saved     = null;
   245 			Loader.saved     = null;
   226 			Loader.body.removeClass( 'customize-active full-overlay-active' ).removeClass( 'customize-loading' );
   246 			Loader.body.removeClass( 'customize-active full-overlay-active' ).removeClass( 'customize-loading' );
   227 			$( window ).off( 'beforeunload', Loader.beforeunload );
   247 			$( window ).off( 'beforeunload', Loader.beforeunload );
       
   248 			/*
       
   249 			 * Return focus to the link that opened the Customizer overlay after
       
   250 			 * the body element visibility is restored.
       
   251 			 */
       
   252 			if ( Loader.link ) {
       
   253 				Loader.link.focus();
       
   254 			}
   228 		},
   255 		},
   229 
   256 
   230 		/**
   257 		/**
   231 		 * Callback for the `load` event on the Customizer iframe.
   258 		 * Callback for the `load` event on the Customizer iframe.
   232 		 */
   259 		 */
   233 		loaded: function() {
   260 		loaded: function() {
   234 			Loader.body.removeClass('customize-loading');
   261 			Loader.body.removeClass( 'customize-loading' ).attr( 'aria-busy', 'false' );
   235 		},
   262 		},
   236 
   263 
   237 		/**
   264 		/**
   238 		 * Overlay hide/show utility methods.
   265 		 * Overlay hide/show utility methods.
   239 		 */
   266 		 */