Skip to content

Commit

Permalink
Preview: Open preview to previewLink if not autosaveable
Browse files Browse the repository at this point in the history
  • Loading branch information
aduth committed Jul 5, 2018
1 parent dd6d2c2 commit f757da6
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 138 deletions.
57 changes: 36 additions & 21 deletions editor/components/post-preview-button/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class PostPreviewButton extends Component {
constructor() {
super( ...arguments );

this.saveForPreview = this.saveForPreview.bind( this );
this.openPreviewWindow = this.openPreviewWindow.bind( this );
}

componentDidUpdate( prevProps ) {
Expand All @@ -25,7 +25,7 @@ export class PostPreviewButton extends Component {
// This relies on the window being responsible to unset itself when
// navigation occurs or a new preview window is opened, to avoid
// unintentional forceful redirects.
if ( previewLink && previewLink !== prevProps.previewLink ) {
if ( previewLink && ! prevProps.previewLink ) {
this.setPreviewWindowLink( previewLink );
}
}
Expand All @@ -38,48 +38,65 @@ export class PostPreviewButton extends Component {
*/
setPreviewWindowLink( url ) {
const { previewWindow } = this;
if ( ! previewWindow || previewWindow.location.href === url ) {
return;
if ( previewWindow ) {
previewWindow.location = url;
}

previewWindow.location = url;
}

getWindowTarget() {
const { postId } = this.props;
return `wp-preview-${ postId }`;
}

saveForPreview( event ) {
const { isDirty, isNew } = this.props;
/**
* Handles a click event to open a popup window and prevent default click
* behavior if the post is either autosaveable or has a previously assigned
* preview link to be shown in the popup window target. Triggers autosave
* if post is autosaveable.
*
* @param {MouseEvent} event Click event from preview button click.
*/
openPreviewWindow( event ) {
const { isAutosaveable, previewLink } = this.props;

// Let default link behavior occur if no changes to saved post
if ( ! isDirty && ! isNew ) {
// If there are no changes to autosave, we cannot perform the save, but
// if there is an existing preview link (e.g. previous published post
// autosave), it should be reused as the popup destination.
if ( ! isAutosaveable && ! previewLink ) {
return;
}

// Save post prior to opening window
this.props.autosave();

// Open a popup, BUT: Set it to a blank page until save completes. This
// is necessary because popups can only be opened in response to user
// interaction (click), but we must still wait for the post to save.
event.preventDefault();
this.previewWindow = window.open(
'about:blank',
isAutosaveable ? 'about:blank' : previewLink,
this.getWindowTarget()
);

// When popup is closed or redirected by setPreviewWindowLink, delete
// reference to avoid later assignment of location in a post update.
this.previewWindow.onbeforeunload = () => {
delete this.previewWindow;
};

if ( ! isAutosaveable ) {
return;
}

this.props.autosave();

const markup = `
<div>
<div class="editor-post-preview-button__interstitial-message">
<p>Please wait&hellip;</p>
<p>Generating preview.</p>
</div>
<style>
body {
margin: 0;
}
div {
.editor-post-preview-button__interstitial-message {
display: flex;
flex-direction: column;
align-items: center;
Expand All @@ -95,10 +112,6 @@ export class PostPreviewButton extends Component {

this.previewWindow.document.write( markup );
this.previewWindow.document.close();

// When popup is closed or redirected by setPreviewWindowLink, delete
// reference to avoid later assignment of location in a post update.
this.previewWindow.onbeforeunload = () => delete this.previewWindow;
}

render() {
Expand All @@ -109,7 +122,7 @@ export class PostPreviewButton extends Component {
className="editor-post-preview"
isLarge
href={ currentPostLink }
onClick={ this.saveForPreview }
onClick={ this.openPreviewWindow }
target={ this.getWindowTarget() }
disabled={ ! isSaveable }
>
Expand All @@ -132,6 +145,7 @@ export default compose( [
isEditedPostDirty,
isEditedPostNew,
isEditedPostSaveable,
isEditedPostAutosaveable,
} = select( 'core/editor' );
const {
getPostType,
Expand All @@ -144,6 +158,7 @@ export default compose( [
isDirty: isEditedPostDirty(),
isNew: isEditedPostNew(),
isSaveable: isEditedPostSaveable(),
isAutosaveable: isEditedPostAutosaveable(),
isViewable: get( postType, [ 'viewable' ], false ),
};
} ),
Expand Down
87 changes: 38 additions & 49 deletions editor/components/post-preview-button/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,6 @@ describe( 'PostPreviewButton', () => {
expect( setter ).not.toHaveBeenCalled();
} );

it( 'should do nothing if the preview window is already at url location', () => {
const url = 'https://wordpress.org';
const setter = jest.fn();
const wrapper = shallow( <PostPreviewButton /> );
wrapper.instance().previewWindow = {
get location() {
return {
href: url,
};
},
set location( value ) {
setter( value );
},
};

wrapper.instance().setPreviewWindowLink( url );

expect( setter ).not.toHaveBeenCalled();
} );

it( 'set preview window location to url', () => {
const url = 'https://wordpress.org';
const setter = jest.fn();
Expand Down Expand Up @@ -90,8 +70,8 @@ describe( 'PostPreviewButton', () => {
} );
} );

describe( 'saveForPreview()', () => {
function assertForSave( props, isExpectingSave ) {
describe( 'openPreviewWindow()', () => {
function assertForPreview( props, expectedPreviewURL, isExpectingSave ) {
const autosave = jest.fn();
const preventDefault = jest.fn();
const windowOpen = window.open;
Expand All @@ -105,50 +85,59 @@ describe( 'PostPreviewButton', () => {
} );

const wrapper = shallow(
<PostPreviewButton { ...props } autosave={ autosave } />
<PostPreviewButton
postId={ 1 }
{ ...props }
autosave={ autosave }
/>
);

wrapper.simulate( 'click', { preventDefault } );

if ( isExpectingSave ) {
expect( autosave ).toHaveBeenCalled();
if ( expectedPreviewURL ) {
expect( preventDefault ).toHaveBeenCalled();
expect( window.open ).toHaveBeenCalled();
expect( wrapper.instance().previewWindow.document.write ).toHaveBeenCalled();
expect( window.open ).toHaveBeenCalledWith( expectedPreviewURL, 'wp-preview-1' );
} else {
expect( autosave ).not.toHaveBeenCalled();
expect( preventDefault ).not.toHaveBeenCalled();
expect( window.open ).not.toHaveBeenCalled();
}

window.open = windowOpen;

expect( autosave.mock.calls ).toHaveLength( isExpectingSave ? 1 : 0 );
if ( isExpectingSave ) {
expect( wrapper.instance().previewWindow.document.write ).toHaveBeenCalled();
}

return wrapper;
}

it( 'should do nothing if not dirty for saved post', () => {
assertForSave( {
postId: 1,
isNew: false,
isDirty: false,
isSaveable: true,
}, false );
it( 'should do nothing if neither autosaveable nor preview link available', () => {
assertForPreview( {
isAutosaveable: false,
previewLink: undefined,
}, null, false );
} );

it( 'should save if not dirty for new post', () => {
assertForSave( {
postId: 1,
isNew: true,
isDirty: false,
isSaveable: true,
}, true );
it( 'should save for autosaveable post with preview link', () => {
assertForPreview( {
isAutosaveable: true,
previewLink: 'https://wordpress.org/?p=1&preview=true',
}, 'https://wordpress.org/?p=1&preview=true', true );
} );

it( 'should open a popup window', () => {
assertForSave( {
postId: 1,
isNew: true,
isDirty: true,
isSaveable: true,
}, true );
it( 'should save for autosaveable post without preview link', () => {
assertForPreview( {
isAutosaveable: true,
previewLink: undefined,
}, 'about:blank', true );
} );

it( 'should not save but open a popup window if not autosaveable but preview link available', () => {
assertForPreview( {
isAutosaveable: false,
previewLink: 'https://wordpress.org/?p=1&preview=true',
}, 'https://wordpress.org/?p=1&preview=true', false );
} );
} );

Expand Down
Loading

0 comments on commit f757da6

Please sign in to comment.