[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/ -> autosave.js (source)

   1  /**
   2   * @output wp-includes/js/autosave.js
   3   */
   4  
   5  /* global tinymce, wpCookies, autosaveL10n, switchEditors */
   6  // Back-compat.
   7  window.autosave = function() {
   8      return true;
   9  };
  10  
  11  /**
  12   * Adds autosave to the window object on dom ready.
  13   *
  14   * @since 3.9.0
  15   *
  16   * @param {JQueryStatic} $      The jQuery object.
  17   * @param {Object}       window The window object.
  18   *
  19   */
  20  ( function( $, window ) {
  21      /**
  22       * Auto saves the post.
  23       *
  24       * @since 3.9.0
  25       *
  26       * @return {Object}
  27       *     {{
  28       *         getPostData: getPostData,
  29       *         getCompareString: getCompareString,
  30       *         disableButtons: disableButtons,
  31       *         enableButtons: enableButtons,
  32       *         local: ({hasStorage, getSavedPostData, save, suspend, resume}|*),
  33       *         server: ({tempBlockSave, triggerSave, postChanged, suspend, resume}|*)
  34       *     }}
  35       *     The object with all functions for autosave.
  36       */
  37  	function autosave() {
  38          var initialCompareString,
  39              initialCompareData = {},
  40              lastTriggerSave    = 0,
  41              $document          = $( document );
  42  
  43          /**
  44           * Sets the initial compare data.
  45           *
  46           * @since 5.6.1
  47           */
  48  		function setInitialCompare() {
  49              initialCompareData = {
  50                  post_title: $( '#title' ).val() || '',
  51                  content: $( '#content' ).val() || '',
  52                  excerpt: $( '#excerpt' ).val() || ''
  53              };
  54  
  55              initialCompareString = getCompareString( initialCompareData );
  56          }
  57  
  58          /**
  59           * Returns the data saved in both local and remote autosave.
  60           *
  61           * @since 3.9.0
  62           *
  63           * @param {string} type The type of autosave either local or remote.
  64           *
  65           * @return {Object} Object containing the post data.
  66           */
  67  		function getPostData( type ) {
  68              var post_name, parent_id, data,
  69                  time = ( new Date() ).getTime(),
  70                  cats = [],
  71                  editor = getEditor();
  72  
  73              // Don't run editor.save() more often than every 3 seconds.
  74              // It is resource intensive and might slow down typing in long posts on slow devices.
  75              if ( editor && editor.isDirty() && ! editor.isHidden() && time - 3000 > lastTriggerSave ) {
  76                  editor.save();
  77                  lastTriggerSave = time;
  78              }
  79  
  80              data = {
  81                  post_id: $( '#post_ID' ).val() || 0,
  82                  post_type: $( '#post_type' ).val() || '',
  83                  post_author: $( '#post_author' ).val() || '',
  84                  post_title: $( '#title' ).val() || '',
  85                  content: $( '#content' ).val() || '',
  86                  excerpt: $( '#excerpt' ).val() || ''
  87              };
  88  
  89              if ( type === 'local' ) {
  90                  return data;
  91              }
  92  
  93              $( 'input[id^="in-category-"]:checked' ).each( function() {
  94                  cats.push( this.value );
  95              });
  96              data.catslist = cats.join(',');
  97  
  98              if ( post_name = $( '#post_name' ).val() ) {
  99                  data.post_name = post_name;
 100              }
 101  
 102              if ( parent_id = $( '#parent_id' ).val() ) {
 103                  data.parent_id = parent_id;
 104              }
 105  
 106              if ( $( '#comment_status' ).prop( 'checked' ) ) {
 107                  data.comment_status = 'open';
 108              }
 109  
 110              if ( $( '#ping_status' ).prop( 'checked' ) ) {
 111                  data.ping_status = 'open';
 112              }
 113  
 114              if ( $( '#auto_draft' ).val() === '1' ) {
 115                  data.auto_draft = '1';
 116              }
 117  
 118              return data;
 119          }
 120  
 121          /**
 122           * Concatenates the title, content and excerpt. This is used to track changes
 123           * when auto-saving.
 124           *
 125           * @since 3.9.0
 126           *
 127           * @param {Object} postData The object containing the post data.
 128           *
 129           * @return {string} A concatenated string with title, content and excerpt.
 130           */
 131  		function getCompareString( postData ) {
 132              if ( typeof postData === 'object' ) {
 133                  return ( postData.post_title || '' ) + '::' + ( postData.content || '' ) + '::' + ( postData.excerpt || '' );
 134              }
 135  
 136              return ( $('#title').val() || '' ) + '::' + ( $('#content').val() || '' ) + '::' + ( $('#excerpt').val() || '' );
 137          }
 138  
 139          /**
 140           * Disables save buttons.
 141           *
 142           * @since 3.9.0
 143           *
 144           * @return {void}
 145           */
 146  		function disableButtons() {
 147              $document.trigger('autosave-disable-buttons');
 148  
 149              // Re-enable 5 sec later. Just gives autosave a head start to avoid collisions.
 150              setTimeout( enableButtons, 5000 );
 151          }
 152  
 153          /**
 154           * Enables save buttons.
 155           *
 156           * @since 3.9.0
 157           *
 158           * @return {void}
 159           */
 160  		function enableButtons() {
 161              $document.trigger( 'autosave-enable-buttons' );
 162          }
 163  
 164          /**
 165           * Gets the content editor.
 166           *
 167           * @since 4.6.0
 168           *
 169           * @return {boolean|*} Returns either false if the editor is undefined,
 170           *                     or the instance of the content editor.
 171           */
 172  		function getEditor() {
 173              return typeof tinymce !== 'undefined' && tinymce.get('content');
 174          }
 175  
 176          /**
 177           * Autosave in localStorage.
 178           *
 179           * @since 3.9.0
 180           *
 181           * @return {
 182           * {
 183           *     hasStorage: *,
 184           *     getSavedPostData: getSavedPostData,
 185           *     save: save,
 186           *     suspend: suspend,
 187           *     resume: resume
 188           *     }
 189           * }
 190           * The object with all functions for local storage autosave.
 191           */
 192  		function autosaveLocal() {
 193              var blog_id, post_id, hasStorage, intervalTimer,
 194                  lastCompareString,
 195                  isSuspended = false;
 196  
 197              /**
 198               * Checks if the browser supports sessionStorage and it's not disabled.
 199               *
 200               * @since 3.9.0
 201               *
 202               * @return {boolean} True if the sessionStorage is supported and enabled.
 203               */
 204  			function checkStorage() {
 205                  var test = Math.random().toString(),
 206                      result = false;
 207  
 208                  try {
 209                      window.sessionStorage.setItem( 'wp-test', test );
 210                      result = window.sessionStorage.getItem( 'wp-test' ) === test;
 211                      window.sessionStorage.removeItem( 'wp-test' );
 212                  } catch(e) {}
 213  
 214                  hasStorage = result;
 215                  return result;
 216              }
 217  
 218              /**
 219               * Initializes the local storage.
 220               *
 221               * @since 3.9.0
 222               *
 223               * @return {boolean|Object} False if no sessionStorage in the browser or an Object
 224               *                          containing all postData for this blog.
 225               */
 226  			function getStorage() {
 227                  var stored_obj = false;
 228                  // Separate local storage containers for each blog_id.
 229                  if ( hasStorage && blog_id ) {
 230                      stored_obj = sessionStorage.getItem( 'wp-autosave-' + blog_id );
 231  
 232                      if ( stored_obj ) {
 233                          stored_obj = JSON.parse( stored_obj );
 234                      } else {
 235                          stored_obj = {};
 236                      }
 237                  }
 238  
 239                  return stored_obj;
 240              }
 241  
 242              /**
 243               * Sets the storage for this blog. Confirms that the data was saved
 244               * successfully.
 245               *
 246               * @param {Object} stored_obj The storage object to set.
 247               * @since 3.9.0
 248               *
 249               * @return {boolean} True if the data was saved successfully, false if it wasn't saved.
 250               */
 251  			function setStorage( stored_obj ) {
 252                  var key;
 253  
 254                  if ( hasStorage && blog_id ) {
 255                      key = 'wp-autosave-' + blog_id;
 256                      sessionStorage.setItem( key, JSON.stringify( stored_obj ) );
 257                      return sessionStorage.getItem( key ) !== null;
 258                  }
 259  
 260                  return false;
 261              }
 262  
 263              /**
 264               * Gets the saved post data for the current post.
 265               *
 266               * @since 3.9.0
 267               *
 268               * @return {boolean|Object} False if no storage or no data or the postData as an Object.
 269               */
 270  			function getSavedPostData() {
 271                  var stored = getStorage();
 272  
 273                  if ( ! stored || ! post_id ) {
 274                      return false;
 275                  }
 276  
 277                  return stored[ 'post_' + post_id ] || false;
 278              }
 279  
 280              /**
 281               * Sets (save or delete) post data in the storage.
 282               *
 283               * If stored_data evaluates to 'false' the storage key for the current post will be removed.
 284               *
 285               * @since 3.9.0
 286               *
 287               * @param {Object|boolean|null} stored_data The post data to store or null/false/empty to delete the key.
 288               *
 289               * @return {boolean} True if data is stored, false if data was removed.
 290               */
 291  			function setData( stored_data ) {
 292                  var stored = getStorage();
 293  
 294                  if ( ! stored || ! post_id ) {
 295                      return false;
 296                  }
 297  
 298                  if ( stored_data ) {
 299                      stored[ 'post_' + post_id ] = stored_data;
 300                  } else if ( stored.hasOwnProperty( 'post_' + post_id ) ) {
 301                      delete stored[ 'post_' + post_id ];
 302                  } else {
 303                      return false;
 304                  }
 305  
 306                  return setStorage( stored );
 307              }
 308  
 309              /**
 310               * Sets isSuspended to true.
 311               *
 312               * @since 3.9.0
 313               *
 314               * @return {void}
 315               */
 316  			function suspend() {
 317                  isSuspended = true;
 318              }
 319  
 320              /**
 321               * Sets isSuspended to false.
 322               *
 323               * @since 3.9.0
 324               *
 325               * @return {void}
 326               */
 327  			function resume() {
 328                  isSuspended = false;
 329              }
 330  
 331              /**
 332               * Saves post data for the current post.
 333               *
 334               * Runs on a 15 seconds interval, saves when there are differences in the post title or content.
 335               * When the optional data is provided, updates the last saved post data.
 336               *
 337               * @since 3.9.0
 338               *
 339               * @param {Object} data The post data for saving, minimum 'post_title' and 'content'.
 340               *
 341               * @return {boolean} Returns true when data has been saved, otherwise it returns false.
 342               */
 343  			function save( data ) {
 344                  var postData, compareString,
 345                      result = false;
 346  
 347                  if ( isSuspended || ! hasStorage ) {
 348                      return false;
 349                  }
 350  
 351                  if ( data ) {
 352                      postData = getSavedPostData() || {};
 353                      $.extend( postData, data );
 354                  } else {
 355                      postData = getPostData('local');
 356                  }
 357  
 358                  compareString = getCompareString( postData );
 359  
 360                  if ( typeof lastCompareString === 'undefined' ) {
 361                      lastCompareString = initialCompareString;
 362                  }
 363  
 364                  // If the content, title and excerpt did not change since the last save, don't save again.
 365                  if ( compareString === lastCompareString ) {
 366                      return false;
 367                  }
 368  
 369                  postData.save_time = ( new Date() ).getTime();
 370                  postData.status = $( '#post_status' ).val() || '';
 371                  result = setData( postData );
 372  
 373                  if ( result ) {
 374                      lastCompareString = compareString;
 375                  }
 376  
 377                  return result;
 378              }
 379  
 380              /**
 381               * Initializes the auto save function.
 382               *
 383               * Checks whether the editor is active or not to use the editor events
 384               * to autosave, or uses the values from the elements to autosave.
 385               *
 386               * Runs on DOM ready.
 387               *
 388               * @since 3.9.0
 389               *
 390               * @return {void}
 391               */
 392  			function run() {
 393                  post_id = $('#post_ID').val() || 0;
 394  
 395                  // Check if the local post data is different than the loaded post data.
 396                  if ( $( '#wp-content-wrap' ).hasClass( 'tmce-active' ) ) {
 397  
 398                      /*
 399                       * If TinyMCE loads first, check the post 1.5 seconds after it is ready.
 400                       * By this time the content has been loaded in the editor and 'saved' to the textarea.
 401                       * This prevents false positives.
 402                       */
 403                      $document.on( 'tinymce-editor-init.autosave', function() {
 404                          window.setTimeout( function() {
 405                              checkPost();
 406                          }, 1500 );
 407                      });
 408                  } else {
 409                      checkPost();
 410                  }
 411  
 412                  // Save every 15 seconds.
 413                  intervalTimer = window.setInterval( save, 15000 );
 414  
 415                  $( 'form#post' ).on( 'submit.autosave-local', function() {
 416                      var editor = getEditor(),
 417                          post_id = $('#post_ID').val() || 0;
 418  
 419                      if ( editor && ! editor.isHidden() ) {
 420  
 421                          // Last onSubmit event in the editor, needs to run after the content has been moved to the textarea.
 422                          editor.on( 'submit', function() {
 423                              save({
 424                                  post_title: $( '#title' ).val() || '',
 425                                  content: $( '#content' ).val() || '',
 426                                  excerpt: $( '#excerpt' ).val() || ''
 427                              });
 428                          });
 429                      } else {
 430                          save({
 431                              post_title: $( '#title' ).val() || '',
 432                              content: $( '#content' ).val() || '',
 433                              excerpt: $( '#excerpt' ).val() || ''
 434                          });
 435                      }
 436  
 437                      var secure = ( 'https:' === window.location.protocol );
 438                      wpCookies.set( 'wp-saving-post', post_id + '-check', 24 * 60 * 60, false, false, secure );
 439                  });
 440              }
 441  
 442              /**
 443               * Compares 2 strings. Removes whitespaces in the strings before comparing them.
 444               *
 445               * @since 3.9.0
 446               *
 447               * @param {string} str1 The first string.
 448               * @param {string} str2 The second string.
 449               * @return {boolean} True if the strings are the same.
 450               */
 451  			function compare( str1, str2 ) {
 452  				function removeSpaces( string ) {
 453                      return string.toString().replace(/[\x20\t\r\n\f]+/g, '');
 454                  }
 455  
 456                  return ( removeSpaces( str1 || '' ) === removeSpaces( str2 || '' ) );
 457              }
 458  
 459              /**
 460               * Checks if the saved data for the current post (if any) is different than the
 461               * loaded post data on the screen.
 462               *
 463               * Shows a standard message letting the user restore the post data if different.
 464               *
 465               * @since 3.9.0
 466               *
 467               * @return {void}
 468               */
 469  			function checkPost() {
 470                  var content, post_title, excerpt, $notice,
 471                      postData = getSavedPostData(),
 472                      cookie = wpCookies.get( 'wp-saving-post' ),
 473                      $newerAutosaveNotice = $( '#has-newer-autosave' ).parent( '.notice' ),
 474                      $headerEnd = $( '.wp-header-end' );
 475  
 476                  if ( cookie === post_id + '-saved' ) {
 477                      wpCookies.remove( 'wp-saving-post' );
 478                      // The post was saved properly, remove old data and bail.
 479                      setData( false );
 480                      return;
 481                  }
 482  
 483                  if ( ! postData ) {
 484                      return;
 485                  }
 486  
 487                  content = $( '#content' ).val() || '';
 488                  post_title = $( '#title' ).val() || '';
 489                  excerpt = $( '#excerpt' ).val() || '';
 490  
 491                  if ( compare( content, postData.content ) && compare( post_title, postData.post_title ) &&
 492                      compare( excerpt, postData.excerpt ) ) {
 493  
 494                      return;
 495                  }
 496  
 497                  /*
 498                   * If '.wp-header-end' is found, append the notices after it otherwise
 499                   * after the first h1 or h2 heading found within the main content.
 500                   */
 501                  if ( ! $headerEnd.length ) {
 502                      $headerEnd = $( '.wrap h1, .wrap h2' ).first();
 503                  }
 504  
 505                  $notice = $( '#local-storage-notice' )
 506                      .insertAfter( $headerEnd )
 507                      .addClass( 'notice-warning' );
 508  
 509                  if ( $newerAutosaveNotice.length ) {
 510  
 511                      // If there is a "server" autosave notice, hide it.
 512                      // The data in the session storage is either the same or newer.
 513                      $newerAutosaveNotice.slideUp( 150, function() {
 514                          $notice.slideDown( 150 );
 515                      });
 516                  } else {
 517                      $notice.slideDown( 200 );
 518                  }
 519  
 520                  $notice.find( '.restore-backup' ).on( 'click.autosave-local', function() {
 521                      restorePost( postData );
 522                      $notice.fadeTo( 250, 0, function() {
 523                          $notice.slideUp( 150 );
 524                      });
 525                  });
 526              }
 527  
 528              /**
 529               * Restores the current title, content and excerpt from postData.
 530               *
 531               * @since 3.9.0
 532               *
 533               * @param {Object} postData The object containing all post data.
 534               *
 535               * @return {boolean} True if the post is restored.
 536               */
 537  			function restorePost( postData ) {
 538                  var editor;
 539  
 540                  if ( postData ) {
 541                      // Set the last saved data.
 542                      lastCompareString = getCompareString( postData );
 543  
 544                      if ( $( '#title' ).val() !== postData.post_title ) {
 545                          $( '#title' ).trigger( 'focus' ).val( postData.post_title || '' );
 546                      }
 547  
 548                      $( '#excerpt' ).val( postData.excerpt || '' );
 549                      editor = getEditor();
 550  
 551                      if ( editor && ! editor.isHidden() && typeof switchEditors !== 'undefined' ) {
 552                          if ( editor.settings.wpautop && postData.content ) {
 553                              postData.content = switchEditors.wpautop( postData.content );
 554                          }
 555  
 556                          // Make sure there's an undo level in the editor.
 557                          editor.undoManager.transact( function() {
 558                              editor.setContent( postData.content || '' );
 559                              editor.nodeChanged();
 560                          });
 561                      } else {
 562  
 563                          // Make sure the Code editor is selected.
 564                          $( '#content-html' ).trigger( 'click' );
 565                          $( '#content' ).trigger( 'focus' );
 566  
 567                          // Using document.execCommand() will let the user undo.
 568                          document.execCommand( 'selectAll' );
 569                          document.execCommand( 'insertText', false, postData.content || '' );
 570                      }
 571  
 572                      return true;
 573                  }
 574  
 575                  return false;
 576              }
 577  
 578              blog_id = typeof window.autosaveL10n !== 'undefined' && window.autosaveL10n.blog_id;
 579  
 580              /*
 581               * Check if the browser supports sessionStorage and it's not disabled,
 582               * then initialize and run checkPost().
 583               * Don't run if the post type supports neither 'editor' (textarea#content) nor 'excerpt'.
 584               */
 585              if ( checkStorage() && blog_id && ( $('#content').length || $('#excerpt').length ) ) {
 586                  $( run );
 587              }
 588  
 589              return {
 590                  hasStorage: hasStorage,
 591                  getSavedPostData: getSavedPostData,
 592                  save: save,
 593                  suspend: suspend,
 594                  resume: resume
 595              };
 596          }
 597  
 598          /**
 599           * Auto saves the post on the server.
 600           *
 601           * @since 3.9.0
 602           *
 603           * @return {Object} {
 604           *     {
 605           *         tempBlockSave: tempBlockSave,
 606           *         triggerSave: triggerSave,
 607           *         postChanged: postChanged,
 608           *         suspend: suspend,
 609           *         resume: resume
 610           *         }
 611           *     } The object all functions for autosave.
 612           */
 613  		function autosaveServer() {
 614              var _blockSave, _blockSaveTimer, previousCompareString, lastCompareString,
 615                  nextRun = 0,
 616                  isSuspended = false;
 617  
 618  
 619              /**
 620               * Blocks saving for the next 10 seconds.
 621               *
 622               * @since 3.9.0
 623               *
 624               * @return {void}
 625               */
 626  			function tempBlockSave() {
 627                  _blockSave = true;
 628                  window.clearTimeout( _blockSaveTimer );
 629  
 630                  _blockSaveTimer = window.setTimeout( function() {
 631                      _blockSave = false;
 632                  }, 10000 );
 633              }
 634  
 635              /**
 636               * Sets isSuspended to true.
 637               *
 638               * @since 3.9.0
 639               *
 640               * @return {void}
 641               */
 642  			function suspend() {
 643                  isSuspended = true;
 644              }
 645  
 646              /**
 647               * Sets isSuspended to false.
 648               *
 649               * @since 3.9.0
 650               *
 651               * @return {void}
 652               */
 653  			function resume() {
 654                  isSuspended = false;
 655              }
 656  
 657              /**
 658               * Triggers the autosave with the post data.
 659               *
 660               * @since 3.9.0
 661               *
 662               * @param {Object} data The post data.
 663               *
 664               * @return {void}
 665               */
 666  			function response( data ) {
 667                  _schedule();
 668                  _blockSave = false;
 669                  lastCompareString = previousCompareString;
 670                  previousCompareString = '';
 671  
 672                  $document.trigger( 'after-autosave', [data] );
 673                  enableButtons();
 674  
 675                  if ( data.success ) {
 676                      // No longer an auto-draft.
 677                      $( '#auto_draft' ).val('');
 678                  }
 679              }
 680  
 681              /**
 682               * Saves immediately.
 683               *
 684               * Resets the timing and tells heartbeat to connect now.
 685               *
 686               * @since 3.9.0
 687               *
 688               * @return {void}
 689               */
 690  			function triggerSave() {
 691                  nextRun = 0;
 692                  wp.heartbeat.connectNow();
 693              }
 694  
 695              /**
 696               * Checks if the post content in the textarea has changed since page load.
 697               *
 698               * This also happens when TinyMCE is active and editor.save() is triggered by
 699               * wp.autosave.getPostData().
 700               *
 701               * @since 3.9.0
 702               *
 703               * @return {boolean} True if the post has been changed.
 704               */
 705  			function postChanged() {
 706                  var changed = false;
 707  
 708                  // If there are TinyMCE instances, loop through them.
 709                  if ( window.tinymce ) {
 710                      window.tinymce.each( [ 'content', 'excerpt' ], function( field ) {
 711                          var editor = window.tinymce.get( field );
 712  
 713                          if ( ! editor || editor.isHidden() ) {
 714                              if ( ( $( '#' + field ).val() || '' ) !== initialCompareData[ field ] ) {
 715                                  changed = true;
 716                                  // Break.
 717                                  return false;
 718                              }
 719                          } else if ( editor.isDirty() ) {
 720                              changed = true;
 721                              return false;
 722                          }
 723                      } );
 724  
 725                      if ( ( $( '#title' ).val() || '' ) !== initialCompareData.post_title ) {
 726                          changed = true;
 727                      }
 728  
 729                      return changed;
 730                  }
 731  
 732                  return getCompareString() !== initialCompareString;
 733              }
 734  
 735              /**
 736               * Checks if the post can be saved or not.
 737               *
 738               * If the post hasn't changed or it cannot be updated,
 739               * because the autosave is blocked or suspended, the function returns false.
 740               *
 741               * @since 3.9.0
 742               *
 743               * @return {Object} Returns the post data.
 744               */
 745  			function save() {
 746                  var postData, compareString;
 747  
 748                  // window.autosave() used for back-compat.
 749                  if ( isSuspended || _blockSave || ! window.autosave() ) {
 750                      return false;
 751                  }
 752  
 753                  if ( ( new Date() ).getTime() < nextRun ) {
 754                      return false;
 755                  }
 756  
 757                  postData = getPostData();
 758                  compareString = getCompareString( postData );
 759  
 760                  // First check.
 761                  if ( typeof lastCompareString === 'undefined' ) {
 762                      lastCompareString = initialCompareString;
 763                  }
 764  
 765                  // No change.
 766                  if ( compareString === lastCompareString ) {
 767                      return false;
 768                  }
 769  
 770                  previousCompareString = compareString;
 771                  tempBlockSave();
 772                  disableButtons();
 773  
 774                  $document.trigger( 'wpcountwords', [ postData.content ] )
 775                      .trigger( 'before-autosave', [ postData ] );
 776  
 777                  postData._wpnonce = $( '#_wpnonce' ).val() || '';
 778  
 779                  return postData;
 780              }
 781  
 782              /**
 783               * Sets the next run, based on the autosave interval.
 784               *
 785               * @private
 786               *
 787               * @since 3.9.0
 788               *
 789               * @return {void}
 790               */
 791  			function _schedule() {
 792                  nextRun = ( new Date() ).getTime() + ( autosaveL10n.autosaveInterval * 1000 ) || 60000;
 793              }
 794  
 795              /**
 796               * Sets the autosaveData on the autosave heartbeat.
 797               *
 798               * @since 3.9.0
 799               *
 800               * @return {void}
 801               */
 802              $( function() {
 803                  _schedule();
 804              }).on( 'heartbeat-send.autosave', function( event, data ) {
 805                  var autosaveData = save();
 806  
 807                  if ( autosaveData ) {
 808                      data.wp_autosave = autosaveData;
 809                  }
 810  
 811                  /**
 812                   * Triggers the autosave of the post with the autosave data on the autosave
 813                   * heartbeat.
 814                   *
 815                   * @since 3.9.0
 816                   *
 817                   * @return {void}
 818                   */
 819              }).on( 'heartbeat-tick.autosave', function( event, data ) {
 820                  if ( data.wp_autosave ) {
 821                      response( data.wp_autosave );
 822                  }
 823                  /**
 824                   * Disables buttons and throws a notice when the connection is lost.
 825                   *
 826                   * @since 3.9.0
 827                   *
 828                   * @return {void}
 829                   */
 830              }).on( 'heartbeat-connection-lost.autosave', function( event, error, status ) {
 831  
 832                  // When connection is lost, keep user from submitting changes.
 833                  if ( 'timeout' === error || 603 === status ) {
 834                      var $notice = $('#lost-connection-notice');
 835  
 836                      if ( ! wp.autosave.local.hasStorage ) {
 837                          $notice.find('.hide-if-no-sessionstorage').hide();
 838                      }
 839  
 840                      $notice.show();
 841                      disableButtons();
 842                  }
 843  
 844                  /**
 845                   * Enables buttons when the connection is restored.
 846                   *
 847                   * @since 3.9.0
 848                   *
 849                   * @return {void}
 850                   */
 851              }).on( 'heartbeat-connection-restored.autosave', function() {
 852                  $('#lost-connection-notice').hide();
 853                  enableButtons();
 854              });
 855  
 856              return {
 857                  tempBlockSave: tempBlockSave,
 858                  triggerSave: triggerSave,
 859                  postChanged: postChanged,
 860                  suspend: suspend,
 861                  resume: resume
 862              };
 863          }
 864  
 865          /**
 866           * Sets the autosave time out.
 867           *
 868           * Wait for TinyMCE to initialize plus 1 second. for any external css to finish loading,
 869           * then save to the textarea before setting initialCompareString.
 870           * This avoids any insignificant differences between the initial textarea content and the content
 871           * extracted from the editor.
 872           *
 873           * @since 3.9.0
 874           *
 875           * @return {void}
 876           */
 877          $( function() {
 878              // Set the initial compare string in case TinyMCE is not used or not loaded first.
 879              setInitialCompare();
 880          }).on( 'tinymce-editor-init.autosave', function( event, editor ) {
 881              // Reset the initialCompare data after the TinyMCE instances have been initialized.
 882              if ( 'content' === editor.id || 'excerpt' === editor.id ) {
 883                  window.setTimeout( function() {
 884                      editor.save();
 885                      setInitialCompare();
 886                  }, 1000 );
 887              }
 888          });
 889  
 890          return {
 891              getPostData: getPostData,
 892              getCompareString: getCompareString,
 893              disableButtons: disableButtons,
 894              enableButtons: enableButtons,
 895              local: autosaveLocal(),
 896              server: autosaveServer()
 897          };
 898      }
 899  
 900      /** @namespace wp */
 901      window.wp = window.wp || {};
 902      window.wp.autosave = autosave();
 903  
 904  }( jQuery, window ));


Generated : Mon Sep 7 08:20:28 2026 Cross-referenced by PHPXref