[ 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                  /**
 453                   * Removes all whitespace characters from a string.
 454                   *
 455                   * @param {string} string The string to remove whitespace from.
 456                   * @return {string} The string without whitespace characters.
 457                   */
 458  				function removeSpaces( string ) {
 459                      return string.toString().replace(/[\x20\t\r\n\f]+/g, '');
 460                  }
 461  
 462                  return ( removeSpaces( str1 || '' ) === removeSpaces( str2 || '' ) );
 463              }
 464  
 465              /**
 466               * Checks if the saved data for the current post (if any) is different than the
 467               * loaded post data on the screen.
 468               *
 469               * Shows a standard message letting the user restore the post data if different.
 470               *
 471               * @since 3.9.0
 472               *
 473               * @return {void}
 474               */
 475  			function checkPost() {
 476                  var content, post_title, excerpt, $notice,
 477                      postData = getSavedPostData(),
 478                      cookie = wpCookies.get( 'wp-saving-post' ),
 479                      $newerAutosaveNotice = $( '#has-newer-autosave' ).parent( '.notice' ),
 480                      $headerEnd = $( '.wp-header-end' );
 481  
 482                  if ( cookie === post_id + '-saved' ) {
 483                      wpCookies.remove( 'wp-saving-post' );
 484                      // The post was saved properly, remove old data and bail.
 485                      setData( false );
 486                      return;
 487                  }
 488  
 489                  if ( ! postData ) {
 490                      return;
 491                  }
 492  
 493                  content = $( '#content' ).val() || '';
 494                  post_title = $( '#title' ).val() || '';
 495                  excerpt = $( '#excerpt' ).val() || '';
 496  
 497                  if ( compare( content, postData.content ) && compare( post_title, postData.post_title ) &&
 498                      compare( excerpt, postData.excerpt ) ) {
 499  
 500                      return;
 501                  }
 502  
 503                  /*
 504                   * If '.wp-header-end' is found, append the notices after it otherwise
 505                   * after the first h1 or h2 heading found within the main content.
 506                   */
 507                  if ( ! $headerEnd.length ) {
 508                      $headerEnd = $( '.wrap h1, .wrap h2' ).first();
 509                  }
 510  
 511                  $notice = $( '#local-storage-notice' )
 512                      .insertAfter( $headerEnd )
 513                      .addClass( 'notice-warning' );
 514  
 515                  if ( $newerAutosaveNotice.length ) {
 516  
 517                      // If there is a "server" autosave notice, hide it.
 518                      // The data in the session storage is either the same or newer.
 519                      $newerAutosaveNotice.slideUp( 150, function() {
 520                          $notice.slideDown( 150 );
 521                      });
 522                  } else {
 523                      $notice.slideDown( 200 );
 524                  }
 525  
 526                  $notice.find( '.restore-backup' ).on( 'click.autosave-local', function() {
 527                      restorePost( postData );
 528                      $notice.fadeTo( 250, 0, function() {
 529                          $notice.slideUp( 150 );
 530                      });
 531                  });
 532              }
 533  
 534              /**
 535               * Restores the current title, content and excerpt from postData.
 536               *
 537               * @since 3.9.0
 538               *
 539               * @param {Object} postData The object containing all post data.
 540               *
 541               * @return {boolean} True if the post is restored.
 542               */
 543  			function restorePost( postData ) {
 544                  var editor;
 545  
 546                  if ( postData ) {
 547                      // Set the last saved data.
 548                      lastCompareString = getCompareString( postData );
 549  
 550                      if ( $( '#title' ).val() !== postData.post_title ) {
 551                          $( '#title' ).trigger( 'focus' ).val( postData.post_title || '' );
 552                      }
 553  
 554                      $( '#excerpt' ).val( postData.excerpt || '' );
 555                      editor = getEditor();
 556  
 557                      if ( editor && ! editor.isHidden() && typeof switchEditors !== 'undefined' ) {
 558                          if ( editor.settings.wpautop && postData.content ) {
 559                              postData.content = switchEditors.wpautop( postData.content );
 560                          }
 561  
 562                          // Make sure there's an undo level in the editor.
 563                          editor.undoManager.transact( function() {
 564                              editor.setContent( postData.content || '' );
 565                              editor.nodeChanged();
 566                          });
 567                      } else {
 568  
 569                          // Make sure the Code editor is selected.
 570                          $( '#content-html' ).trigger( 'click' );
 571                          $( '#content' ).trigger( 'focus' );
 572  
 573                          // Using document.execCommand() will let the user undo.
 574                          document.execCommand( 'selectAll' );
 575                          document.execCommand( 'insertText', false, postData.content || '' );
 576                      }
 577  
 578                      return true;
 579                  }
 580  
 581                  return false;
 582              }
 583  
 584              blog_id = typeof window.autosaveL10n !== 'undefined' && window.autosaveL10n.blog_id;
 585  
 586              /*
 587               * Check if the browser supports sessionStorage and it's not disabled,
 588               * then initialize and run checkPost().
 589               * Don't run if the post type supports neither 'editor' (textarea#content) nor 'excerpt'.
 590               */
 591              if ( checkStorage() && blog_id && ( $('#content').length || $('#excerpt').length ) ) {
 592                  $( run );
 593              }
 594  
 595              return {
 596                  hasStorage: hasStorage,
 597                  getSavedPostData: getSavedPostData,
 598                  save: save,
 599                  suspend: suspend,
 600                  resume: resume
 601              };
 602          }
 603  
 604          /**
 605           * Auto saves the post on the server.
 606           *
 607           * @since 3.9.0
 608           *
 609           * @return {Object} {
 610           *     {
 611           *         tempBlockSave: tempBlockSave,
 612           *         triggerSave: triggerSave,
 613           *         postChanged: postChanged,
 614           *         suspend: suspend,
 615           *         resume: resume
 616           *         }
 617           *     } The object all functions for autosave.
 618           */
 619  		function autosaveServer() {
 620              var _blockSave, _blockSaveTimer, previousCompareString, lastCompareString,
 621                  nextRun = 0,
 622                  isSuspended = false;
 623  
 624  
 625              /**
 626               * Blocks saving for the next 10 seconds.
 627               *
 628               * @since 3.9.0
 629               *
 630               * @return {void}
 631               */
 632  			function tempBlockSave() {
 633                  _blockSave = true;
 634                  window.clearTimeout( _blockSaveTimer );
 635  
 636                  _blockSaveTimer = window.setTimeout( function() {
 637                      _blockSave = false;
 638                  }, 10000 );
 639              }
 640  
 641              /**
 642               * Sets isSuspended to true.
 643               *
 644               * @since 3.9.0
 645               *
 646               * @return {void}
 647               */
 648  			function suspend() {
 649                  isSuspended = true;
 650              }
 651  
 652              /**
 653               * Sets isSuspended to false.
 654               *
 655               * @since 3.9.0
 656               *
 657               * @return {void}
 658               */
 659  			function resume() {
 660                  isSuspended = false;
 661              }
 662  
 663              /**
 664               * Triggers the autosave with the post data.
 665               *
 666               * @since 3.9.0
 667               *
 668               * @param {Object} data The post data.
 669               *
 670               * @return {void}
 671               */
 672  			function response( data ) {
 673                  _schedule();
 674                  _blockSave = false;
 675                  lastCompareString = previousCompareString;
 676                  previousCompareString = '';
 677  
 678                  $document.trigger( 'after-autosave', [data] );
 679                  enableButtons();
 680  
 681                  if ( data.success ) {
 682                      // No longer an auto-draft.
 683                      $( '#auto_draft' ).val('');
 684                  }
 685              }
 686  
 687              /**
 688               * Saves immediately.
 689               *
 690               * Resets the timing and tells heartbeat to connect now.
 691               *
 692               * @since 3.9.0
 693               *
 694               * @return {void}
 695               */
 696  			function triggerSave() {
 697                  nextRun = 0;
 698                  wp.heartbeat.connectNow();
 699              }
 700  
 701              /**
 702               * Checks if the post content in the textarea has changed since page load.
 703               *
 704               * This also happens when TinyMCE is active and editor.save() is triggered by
 705               * wp.autosave.getPostData().
 706               *
 707               * @since 3.9.0
 708               *
 709               * @return {boolean} True if the post has been changed.
 710               */
 711  			function postChanged() {
 712                  var changed = false;
 713  
 714                  // If there are TinyMCE instances, loop through them.
 715                  if ( window.tinymce ) {
 716                      window.tinymce.each( [ 'content', 'excerpt' ], function( field ) {
 717                          var editor = window.tinymce.get( field );
 718  
 719                          if ( ! editor || editor.isHidden() ) {
 720                              if ( ( $( '#' + field ).val() || '' ) !== initialCompareData[ field ] ) {
 721                                  changed = true;
 722                                  // Break.
 723                                  return false;
 724                              }
 725                          } else if ( editor.isDirty() ) {
 726                              changed = true;
 727                              return false;
 728                          }
 729                      } );
 730  
 731                      if ( ( $( '#title' ).val() || '' ) !== initialCompareData.post_title ) {
 732                          changed = true;
 733                      }
 734  
 735                      return changed;
 736                  }
 737  
 738                  return getCompareString() !== initialCompareString;
 739              }
 740  
 741              /**
 742               * Checks if the post can be saved or not.
 743               *
 744               * If the post hasn't changed or it cannot be updated,
 745               * because the autosave is blocked or suspended, the function returns false.
 746               *
 747               * @since 3.9.0
 748               *
 749               * @return {Object} Returns the post data.
 750               */
 751  			function save() {
 752                  var postData, compareString;
 753  
 754                  // window.autosave() used for back-compat.
 755                  if ( isSuspended || _blockSave || ! window.autosave() ) {
 756                      return false;
 757                  }
 758  
 759                  if ( ( new Date() ).getTime() < nextRun ) {
 760                      return false;
 761                  }
 762  
 763                  postData = getPostData();
 764                  compareString = getCompareString( postData );
 765  
 766                  // First check.
 767                  if ( typeof lastCompareString === 'undefined' ) {
 768                      lastCompareString = initialCompareString;
 769                  }
 770  
 771                  // No change.
 772                  if ( compareString === lastCompareString ) {
 773                      return false;
 774                  }
 775  
 776                  previousCompareString = compareString;
 777                  tempBlockSave();
 778                  disableButtons();
 779  
 780                  $document.trigger( 'wpcountwords', [ postData.content ] )
 781                      .trigger( 'before-autosave', [ postData ] );
 782  
 783                  postData._wpnonce = $( '#_wpnonce' ).val() || '';
 784  
 785                  return postData;
 786              }
 787  
 788              /**
 789               * Sets the next run, based on the autosave interval.
 790               *
 791               * @private
 792               *
 793               * @since 3.9.0
 794               *
 795               * @return {void}
 796               */
 797  			function _schedule() {
 798                  nextRun = ( new Date() ).getTime() + ( autosaveL10n.autosaveInterval * 1000 ) || 60000;
 799              }
 800  
 801              /**
 802               * Sets the autosaveData on the autosave heartbeat.
 803               *
 804               * @since 3.9.0
 805               *
 806               * @return {void}
 807               */
 808              $( function() {
 809                  _schedule();
 810              }).on( 'heartbeat-send.autosave', function( event, data ) {
 811                  var autosaveData = save();
 812  
 813                  if ( autosaveData ) {
 814                      data.wp_autosave = autosaveData;
 815                  }
 816  
 817                  /**
 818                   * Triggers the autosave of the post with the autosave data on the autosave
 819                   * heartbeat.
 820                   *
 821                   * @since 3.9.0
 822                   *
 823                   * @return {void}
 824                   */
 825              }).on( 'heartbeat-tick.autosave', function( event, data ) {
 826                  if ( data.wp_autosave ) {
 827                      response( data.wp_autosave );
 828                  }
 829                  /**
 830                   * Disables buttons and throws a notice when the connection is lost.
 831                   *
 832                   * @since 3.9.0
 833                   *
 834                   * @return {void}
 835                   */
 836              }).on( 'heartbeat-connection-lost.autosave', function( event, error, status ) {
 837  
 838                  // When connection is lost, keep user from submitting changes.
 839                  if ( 'timeout' === error || 603 === status ) {
 840                      var $notice = $('#lost-connection-notice');
 841  
 842                      if ( ! wp.autosave.local.hasStorage ) {
 843                          $notice.find('.hide-if-no-sessionstorage').hide();
 844                      }
 845  
 846                      $notice.show();
 847                      disableButtons();
 848                  }
 849  
 850                  /**
 851                   * Enables buttons when the connection is restored.
 852                   *
 853                   * @since 3.9.0
 854                   *
 855                   * @return {void}
 856                   */
 857              }).on( 'heartbeat-connection-restored.autosave', function() {
 858                  $('#lost-connection-notice').hide();
 859                  enableButtons();
 860              });
 861  
 862              return {
 863                  tempBlockSave: tempBlockSave,
 864                  triggerSave: triggerSave,
 865                  postChanged: postChanged,
 866                  suspend: suspend,
 867                  resume: resume
 868              };
 869          }
 870  
 871          /**
 872           * Sets the autosave time out.
 873           *
 874           * Wait for TinyMCE to initialize plus 1 second. for any external css to finish loading,
 875           * then save to the textarea before setting initialCompareString.
 876           * This avoids any insignificant differences between the initial textarea content and the content
 877           * extracted from the editor.
 878           *
 879           * @since 3.9.0
 880           *
 881           * @return {void}
 882           */
 883          $( function() {
 884              // Set the initial compare string in case TinyMCE is not used or not loaded first.
 885              setInitialCompare();
 886          }).on( 'tinymce-editor-init.autosave', function( event, editor ) {
 887              // Reset the initialCompare data after the TinyMCE instances have been initialized.
 888              if ( 'content' === editor.id || 'excerpt' === editor.id ) {
 889                  window.setTimeout( function() {
 890                      editor.save();
 891                      setInitialCompare();
 892                  }, 1000 );
 893              }
 894          });
 895  
 896          return {
 897              getPostData: getPostData,
 898              getCompareString: getCompareString,
 899              disableButtons: disableButtons,
 900              enableButtons: enableButtons,
 901              local: autosaveLocal(),
 902              server: autosaveServer()
 903          };
 904      }
 905  
 906      /** @namespace wp */
 907      window.wp = window.wp || {};
 908      window.wp.autosave = autosave();
 909  
 910  }( jQuery, window ));


Generated : Wed Sep 16 08:20:31 2026 Cross-referenced by PHPXref