JAVASCRIPT   31

autosave js

Guest on 13th June 2022 01:09:00 AM

  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 {jQuery} $ jQuery object.
  17.  * @param {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.                          * @since 3.9.0
  247.                          *
  248.                          * @return {boolean} True if the data was saved successfully, false if it wasn't saved.
  249.                          */
  250.                         function setStorage( stored_obj ) {
  251.                                 var key;
  252.  
  253.                                 if ( hasStorage && blog_id ) {
  254.                                         key = 'wp-autosave-' + blog_id;
  255.                                         sessionStorage.setItem( key, JSON.stringify( stored_obj ) );
  256.                                         return sessionStorage.getItem( key ) !== null;
  257.                                 }
  258.  
  259.                                 return false;
  260.                         }
  261.  
  262.                         /**
  263.                          * Gets the saved post data for the current post.
  264.                          *
  265.                          * @since 3.9.0
  266.                          *
  267.                          * @return {boolean|Object} False if no storage or no data or the postData as an Object.
  268.                          */
  269.                         function getSavedPostData() {
  270.                                 var stored = getStorage();
  271.  
  272.                                 if ( ! stored || ! post_id ) {
  273.                                         return false;
  274.                                 }
  275.  
  276.                                 return stored[ 'post_' + post_id ] || false;
  277.                         }
  278.  
  279.                         /**
  280.                          * Sets (save or delete) post data in the storage.
  281.                          *
  282.                          * If stored_data evaluates to 'false' the storage key for the current post will be removed.
  283.                          *
  284.                          * @since 3.9.0
  285.                          *
  286.                          * @param {Object|boolean|null} stored_data The post data to store or null/false/empty to delete the key.
  287.                          *
  288.                          * @return {boolean} True if data is stored, false if data was removed.
  289.                          */
  290.                         function setData( stored_data ) {
  291.                                 var stored = getStorage();
  292.  
  293.                                 if ( ! stored || ! post_id ) {
  294.                                         return false;
  295.                                 }
  296.  
  297.                                 if ( stored_data ) {
  298.                                         stored[ 'post_' + post_id ] = stored_data;
  299.                                 } else if ( stored.hasOwnProperty( 'post_' + post_id ) ) {
  300.                                         delete stored[ 'post_' + post_id ];
  301.                                 } else {
  302.                                         return false;
  303.                                 }
  304.  
  305.                                 return setStorage( stored );
  306.                         }
  307.  
  308.                         /**
  309.                          * Sets isSuspended to true.
  310.                          *
  311.                          * @since 3.9.0
  312.                          *
  313.                          * @return {void}
  314.                          */
  315.                         function suspend() {
  316.                                 isSuspended = true;
  317.                         }
  318.  
  319.                         /**
  320.                          * Sets isSuspended to false.
  321.                          *
  322.                          * @since 3.9.0
  323.                          *
  324.                          * @return {void}
  325.                          */
  326.                         function resume() {
  327.                                 isSuspended = false;
  328.                         }
  329.  
  330.                         /**
  331.                          * Saves post data for the current post.
  332.                          *
  333.                          * Runs on a 15 seconds interval, saves when there are differences in the post title or content.
  334.                          * When the optional data is provided, updates the last saved post data.
  335.                          *
  336.                          * @since 3.9.0
  337.                          *
  338.                          * @param {Object} data The post data for saving, minimum 'post_title' and 'content'.
  339.                          *
  340.                          * @return {boolean} Returns true when data has been saved, otherwise it returns false.
  341.                          */
  342.                         function save( data ) {
  343.                                 var postData, compareString,
  344.                                         result = false;
  345.  
  346.                                 if ( isSuspended || ! hasStorage ) {
  347.                                         return false;
  348.                                 }
  349.  
  350.                                 if ( data ) {
  351.                                         postData = getSavedPostData() || {};
  352.                                         $.extend( postData, data );
  353.                                 } else {
  354.                                         postData = getPostData('local');
  355.                                 }
  356.  
  357.                                 compareString = getCompareString( postData );
  358.  
  359.                                 if ( typeof lastCompareString === 'undefined' ) {
  360.                                         lastCompareString = initialCompareString;
  361.                                 }
  362.  
  363.                                 // If the content, title and excerpt did not change since the last save, don't save again.
  364.                                 if ( compareString === lastCompareString ) {
  365.                                         return false;
  366.                                 }
  367.  
  368.                                 postData.save_time = ( new Date() ).getTime();
  369.                                 postData.status = $( '#post_status' ).val() || '';
  370.                                 result = setData( postData );
  371.  
  372.                                 if ( result ) {
  373.                                         lastCompareString = compareString;
  374.                                 }
  375.  
  376.                                 return result;
  377.                         }
  378.  
  379.                         /**
  380.                          * Initializes the auto save function.
  381.                          *
  382.                          * Checks whether the editor is active or not to use the editor events
  383.                          * to autosave, or uses the values from the elements to autosave.
  384.                          *
  385.                          * Runs on DOM ready.
  386.                          *
  387.                          * @since 3.9.0
  388.                          *
  389.                          * @return {void}
  390.                          */
  391.                         function run() {
  392.                                 post_id = $('#post_ID').val() || 0;
  393.  
  394.                                 // Check if the local post data is different than the loaded post data.
  395.                                 if ( $( '#wp-content-wrap' ).hasClass( 'tmce-active' ) ) {
  396.  
  397.                                         /*
  398.                                          * If TinyMCE loads first, check the post 1.5 seconds after it is ready.
  399.                                          * By this time the content has been loaded in the editor and 'saved' to the textarea.
  400.                                          * This prevents false positives.
  401.                                          */
  402.                                         $document.on( 'tinymce-editor-init.autosave', function() {
  403.                                                 window.setTimeout( function() {
  404.                                                         checkPost();
  405.                                                 }, 1500 );
  406.                                         });
  407.                                 } else {
  408.                                         checkPost();
  409.                                 }
  410.  
  411.                                 // Save every 15 seconds.
  412.                                 intervalTimer = window.setInterval( save, 15000 );
  413.  
  414.                                 $( 'form#post' ).on( 'submit.autosave-local', function() {
  415.                                         var editor = getEditor(),
  416.                                                 post_id = $('#post_ID').val() || 0;
  417.  
  418.                                         if ( editor && ! editor.isHidden() ) {
  419.  
  420.                                                 // Last onSubmit event in the editor, needs to run after the content has been moved to the textarea.
  421.                                                 editor.on( 'submit', function() {
  422.                                                         save({
  423.                                                                 post_title: $( '#title' ).val() || '',
  424.                                                                 content: $( '#content' ).val() || '',
  425.                                                                 excerpt: $( '#excerpt' ).val() || ''
  426.                                                         });
  427.                                                 });
  428.                                         } else {
  429.                                                 save({
  430.                                                         post_title: $( '#title' ).val() || '',
  431.                                                         content: $( '#content' ).val() || '',
  432.                                                         excerpt: $( '#excerpt' ).val() || ''
  433.                                                 });
  434.                                         }
  435.  
  436.                                         var secure = ( 'https:' === window.location.protocol );
  437.                                         wpCookies.set( 'wp-saving-post', post_id + '-check', 24 * 60 * 60, false, false, secure );
  438.                                 });
  439.                         }
  440.  
  441.                         /**
  442.                          * Compares 2 strings. Removes whitespaces in the strings before comparing them.
  443.                          *
  444.                          * @since 3.9.0
  445.                          *
  446.                          * @param {string} str1 The first string.
  447.                          * @param {string} str2 The second string.
  448.                          * @return {boolean} True if the strings are the same.
  449.                          */
  450.                         function compare( str1, str2 ) {
  451.                                 function removeSpaces( string ) {
  452.                                         return string.toString().replace(/[\x20\t\r\n\f]+/g, '');
  453.                                 }
  454.  
  455.                                 return ( removeSpaces( str1 || '' ) === removeSpaces( str2 || '' ) );
  456.                         }
  457.  
  458.                         /**
  459.                          * Checks if the saved data for the current post (if any) is different than the
  460.                          * loaded post data on the screen.
  461.                          *
  462.                          * Shows a standard message letting the user restore the post data if different.
  463.                          *
  464.                          * @since 3.9.0
  465.                          *
  466.                          * @return {void}
  467.                          */
  468.                         function checkPost() {
  469.                                 var content, post_title, excerpt, $notice,
  470.                                         postData = getSavedPostData(),
  471.                                         cookie = wpCookies.get( 'wp-saving-post' ),
  472.                                         $newerAutosaveNotice = $( '#has-newer-autosave' ).parent( '.notice' ),
  473.                                         $headerEnd = $( '.wp-header-end' );
  474.  
  475.                                 if ( cookie === post_id + '-saved' ) {
  476.                                         wpCookies.remove( 'wp-saving-post' );
  477.                                         // The post was saved properly, remove old data and bail.
  478.                                         setData( false );
  479.                                         return;
  480.                                 }
  481.  
  482.                                 if ( ! postData ) {
  483.                                         return;
  484.                                 }
  485.  
  486.                                 content = $( '#content' ).val() || '';
  487.                                 post_title = $( '#title' ).val() || '';
  488.                                 excerpt = $( '#excerpt' ).val() || '';
  489.  
  490.                                 if ( compare( content, postData.content ) && compare( post_title, postData.post_title ) &&
  491.                                         compare( excerpt, postData.excerpt ) ) {
  492.  
  493.                                         return;
  494.                                 }
  495.  
  496.                                 /*
  497.                                  * If '.wp-header-end' is found, append the notices after it otherwise
  498.                                  * after the first h1 or h2 heading found within the main content.
  499.                                  */
  500.                                 if ( ! $headerEnd.length ) {
  501.                                         $headerEnd = $( '.wrap h1, .wrap h2' ).first();
  502.                                 }
  503.  
  504.                                 $notice = $( '#local-storage-notice' )
  505.                                         .insertAfter( $headerEnd )
  506.                                         .addClass( 'notice-warning' );
  507.  
  508.                                 if ( $newerAutosaveNotice.length ) {
  509.  
  510.                                         // If there is a "server" autosave notice, hide it.
  511.                                         // The data in the session storage is either the same or newer.
  512.                                         $newerAutosaveNotice.slideUp( 150, function() {
  513.                                                 $notice.slideDown( 150 );
  514.                                         });
  515.                                 } else {
  516.                                         $notice.slideDown( 200 );
  517.                                 }
  518.  
  519.                                 $notice.find( '.restore-backup' ).on( 'click.autosave-local', function() {
  520.                                         restorePost( postData );
  521.                                         $notice.fadeTo( 250, 0, function() {
  522.                                                 $notice.slideUp( 150 );
  523.                                         });
  524.                                 });
  525.                         }
  526.  
  527.                         /**
  528.                          * Restores the current title, content and excerpt from postData.
  529.                          *
  530.                          * @since 3.9.0
  531.                          *
  532.                          * @param {Object} postData The object containing all post data.
  533.                          *
  534.                          * @return {boolean} True if the post is restored.
  535.                          */
  536.                         function restorePost( postData ) {
  537.                                 var editor;
  538.  
  539.                                 if ( postData ) {
  540.                                         // Set the last saved data.
  541.                                         lastCompareString = getCompareString( postData );
  542.  
  543.                                         if ( $( '#title' ).val() !== postData.post_title ) {
  544.                                                 $( '#title' ).trigger( 'focus' ).val( postData.post_title || '' );
  545.                                         }
  546.  
  547.                                         $( '#excerpt' ).val( postData.excerpt || '' );
  548.                                         editor = getEditor();
  549.  
  550.                                         if ( editor && ! editor.isHidden() && typeof switchEditors !== 'undefined' ) {
  551.                                                 if ( editor.settings.wpautop && postData.content ) {
  552.                                                         postData.content = switchEditors.wpautop( postData.content );
  553.                                                 }
  554.  
  555.                                                 // Make sure there's an undo level in the editor.
  556.                                                 editor.undoManager.transact( function() {
  557.                                                         editor.setContent( postData.content || '' );
  558.                                                         editor.nodeChanged();
  559.                                                 });
  560.                                         } else {
  561.  
  562.                                                 // Make sure the Text editor is selected.
  563.                                                 $( '#content-html' ).trigger( 'click' );
  564.                                                 $( '#content' ).trigger( 'focus' );
  565.  
  566.                                                 // Using document.execCommand() will let the user undo.
  567.                                                 document.execCommand( 'selectAll' );
  568.                                                 document.execCommand( 'insertText', false, postData.content || '' );
  569.                                         }
  570.  
  571.                                         return true;
  572.                                 }
  573.  
  574.                                 return false;
  575.                         }
  576.  
  577.                         blog_id = typeof window.autosaveL10n !== 'undefined' && window.autosaveL10n.blog_id;
  578.  
  579.                         /*
  580.                          * Check if the browser supports sessionStorage and it's not disabled,
  581.                          * then initialize and run checkPost().
  582.                          * Don't run if the post type supports neither 'editor' (textarea#content) nor 'excerpt'.
  583.                          */
  584.                         if ( checkStorage() && blog_id && ( $('#content').length || $('#excerpt').length ) ) {
  585.                                 $( run );
  586.                         }
  587.  
  588.                         return {
  589.                                 hasStorage: hasStorage,
  590.                                 getSavedPostData: getSavedPostData,
  591.                                 save: save,
  592.                                 suspend: suspend,
  593.                                 resume: resume
  594.                         };
  595.                 }
  596.  
  597.                 /**
  598.                  * Auto saves the post on the server.
  599.                  *
  600.                  * @since 3.9.0
  601.                  *
  602.                  * @return {Object} {
  603.                  *      {
  604.                  *              tempBlockSave: tempBlockSave,
  605.                  *              triggerSave: triggerSave,
  606.                  *              postChanged: postChanged,
  607.                  *              suspend: suspend,
  608.                  *              resume: resume
  609.                  *              }
  610.                  *      } The object all functions for autosave.
  611.                  */
  612.                 function autosaveServer() {
  613.                         var _blockSave, _blockSaveTimer, previousCompareString, lastCompareString,
  614.                                 nextRun = 0,
  615.                                 isSuspended = false;
  616.  
  617.  
  618.                         /**
  619.                          * Blocks saving for the next 10 seconds.
  620.                          *
  621.                          * @since 3.9.0
  622.                          *
  623.                          * @return {void}
  624.                          */
  625.                         function tempBlockSave() {
  626.                                 _blockSave = true;
  627.                                 window.clearTimeout( _blockSaveTimer );
  628.  
  629.                                 _blockSaveTimer = window.setTimeout( function() {
  630.                                         _blockSave = false;
  631.                                 }, 10000 );
  632.                         }
  633.  
  634.                         /**
  635.                          * Sets isSuspended to true.
  636.                          *
  637.                          * @since 3.9.0
  638.                          *
  639.                          * @return {void}
  640.                          */
  641.                         function suspend() {
  642.                                 isSuspended = true;
  643.                         }
  644.  
  645.                         /**
  646.                          * Sets isSuspended to false.
  647.                          *
  648.                          * @since 3.9.0
  649.                          *
  650.                          * @return {void}
  651.                          */
  652.                         function resume() {
  653.                                 isSuspended = false;
  654.                         }
  655.  
  656.                         /**
  657.                          * Triggers the autosave with the post data.
  658.                          *
  659.                          * @since 3.9.0
  660.                          *
  661.                          * @param {Object} data The post data.
  662.                          *
  663.                          * @return {void}
  664.                          */
  665.                         function response( data ) {
  666.                                 _schedule();
  667.                                 _blockSave = false;
  668.                                 lastCompareString = previousCompareString;
  669.                                 previousCompareString = '';
  670.  
  671.                                 $document.trigger( 'after-autosave', [data] );
  672.                                 enableButtons();
  673.  
  674.                                 if ( data.success ) {
  675.                                         // No longer an auto-draft.
  676.                                         $( '#auto_draft' ).val('');
  677.                                 }
  678.                         }
  679.  
  680.                         /**
  681.                          * Saves immediately.
  682.                          *
  683.                          * Resets the timing and tells heartbeat to connect now.
  684.                          *
  685.                          * @since 3.9.0
  686.                          *
  687.                          * @return {void}
  688.                          */
  689.                         function triggerSave() {
  690.                                 nextRun = 0;
  691.                                 wp.heartbeat.connectNow();
  692.                         }
  693.  
  694.                         /**
  695.                          * Checks if the post content in the textarea has changed since page load.
  696.                          *
  697.                          * This also happens when TinyMCE is active and editor.save() is triggered by
  698.                          * wp.autosave.getPostData().
  699.                          *
  700.                          * @since 3.9.0
  701.                          *
  702.                          * @return {boolean} True if the post has been changed.
  703.                          */
  704.                         function postChanged() {
  705.                                 var changed = false;
  706.  
  707.                                 // If there are TinyMCE instances, loop through them.
  708.                                 if ( window.tinymce ) {
  709.                                         window.tinymce.each( [ 'content', 'excerpt' ], function( field ) {
  710.                                                 var editor = window.tinymce.get( field );
  711.  
  712.                                                 if ( ! editor || editor.isHidden() ) {
  713.                                                         if ( ( $( '#' + field ).val() || '' ) !== initialCompareData[ field ] ) {
  714.                                                                 changed = true;
  715.                                                                 // Break.
  716.                                                                 return false;
  717.                                                         }
  718.                                                 } else if ( editor.isDirty() ) {
  719.                                                         changed = true;
  720.                                                         return false;
  721.                                                 }
  722.                                         } );
  723.  
  724.                                         if ( ( $( '#title' ).val() || '' ) !== initialCompareData.post_title ) {
  725.                                                 changed = true;
  726.                                         }
  727.  
  728.                                         return changed;
  729.                                 }
  730.  
  731.                                 return getCompareString() !== initialCompareString;
  732.                         }
  733.  
  734.                         /**
  735.                          * Checks if the post can be saved or not.
  736.                          *
  737.                          * If the post hasn't changed or it cannot be updated,
  738.                          * because the autosave is blocked or suspended, the function returns false.
  739.                          *
  740.                          * @since 3.9.0
  741.                          *
  742.                          * @return {Object} Returns the post data.
  743.                          */
  744.                         function save() {
  745.                                 var postData, compareString;
  746.  
  747.                                 // window.autosave() used for back-compat.
  748.                                 if ( isSuspended || _blockSave || ! window.autosave() ) {
  749.                                         return false;
  750.                                 }
  751.  
  752.                                 if ( ( new Date() ).getTime() < nextRun ) {
  753.                                         return false;
  754.                                 }
  755.  
  756.                                 postData = getPostData();
  757.                                 compareString = getCompareString( postData );
  758.  
  759.                                 // First check.
  760.                                 if ( typeof lastCompareString === 'undefined' ) {
  761.                                         lastCompareString = initialCompareString;
  762.                                 }
  763.  
  764.                                 // No change.
  765.                                 if ( compareString === lastCompareString ) {
  766.                                         return false;
  767.                                 }
  768.  
  769.                                 previousCompareString = compareString;
  770.                                 tempBlockSave();
  771.                                 disableButtons();
  772.  
  773.                                 $document.trigger( 'wpcountwords', [ postData.content ] )
  774.                                         .trigger( 'before-autosave', [ postData ] );
  775.  
  776.                                 postData._wpnonce = $( '#_wpnonce' ).val() || '';
  777.  
  778.                                 return postData;
  779.                         }
  780.  
  781.                         /**
  782.                          * Sets the next run, based on the autosave interval.
  783.                          *
  784.                          * @private
  785.                          *
  786.                          * @since 3.9.0
  787.                          *
  788.                          * @return {void}
  789.                          */
  790.                         function _schedule() {
  791.                                 nextRun = ( new Date() ).getTime() + ( autosaveL10n.autosaveInterval * 1000 ) || 60000;
  792.                         }
  793.  
  794.                         /**
  795.                          * Sets the autosaveData on the autosave heartbeat.
  796.                          *
  797.                          * @since 3.9.0
  798.                          *
  799.                          * @return {void}
  800.                          */
  801.                         $( function() {
  802.                                 _schedule();
  803.                         }).on( 'heartbeat-send.autosave', function( event, data ) {
  804.                                 var autosaveData = save();
  805.  
  806.                                 if ( autosaveData ) {
  807.                                         data.wp_autosave = autosaveData;
  808.                                 }
  809.  
  810.                                 /**
  811.                                  * Triggers the autosave of the post with the autosave data on the autosave
  812.                                  * heartbeat.
  813.                                  *
  814.                                  * @since 3.9.0
  815.                                  *
  816.                                  * @return {void}
  817.                                  */
  818.                         }).on( 'heartbeat-tick.autosave', function( event, data ) {
  819.                                 if ( data.wp_autosave ) {
  820.                                         response( data.wp_autosave );
  821.                                 }
  822.                                 /**
  823.                                  * Disables buttons and throws a notice when the connection is lost.
  824.                                  *
  825.                                  * @since 3.9.0
  826.                                  *
  827.                                  * @return {void}
  828.                                  */
  829.                         }).on( 'heartbeat-connection-lost.autosave', function( event, error, status ) {
  830.  
  831.                                 // When connection is lost, keep user from submitting changes.
  832.                                 if ( 'timeout' === error || 603 === status ) {
  833.                                         var $notice = $('#lost-connection-notice');
  834.  
  835.                                         if ( ! wp.autosave.local.hasStorage ) {
  836.                                                 $notice.find('.hide-if-no-sessionstorage').hide();
  837.                                         }
  838.  
  839.                                         $notice.show();
  840.                                         disableButtons();
  841.                                 }
  842.  
  843.                                 /**
  844.                                  * Enables buttons when the connection is restored.
  845.                                  *
  846.                                  * @since 3.9.0
  847.                                  *
  848.                                  * @return {void}
  849.                                  */
  850.                         }).on( 'heartbeat-connection-restored.autosave', function() {
  851.                                 $('#lost-connection-notice').hide();
  852.                                 enableButtons();
  853.                         });
  854.  
  855.                         return {
  856.                                 tempBlockSave: tempBlockSave,
  857.                                 triggerSave: triggerSave,
  858.                                 postChanged: postChanged,
  859.                                 suspend: suspend,
  860.                                 resume: resume
  861.                         };
  862.                 }
  863.  
  864.                 /**
  865.                  * Sets the autosave time out.
  866.                  *
  867.                  * Wait for TinyMCE to initialize plus 1 second. for any external css to finish loading,
  868.                  * then save to the textarea before setting initialCompareString.
  869.                  * This avoids any insignificant differences between the initial textarea content and the content
  870.                  * extracted from the editor.
  871.                  *
  872.                  * @since 3.9.0
  873.                  *
  874.                  * @return {void}
  875.                  */
  876.                 $( function() {
  877.                         // Set the initial compare string in case TinyMCE is not used or not loaded first.
  878.                         setInitialCompare();
  879.                 }).on( 'tinymce-editor-init.autosave', function( event, editor ) {
  880.                         // Reset the initialCompare data after the TinyMCE instances have been initialized.
  881.                         if ( 'content' === editor.id || 'excerpt' === editor.id ) {
  882.                                 window.setTimeout( function() {
  883.                                         editor.save();
  884.                                         setInitialCompare();
  885.                                 }, 1000 );
  886.                         }
  887.                 });
  888.  
  889.                 return {
  890.                         getPostData: getPostData,
  891.                         getCompareString: getCompareString,
  892.                         disableButtons: disableButtons,
  893.                         enableButtons: enableButtons,
  894.                         local: autosaveLocal(),
  895.                         server: autosaveServer()
  896.                 };
  897.         }
  898.  
  899.         /** @namespace wp */
  900.         window.wp = window.wp || {};
  901.         window.wp.autosave = autosave();
  902.  
  903. }( jQuery, window ));

Raw Paste


Login or Register to edit or fork this paste. It's free.