wp/wp-includes/js/autosave.js
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
     1 /**
     1 /**
     2  * @output wp-includes/js/autosave.js
     2  * @output wp-includes/js/autosave.js
     3  */
     3  */
     4 
     4 
     5 /* global tinymce, wpCookies, autosaveL10n, switchEditors */
     5 /* global tinymce, wpCookies, autosaveL10n, switchEditors */
     6 // Back-compat
     6 // Back-compat.
     7 window.autosave = function() {
     7 window.autosave = function() {
     8 	return true;
     8 	return true;
     9 };
     9 };
    10 
    10 
    11 /**
    11 /**
    21 	/**
    21 	/**
    22 	 * Auto saves the post.
    22 	 * Auto saves the post.
    23 	 *
    23 	 *
    24 	 * @since 3.9.0
    24 	 * @since 3.9.0
    25 	 *
    25 	 *
    26 	 * @returns {Object}
    26 	 * @return {Object}
    27 	 * 	{{
    27 	 * 	{{
    28 	 * 		getPostData: getPostData,
    28 	 * 		getPostData: getPostData,
    29 	 * 		getCompareString: getCompareString,
    29 	 * 		getCompareString: getCompareString,
    30 	 * 		disableButtons: disableButtons,
    30 	 * 		disableButtons: disableButtons,
    31 	 * 		enableButtons: enableButtons,
    31 	 * 		enableButtons: enableButtons,
    44 		 *
    44 		 *
    45 		 * @since 3.9.0
    45 		 * @since 3.9.0
    46 		 *
    46 		 *
    47 		 * @param {string} type The type of autosave either local or remote.
    47 		 * @param {string} type The type of autosave either local or remote.
    48 		 *
    48 		 *
    49 		 * @returns {Object} Object containing the post data.
    49 		 * @return {Object} Object containing the post data.
    50 		 */
    50 		 */
    51 		function getPostData( type ) {
    51 		function getPostData( type ) {
    52 			var post_name, parent_id, data,
    52 			var post_name, parent_id, data,
    53 				time = ( new Date() ).getTime(),
    53 				time = ( new Date() ).getTime(),
    54 				cats = [],
    54 				cats = [],
   108 		 *
   108 		 *
   109 		 * @since 3.9.0
   109 		 * @since 3.9.0
   110 		 *
   110 		 *
   111 		 * @param {Object} postData The object containing the post data.
   111 		 * @param {Object} postData The object containing the post data.
   112 		 *
   112 		 *
   113 		 * @returns {string} A concatenated string with title, content and excerpt.
   113 		 * @return {string} A concatenated string with title, content and excerpt.
   114 		 */
   114 		 */
   115 		function getCompareString( postData ) {
   115 		function getCompareString( postData ) {
   116 			if ( typeof postData === 'object' ) {
   116 			if ( typeof postData === 'object' ) {
   117 				return ( postData.post_title || '' ) + '::' + ( postData.content || '' ) + '::' + ( postData.excerpt || '' );
   117 				return ( postData.post_title || '' ) + '::' + ( postData.content || '' ) + '::' + ( postData.excerpt || '' );
   118 			}
   118 			}
   123 		/**
   123 		/**
   124 		 * Disables save buttons.
   124 		 * Disables save buttons.
   125 		 *
   125 		 *
   126 		 * @since 3.9.0
   126 		 * @since 3.9.0
   127 		 *
   127 		 *
   128 		 * @returns {void}
   128 		 * @return {void}
   129 		 */
   129 		 */
   130 		function disableButtons() {
   130 		function disableButtons() {
   131 			$document.trigger('autosave-disable-buttons');
   131 			$document.trigger('autosave-disable-buttons');
   132 
   132 
   133 			// Re-enable 5 sec later. Just gives autosave a head start to avoid collisions.
   133 			// Re-enable 5 sec later. Just gives autosave a head start to avoid collisions.
   137 		/**
   137 		/**
   138 		 * Enables save buttons.
   138 		 * Enables save buttons.
   139 		 *
   139 		 *
   140 		 * @since 3.9.0
   140 		 * @since 3.9.0
   141 		 *
   141 		 *
   142 		 * @returns {void}
   142 		 * @return {void}
   143 		 */
   143 		 */
   144 		function enableButtons() {
   144 		function enableButtons() {
   145 			$document.trigger( 'autosave-enable-buttons' );
   145 			$document.trigger( 'autosave-enable-buttons' );
   146 		}
   146 		}
   147 
   147 
   148 		/**
   148 		/**
   149 		 * Gets the content editor.
   149 		 * Gets the content editor.
   150 		 *
   150 		 *
   151 		 * @since 4.6.0
   151 		 * @since 4.6.0
   152 		 *
   152 		 *
   153 		 * @returns {boolean|*} Returns either false if the editor is undefined,
   153 		 * @return {boolean|*} Returns either false if the editor is undefined,
   154 		 * 						or the instance of the content editor.
   154 		 *                     or the instance of the content editor.
   155 		 */
   155 		 */
   156 		function getEditor() {
   156 		function getEditor() {
   157 			return typeof tinymce !== 'undefined' && tinymce.get('content');
   157 			return typeof tinymce !== 'undefined' && tinymce.get('content');
   158 		}
   158 		}
   159 
   159 
   160 		/**
   160 		/**
   161 		 * Autosave in localStorage.
   161 		 * Autosave in localStorage.
   162 		 *
   162 		 *
   163 		 * @since 3.9.0
   163 		 * @since 3.9.0
   164 		 *
   164 		 *
   165 		 * @returns {
   165 		 * @return {
   166 		 * {
   166 		 * {
   167 		 * 	hasStorage: *,
   167 		 * 	hasStorage: *,
   168 		 * 	getSavedPostData: getSavedPostData,
   168 		 * 	getSavedPostData: getSavedPostData,
   169 		 * 	save: save,
   169 		 * 	save: save,
   170 		 * 	suspend: suspend,
   170 		 * 	suspend: suspend,
   181 			/**
   181 			/**
   182 			 * Checks if the browser supports sessionStorage and it's not disabled.
   182 			 * Checks if the browser supports sessionStorage and it's not disabled.
   183 			 *
   183 			 *
   184 			 * @since 3.9.0
   184 			 * @since 3.9.0
   185 			 *
   185 			 *
   186 			 * @returns {boolean} True if the sessionStorage is supported and enabled.
   186 			 * @return {boolean} True if the sessionStorage is supported and enabled.
   187 			 */
   187 			 */
   188 			function checkStorage() {
   188 			function checkStorage() {
   189 				var test = Math.random().toString(),
   189 				var test = Math.random().toString(),
   190 					result = false;
   190 					result = false;
   191 
   191 
   202 			/**
   202 			/**
   203 			 * Initializes the local storage.
   203 			 * Initializes the local storage.
   204 			 *
   204 			 *
   205 			 * @since 3.9.0
   205 			 * @since 3.9.0
   206 			 *
   206 			 *
   207 			 * @returns {boolean|Object} False if no sessionStorage in the browser or an Object
   207 			 * @return {boolean|Object} False if no sessionStorage in the browser or an Object
   208 			 *                           containing all postData for this blog.
   208 			 *                          containing all postData for this blog.
   209 			 */
   209 			 */
   210 			function getStorage() {
   210 			function getStorage() {
   211 				var stored_obj = false;
   211 				var stored_obj = false;
   212 				// Separate local storage containers for each blog_id
   212 				// Separate local storage containers for each blog_id.
   213 				if ( hasStorage && blog_id ) {
   213 				if ( hasStorage && blog_id ) {
   214 					stored_obj = sessionStorage.getItem( 'wp-autosave-' + blog_id );
   214 					stored_obj = sessionStorage.getItem( 'wp-autosave-' + blog_id );
   215 
   215 
   216 					if ( stored_obj ) {
   216 					if ( stored_obj ) {
   217 						stored_obj = JSON.parse( stored_obj );
   217 						stored_obj = JSON.parse( stored_obj );
   227 			 * Sets the storage for this blog. Confirms that the data was saved
   227 			 * Sets the storage for this blog. Confirms that the data was saved
   228 			 * successfully.
   228 			 * successfully.
   229 			 *
   229 			 *
   230 			 * @since 3.9.0
   230 			 * @since 3.9.0
   231 			 *
   231 			 *
   232 			 * @returns {boolean} True if the data was saved successfully, false if it wasn't saved.
   232 			 * @return {boolean} True if the data was saved successfully, false if it wasn't saved.
   233 			 */
   233 			 */
   234 			function setStorage( stored_obj ) {
   234 			function setStorage( stored_obj ) {
   235 				var key;
   235 				var key;
   236 
   236 
   237 				if ( hasStorage && blog_id ) {
   237 				if ( hasStorage && blog_id ) {
   246 			/**
   246 			/**
   247 			 * Gets the saved post data for the current post.
   247 			 * Gets the saved post data for the current post.
   248 			 *
   248 			 *
   249 			 * @since 3.9.0
   249 			 * @since 3.9.0
   250 			 *
   250 			 *
   251 			 * @returns {boolean|Object} False if no storage or no data or the postData as an Object.
   251 			 * @return {boolean|Object} False if no storage or no data or the postData as an Object.
   252 			 */
   252 			 */
   253 			function getSavedPostData() {
   253 			function getSavedPostData() {
   254 				var stored = getStorage();
   254 				var stored = getStorage();
   255 
   255 
   256 				if ( ! stored || ! post_id ) {
   256 				if ( ! stored || ! post_id ) {
   267 			 *
   267 			 *
   268 			 * @since 3.9.0
   268 			 * @since 3.9.0
   269 			 *
   269 			 *
   270 			 * @param {Object|boolean|null} stored_data The post data to store or null/false/empty to delete the key.
   270 			 * @param {Object|boolean|null} stored_data The post data to store or null/false/empty to delete the key.
   271 			 *
   271 			 *
   272 			 * @returns {boolean} True if data is stored, false if data was removed.
   272 			 * @return {boolean} True if data is stored, false if data was removed.
   273 			 */
   273 			 */
   274 			function setData( stored_data ) {
   274 			function setData( stored_data ) {
   275 				var stored = getStorage();
   275 				var stored = getStorage();
   276 
   276 
   277 				if ( ! stored || ! post_id ) {
   277 				if ( ! stored || ! post_id ) {
   292 			/**
   292 			/**
   293 			 * Sets isSuspended to true.
   293 			 * Sets isSuspended to true.
   294 			 *
   294 			 *
   295 			 * @since 3.9.0
   295 			 * @since 3.9.0
   296 			 *
   296 			 *
   297 			 * @returns {void}
   297 			 * @return {void}
   298 			 */
   298 			 */
   299 			function suspend() {
   299 			function suspend() {
   300 				isSuspended = true;
   300 				isSuspended = true;
   301 			}
   301 			}
   302 
   302 
   303 			/**
   303 			/**
   304 			 * Sets isSuspended to false.
   304 			 * Sets isSuspended to false.
   305 			 *
   305 			 *
   306 			 * @since 3.9.0
   306 			 * @since 3.9.0
   307 			 *
   307 			 *
   308 			 * @returns {void}
   308 			 * @return {void}
   309 			 */
   309 			 */
   310 			function resume() {
   310 			function resume() {
   311 				isSuspended = false;
   311 				isSuspended = false;
   312 			}
   312 			}
   313 
   313 
   314 			/**
   314 			/**
   315 			 * Saves post data for the current post.
   315 			 * Saves post data for the current post.
   316 			 *
   316 			 *
   317 			 * Runs on a 15 sec. interval, saves when there are differences in the post title or content.
   317 			 * Runs on a 15 seconds interval, saves when there are differences in the post title or content.
   318 			 * When the optional data is provided, updates the last saved post data.
   318 			 * When the optional data is provided, updates the last saved post data.
   319 			 *
   319 			 *
   320 			 * @since 3.9.0
   320 			 * @since 3.9.0
   321 			 *
   321 			 *
   322 			 * @param {Object} data The post data for saving, minimum 'post_title' and 'content'.
   322 			 * @param {Object} data The post data for saving, minimum 'post_title' and 'content'.
   323 			 *
   323 			 *
   324 			 * @returns {boolean} Returns true when data has been saved, otherwise it returns false.
   324 			 * @return {boolean} Returns true when data has been saved, otherwise it returns false.
   325 			 */
   325 			 */
   326 			function save( data ) {
   326 			function save( data ) {
   327 				var postData, compareString,
   327 				var postData, compareString,
   328 					result = false;
   328 					result = false;
   329 
   329 
   368 			 *
   368 			 *
   369 			 * Runs on DOM ready.
   369 			 * Runs on DOM ready.
   370 			 *
   370 			 *
   371 			 * @since 3.9.0
   371 			 * @since 3.9.0
   372 			 *
   372 			 *
   373 			 * @returns {void}
   373 			 * @return {void}
   374 			 */
   374 			 */
   375 			function run() {
   375 			function run() {
   376 				post_id = $('#post_ID').val() || 0;
   376 				post_id = $('#post_ID').val() || 0;
   377 
   377 
   378 				// Check if the local post data is different than the loaded post data.
   378 				// Check if the local post data is different than the loaded post data.
   379 				if ( $( '#wp-content-wrap' ).hasClass( 'tmce-active' ) ) {
   379 				if ( $( '#wp-content-wrap' ).hasClass( 'tmce-active' ) ) {
   380 
   380 
   381 					// If TinyMCE loads first, check the post 1.5 sec. after it is ready.
   381 					/*
   382 					// By this time the content has been loaded in the editor and 'saved' to the textarea.
   382 					 * If TinyMCE loads first, check the post 1.5 seconds after it is ready.
   383 					// This prevents false positives.
   383 					 * By this time the content has been loaded in the editor and 'saved' to the textarea.
       
   384 					 * This prevents false positives.
       
   385 					 */
   384 					$document.on( 'tinymce-editor-init.autosave', function() {
   386 					$document.on( 'tinymce-editor-init.autosave', function() {
   385 						window.setTimeout( function() {
   387 						window.setTimeout( function() {
   386 							checkPost();
   388 							checkPost();
   387 						}, 1500 );
   389 						}, 1500 );
   388 					});
   390 					});
   389 				} else {
   391 				} else {
   390 					checkPost();
   392 					checkPost();
   391 				}
   393 				}
   392 
   394 
   393 				// Save every 15 sec.
   395 				// Save every 15 seconds.
   394 				intervalTimer = window.setInterval( save, 15000 );
   396 				intervalTimer = window.setInterval( save, 15000 );
   395 
   397 
   396 				$( 'form#post' ).on( 'submit.autosave-local', function() {
   398 				$( 'form#post' ).on( 'submit.autosave-local', function() {
   397 					var editor = getEditor(),
   399 					var editor = getEditor(),
   398 						post_id = $('#post_ID').val() || 0;
   400 						post_id = $('#post_ID').val() || 0;
   425 			 *
   427 			 *
   426 			 * @since 3.9.0
   428 			 * @since 3.9.0
   427 			 *
   429 			 *
   428 			 * @param {string} str1 The first string.
   430 			 * @param {string} str1 The first string.
   429 			 * @param {string} str2 The second string.
   431 			 * @param {string} str2 The second string.
   430 			 * @returns {boolean} True if the strings are the same.
   432 			 * @return {boolean} True if the strings are the same.
   431 			 */
   433 			 */
   432 			function compare( str1, str2 ) {
   434 			function compare( str1, str2 ) {
   433 				function removeSpaces( string ) {
   435 				function removeSpaces( string ) {
   434 					return string.toString().replace(/[\x20\t\r\n\f]+/g, '');
   436 					return string.toString().replace(/[\x20\t\r\n\f]+/g, '');
   435 				}
   437 				}
   443 			 *
   445 			 *
   444 			 * Shows a standard message letting the user restore the post data if different.
   446 			 * Shows a standard message letting the user restore the post data if different.
   445 			 *
   447 			 *
   446 			 * @since 3.9.0
   448 			 * @since 3.9.0
   447 			 *
   449 			 *
   448 			 * @returns {void}
   450 			 * @return {void}
   449 			 */
   451 			 */
   450 			function checkPost() {
   452 			function checkPost() {
   451 				var content, post_title, excerpt, $notice,
   453 				var content, post_title, excerpt, $notice,
   452 					postData = getSavedPostData(),
   454 					postData = getSavedPostData(),
   453 					cookie = wpCookies.get( 'wp-saving-post' ),
   455 					cookie = wpCookies.get( 'wp-saving-post' ),
   454 					$newerAutosaveNotice = $( '#has-newer-autosave' ).parent( '.notice' ),
   456 					$newerAutosaveNotice = $( '#has-newer-autosave' ).parent( '.notice' ),
   455 					$headerEnd = $( '.wp-header-end' );
   457 					$headerEnd = $( '.wp-header-end' );
   456 
   458 
   457 				if ( cookie === post_id + '-saved' ) {
   459 				if ( cookie === post_id + '-saved' ) {
   458 					wpCookies.remove( 'wp-saving-post' );
   460 					wpCookies.remove( 'wp-saving-post' );
   459 					// The post was saved properly, remove old data and bail
   461 					// The post was saved properly, remove old data and bail.
   460 					setData( false );
   462 					setData( false );
   461 					return;
   463 					return;
   462 				}
   464 				}
   463 
   465 
   464 				if ( ! postData ) {
   466 				if ( ! postData ) {
   511 			 *
   513 			 *
   512 			 * @since 3.9.0
   514 			 * @since 3.9.0
   513 			 *
   515 			 *
   514 			 * @param {Object} postData The object containing all post data.
   516 			 * @param {Object} postData The object containing all post data.
   515 			 *
   517 			 *
   516 			 * @returns {boolean} True if the post is restored.
   518 			 * @return {boolean} True if the post is restored.
   517 			 */
   519 			 */
   518 			function restorePost( postData ) {
   520 			function restorePost( postData ) {
   519 				var editor;
   521 				var editor;
   520 
   522 
   521 				if ( postData ) {
   523 				if ( postData ) {
   522 					// Set the last saved data
   524 					// Set the last saved data.
   523 					lastCompareString = getCompareString( postData );
   525 					lastCompareString = getCompareString( postData );
   524 
   526 
   525 					if ( $( '#title' ).val() !== postData.post_title ) {
   527 					if ( $( '#title' ).val() !== postData.post_title ) {
   526 						$( '#title' ).focus().val( postData.post_title || '' );
   528 						$( '#title' ).focus().val( postData.post_title || '' );
   527 					}
   529 					}
   532 					if ( editor && ! editor.isHidden() && typeof switchEditors !== 'undefined' ) {
   534 					if ( editor && ! editor.isHidden() && typeof switchEditors !== 'undefined' ) {
   533 						if ( editor.settings.wpautop && postData.content ) {
   535 						if ( editor.settings.wpautop && postData.content ) {
   534 							postData.content = switchEditors.wpautop( postData.content );
   536 							postData.content = switchEditors.wpautop( postData.content );
   535 						}
   537 						}
   536 
   538 
   537 						// Make sure there's an undo level in the editor
   539 						// Make sure there's an undo level in the editor.
   538 						editor.undoManager.transact( function() {
   540 						editor.undoManager.transact( function() {
   539 							editor.setContent( postData.content || '' );
   541 							editor.setContent( postData.content || '' );
   540 							editor.nodeChanged();
   542 							editor.nodeChanged();
   541 						});
   543 						});
   542 					} else {
   544 					} else {
   543 
   545 
   544 						// Make sure the Text editor is selected
   546 						// Make sure the Text editor is selected.
   545 						$( '#content-html' ).click();
   547 						$( '#content-html' ).click();
   546 						$( '#content' ).focus();
   548 						$( '#content' ).focus();
   547 
   549 
   548 						// Using document.execCommand() will let the user undo.
   550 						// Using document.execCommand() will let the user undo.
   549 						document.execCommand( 'selectAll' );
   551 						document.execCommand( 'selectAll' );
   556 				return false;
   558 				return false;
   557 			}
   559 			}
   558 
   560 
   559 			blog_id = typeof window.autosaveL10n !== 'undefined' && window.autosaveL10n.blog_id;
   561 			blog_id = typeof window.autosaveL10n !== 'undefined' && window.autosaveL10n.blog_id;
   560 
   562 
   561 			// Check if the browser supports sessionStorage and it's not disabled,
   563 			/*
   562 			// then initialize and run checkPost().
   564 			 * Check if the browser supports sessionStorage and it's not disabled,
   563 			// Don't run if the post type supports neither 'editor' (textarea#content) nor 'excerpt'.
   565 			 * then initialize and run checkPost().
       
   566 			 * Don't run if the post type supports neither 'editor' (textarea#content) nor 'excerpt'.
       
   567 			 */
   564 			if ( checkStorage() && blog_id && ( $('#content').length || $('#excerpt').length ) ) {
   568 			if ( checkStorage() && blog_id && ( $('#content').length || $('#excerpt').length ) ) {
   565 				$document.ready( run );
   569 				$document.ready( run );
   566 			}
   570 			}
   567 
   571 
   568 			return {
   572 			return {
   577 		/**
   581 		/**
   578 		 * Auto saves the post on the server.
   582 		 * Auto saves the post on the server.
   579 		 *
   583 		 *
   580 		 * @since 3.9.0
   584 		 * @since 3.9.0
   581 		 *
   585 		 *
   582 		 * @returns {Object} {
   586 		 * @return {Object} {
   583 		 * 	{
   587 		 * 	{
   584 		 * 		tempBlockSave: tempBlockSave,
   588 		 * 		tempBlockSave: tempBlockSave,
   585 		 * 		triggerSave: triggerSave,
   589 		 * 		triggerSave: triggerSave,
   586 		 * 		postChanged: postChanged,
   590 		 * 		postChanged: postChanged,
   587 		 * 		suspend: suspend,
   591 		 * 		suspend: suspend,
   598 			/**
   602 			/**
   599 			 * Blocks saving for the next 10 seconds.
   603 			 * Blocks saving for the next 10 seconds.
   600 			 *
   604 			 *
   601 			 * @since 3.9.0
   605 			 * @since 3.9.0
   602 			 *
   606 			 *
   603 			 * @returns {void}
   607 			 * @return {void}
   604 			 */
   608 			 */
   605 			function tempBlockSave() {
   609 			function tempBlockSave() {
   606 				_blockSave = true;
   610 				_blockSave = true;
   607 				window.clearTimeout( _blockSaveTimer );
   611 				window.clearTimeout( _blockSaveTimer );
   608 
   612 
   614 			/**
   618 			/**
   615 			 * Sets isSuspended to true.
   619 			 * Sets isSuspended to true.
   616 			 *
   620 			 *
   617 			 * @since 3.9.0
   621 			 * @since 3.9.0
   618 			 *
   622 			 *
   619 			 * @returns {void}
   623 			 * @return {void}
   620 			 */
   624 			 */
   621 			function suspend() {
   625 			function suspend() {
   622 				isSuspended = true;
   626 				isSuspended = true;
   623 			}
   627 			}
   624 
   628 
   625 			/**
   629 			/**
   626 			 * Sets isSuspended to false.
   630 			 * Sets isSuspended to false.
   627 			 *
   631 			 *
   628 			 * @since 3.9.0
   632 			 * @since 3.9.0
   629 			 *
   633 			 *
   630 			 * @returns {void}
   634 			 * @return {void}
   631 			 */
   635 			 */
   632 			function resume() {
   636 			function resume() {
   633 				isSuspended = false;
   637 				isSuspended = false;
   634 			}
   638 			}
   635 
   639 
   638 			 *
   642 			 *
   639 			 * @since 3.9.0
   643 			 * @since 3.9.0
   640 			 *
   644 			 *
   641 			 * @param {Object} data The post data.
   645 			 * @param {Object} data The post data.
   642 			 *
   646 			 *
   643 			 * @returns {void}
   647 			 * @return {void}
   644 			 */
   648 			 */
   645 			function response( data ) {
   649 			function response( data ) {
   646 				_schedule();
   650 				_schedule();
   647 				_blockSave = false;
   651 				_blockSave = false;
   648 				lastCompareString = previousCompareString;
   652 				lastCompareString = previousCompareString;
   650 
   654 
   651 				$document.trigger( 'after-autosave', [data] );
   655 				$document.trigger( 'after-autosave', [data] );
   652 				enableButtons();
   656 				enableButtons();
   653 
   657 
   654 				if ( data.success ) {
   658 				if ( data.success ) {
   655 					// No longer an auto-draft
   659 					// No longer an auto-draft.
   656 					$( '#auto_draft' ).val('');
   660 					$( '#auto_draft' ).val('');
   657 				}
   661 				}
   658 			}
   662 			}
   659 
   663 
   660 			/**
   664 			/**
   662 			 *
   666 			 *
   663 			 * Resets the timing and tells heartbeat to connect now.
   667 			 * Resets the timing and tells heartbeat to connect now.
   664 			 *
   668 			 *
   665 			 * @since 3.9.0
   669 			 * @since 3.9.0
   666 			 *
   670 			 *
   667 			 * @returns {void}
   671 			 * @return {void}
   668 			 */
   672 			 */
   669 			function triggerSave() {
   673 			function triggerSave() {
   670 				nextRun = 0;
   674 				nextRun = 0;
   671 				wp.heartbeat.connectNow();
   675 				wp.heartbeat.connectNow();
   672 			}
   676 			}
   691 			 * If the post hasn't changed or it cannot be updated,
   695 			 * If the post hasn't changed or it cannot be updated,
   692 			 * because the autosave is blocked or suspended, the function returns false.
   696 			 * because the autosave is blocked or suspended, the function returns false.
   693 			 *
   697 			 *
   694 			 * @since 3.9.0
   698 			 * @since 3.9.0
   695 			 *
   699 			 *
   696 			 * @returns {Object} Returns the post data.
   700 			 * @return {Object} Returns the post data.
   697 			 */
   701 			 */
   698 			function save() {
   702 			function save() {
   699 				var postData, compareString;
   703 				var postData, compareString;
   700 
   704 
   701 				// window.autosave() used for back-compat
   705 				// window.autosave() used for back-compat.
   702 				if ( isSuspended || _blockSave || ! window.autosave() ) {
   706 				if ( isSuspended || _blockSave || ! window.autosave() ) {
   703 					return false;
   707 					return false;
   704 				}
   708 				}
   705 
   709 
   706 				if ( ( new Date() ).getTime() < nextRun ) {
   710 				if ( ( new Date() ).getTime() < nextRun ) {
   708 				}
   712 				}
   709 
   713 
   710 				postData = getPostData();
   714 				postData = getPostData();
   711 				compareString = getCompareString( postData );
   715 				compareString = getCompareString( postData );
   712 
   716 
   713 				// First check
   717 				// First check.
   714 				if ( typeof lastCompareString === 'undefined' ) {
   718 				if ( typeof lastCompareString === 'undefined' ) {
   715 					lastCompareString = initialCompareString;
   719 					lastCompareString = initialCompareString;
   716 				}
   720 				}
   717 
   721 
   718 				// No change
   722 				// No change.
   719 				if ( compareString === lastCompareString ) {
   723 				if ( compareString === lastCompareString ) {
   720 					return false;
   724 					return false;
   721 				}
   725 				}
   722 
   726 
   723 				previousCompareString = compareString;
   727 				previousCompareString = compareString;
   737 			 *
   741 			 *
   738 			 * @private
   742 			 * @private
   739 			 *
   743 			 *
   740 			 * @since 3.9.0
   744 			 * @since 3.9.0
   741 			 *
   745 			 *
   742 			 * @returns {void}
   746 			 * @return {void}
   743 			 */
   747 			 */
   744 			function _schedule() {
   748 			function _schedule() {
   745 				nextRun = ( new Date() ).getTime() + ( autosaveL10n.autosaveInterval * 1000 ) || 60000;
   749 				nextRun = ( new Date() ).getTime() + ( autosaveL10n.autosaveInterval * 1000 ) || 60000;
   746 			}
   750 			}
   747 
   751 
   748 			/**
   752 			/**
   749 			 * Sets the autosaveData on the autosave heartbeat.
   753 			 * Sets the autosaveData on the autosave heartbeat.
   750 			 *
   754 			 *
   751 			 * @since 3.9.0
   755 			 * @since 3.9.0
   752 			 *
   756 			 *
   753 			 * @returns {void}
   757 			 * @return {void}
   754 			 */
   758 			 */
   755 			$document.on( 'heartbeat-send.autosave', function( event, data ) {
   759 			$document.on( 'heartbeat-send.autosave', function( event, data ) {
   756 				var autosaveData = save();
   760 				var autosaveData = save();
   757 
   761 
   758 				if ( autosaveData ) {
   762 				if ( autosaveData ) {
   763 				 * Triggers the autosave of the post with the autosave data on the autosave
   767 				 * Triggers the autosave of the post with the autosave data on the autosave
   764 				 * heartbeat.
   768 				 * heartbeat.
   765 				 *
   769 				 *
   766 				 * @since 3.9.0
   770 				 * @since 3.9.0
   767 				 *
   771 				 *
   768 				 * @returns {void}
   772 				 * @return {void}
   769 				 */
   773 				 */
   770 			}).on( 'heartbeat-tick.autosave', function( event, data ) {
   774 			}).on( 'heartbeat-tick.autosave', function( event, data ) {
   771 				if ( data.wp_autosave ) {
   775 				if ( data.wp_autosave ) {
   772 					response( data.wp_autosave );
   776 					response( data.wp_autosave );
   773 				}
   777 				}
   774 				/**
   778 				/**
   775 				 * Disables buttons and throws a notice when the connection is lost.
   779 				 * Disables buttons and throws a notice when the connection is lost.
   776 				 *
   780 				 *
   777 				 * @since 3.9.0
   781 				 * @since 3.9.0
   778 				 *
   782 				 *
   779 				 * @returns {void}
   783 				 * @return {void}
   780 				 */
   784 				 */
   781 			}).on( 'heartbeat-connection-lost.autosave', function( event, error, status ) {
   785 			}).on( 'heartbeat-connection-lost.autosave', function( event, error, status ) {
   782 
   786 
   783 				// When connection is lost, keep user from submitting changes.
   787 				// When connection is lost, keep user from submitting changes.
   784 				if ( 'timeout' === error || 603 === status ) {
   788 				if ( 'timeout' === error || 603 === status ) {
   795 				/**
   799 				/**
   796 				 * Enables buttons when the connection is restored.
   800 				 * Enables buttons when the connection is restored.
   797 				 *
   801 				 *
   798 				 * @since 3.9.0
   802 				 * @since 3.9.0
   799 				 *
   803 				 *
   800 				 * @returns {void}
   804 				 * @return {void}
   801 				 */
   805 				 */
   802 			}).on( 'heartbeat-connection-restored.autosave', function() {
   806 			}).on( 'heartbeat-connection-restored.autosave', function() {
   803 				$('#lost-connection-notice').hide();
   807 				$('#lost-connection-notice').hide();
   804 				enableButtons();
   808 				enableButtons();
   805 			}).ready( function() {
   809 			}).ready( function() {
   823 		 * This avoids any insignificant differences between the initial textarea content and the content
   827 		 * This avoids any insignificant differences between the initial textarea content and the content
   824 		 * extracted from the editor.
   828 		 * extracted from the editor.
   825 		 *
   829 		 *
   826 		 * @since 3.9.0
   830 		 * @since 3.9.0
   827 		 *
   831 		 *
   828 		 * @returns {void}
   832 		 * @return {void}
   829 		 */
   833 		 */
   830 		$document.on( 'tinymce-editor-init.autosave', function( event, editor ) {
   834 		$document.on( 'tinymce-editor-init.autosave', function( event, editor ) {
   831 			if ( editor.id === 'content' ) {
   835 			if ( editor.id === 'content' ) {
   832 				window.setTimeout( function() {
   836 				window.setTimeout( function() {
   833 					editor.save();
   837 					editor.save();
   834 					initialCompareString = getCompareString();
   838 					initialCompareString = getCompareString();
   835 				}, 1000 );
   839 				}, 1000 );
   836 			}
   840 			}
   837 		}).ready( function() {
   841 		}).ready( function() {
   838 
   842 
   839 			// Set the initial compare string in case TinyMCE is not used or not loaded first
   843 			// Set the initial compare string in case TinyMCE is not used or not loaded first.
   840 			initialCompareString = getCompareString();
   844 			initialCompareString = getCompareString();
   841 		});
   845 		});
   842 
   846 
   843 		return {
   847 		return {
   844 			getPostData: getPostData,
   848 			getPostData: getPostData,