Skip to content

Commit

Permalink
Autosave drafts after debounce delay
Browse files Browse the repository at this point in the history
  • Loading branch information
aduth committed Jul 26, 2017
1 parent 511d6c1 commit 995f4cd
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 2 deletions.
23 changes: 23 additions & 0 deletions editor/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,29 @@ export function mergeBlocks( blockA, blockB ) {
};
}

/**
* Returns an action object used in signalling that the post should autosave.
*
* @return {Object} Action object
*/
export function autosave() {
return {
type: 'AUTOSAVE',
};
}

/**
* Returns an action object used in signalling that the post should be queued
* for autosave after a delay.
*
* @return {Object} Action object
*/
export function queueAutosave() {
return {
type: 'QUEUE_AUTOSAVE',
};
}

/**
* Returns an action object used in signalling that the blocks
* corresponding to the specified UID set are to be removed.
Expand Down
44 changes: 42 additions & 2 deletions editor/effects.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* External dependencies
*/
import { BEGIN, COMMIT, REVERT } from 'redux-optimist';
import { get, uniqueId } from 'lodash';
import { get, uniqueId, debounce } from 'lodash';

/**
* WordPress dependencies
Expand All @@ -14,12 +14,23 @@ import { __ } from 'i18n';
* Internal dependencies
*/
import { getGutenbergURL, getWPAdminURL } from './utils/url';
import { focusBlock, replaceBlocks, createSuccessNotice, createErrorNotice } from './actions';
import {
focusBlock,
replaceBlocks,
createSuccessNotice,
createErrorNotice,
autosave,
queueAutosave,
savePost,
} from './actions';
import {
getCurrentPost,
getCurrentPostType,
getBlocks,
getPostEdits,
isCurrentPostPublished,
isEditedPostDirty,
isEditedPostSaveable,
} from './selectors';

export default {
Expand Down Expand Up @@ -207,4 +218,33 @@ export default {
]
) );
},
AUTOSAVE( action, store ) {
const { getState } = store;
const state = getState();
if ( ! isEditedPostSaveable( state ) || ! isEditedPostDirty( state ) ) {
return;
}

if ( isCurrentPostPublished( state ) ) {
// TODO: Publish autosave.
// - Autosaves are created as revisions for published posts, but
// the necessary REST API behavior does not yet exist
// - May need to check for whether the status of the edited post
// has changed from the saved copy (i.e. published -> pending)
return;
}

return savePost();
},
QUEUE_AUTOSAVE: debounce( ( action, store ) => {
store.dispatch( autosave() );
}, 10000 ),
UPDATE_BLOCK_ATTRIBUTES: () => queueAutosave(),
INSERT_BLOCKS: () => queueAutosave(),
MOVE_BLOCKS_DOWN: () => queueAutosave(),
MOVE_BLOCKS_UP: () => queueAutosave(),
REPLACE_BLOCKS: () => queueAutosave(),
REMOVE_BLOCKS: () => queueAutosave(),
EDIT_POST: () => queueAutosave(),
MARK_DIRTY: () => queueAutosave(),
};
46 changes: 46 additions & 0 deletions editor/test/effects.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@ import { getBlockTypes, unregisterBlockType, registerBlockType, createBlock } fr
*/
import { mergeBlocks, focusBlock, replaceBlocks } from '../actions';
import effects from '../effects';
import * as selectors from '../selectors';

jest.mock( '../selectors' );

describe( 'effects', () => {
const defaultBlockSettings = { save: noop };

beforeEach( () => jest.resetAllMocks() );

describe( '.MERGE_BLOCKS', () => {
const handler = effects.MERGE_BLOCKS;

Expand Down Expand Up @@ -145,4 +150,45 @@ describe( 'effects', () => {
} ] ) );
} );
} );

describe( '.AUTOSAVE', () => {
const handler = effects.AUTOSAVE;
const store = { getState: () => {} };

it( 'should do nothing for unsaveable', () => {
selectors.isEditedPostSaveable.mockReturnValue( false );
selectors.isEditedPostDirty.mockReturnValue( true );
selectors.isCurrentPostPublished.mockReturnValue( false );

expect( handler( {}, store ) ).toBeUndefined();
} );

it( 'should do nothing for clean', () => {
selectors.isEditedPostSaveable.mockReturnValue( true );
selectors.isEditedPostDirty.mockReturnValue( false );
selectors.isCurrentPostPublished.mockReturnValue( false );

expect( handler( {}, store ) ).toBeUndefined();
} );

it( 'should return autosave action for saveable, dirty, published post', () => {
selectors.isEditedPostSaveable.mockReturnValue( true );
selectors.isEditedPostDirty.mockReturnValue( true );
selectors.isCurrentPostPublished.mockReturnValue( true );

expect( handler( {}, store ) ).toBeUndefined();
// TODO: Publish autosave
// expect( handler( {}, store ) ).toEqual( { } );
} );

it( 'should return update action for saveable, dirty draft', () => {
selectors.isEditedPostSaveable.mockReturnValue( true );
selectors.isEditedPostDirty.mockReturnValue( true );
selectors.isCurrentPostPublished.mockReturnValue( false );

expect( handler( {}, store ) ).toEqual( {
type: 'REQUEST_POST_UPDATE',
} );
} );
} );
} );

0 comments on commit 995f4cd

Please sign in to comment.