Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Legacy widget's preview functionality is broken when the page is moved #34384

Merged
merged 23 commits into from
Aug 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b138bfe
Load preview using the new REST API endpoint.
anton-vlasenko Aug 19, 2021
a646738
1. Use previewLoaded instead of srcdoc attribute to check if the prev…
anton-vlasenko Aug 19, 2021
25e7310
1. Rename renderPreview function (code review feedback).
anton-vlasenko Aug 20, 2021
7f3b4a1
Fix bug related to isPreviewFetched state.
anton-vlasenko Aug 20, 2021
710924a
Don't call fetchPreviewHTML with arguments because we use closures now.
anton-vlasenko Aug 20, 2021
988afae
useEffect should always return a cleanup function.
anton-vlasenko Aug 20, 2021
9b5b66a
Don't call useEffect on each component rerender.
anton-vlasenko Aug 20, 2021
7129e21
1. Use an optional chaining operator instead of typeof to improve rea…
anton-vlasenko Aug 23, 2021
e159cdb
1. Don't use a custom message as it increases the bundle size and the…
anton-vlasenko Aug 24, 2021
351ad12
An attempt to fix the failing test.
anton-vlasenko Aug 24, 2021
a51602f
2nd attempt to fix the failing test.
anton-vlasenko Aug 24, 2021
7c63c4a
3rd attempt to fix the failing test.
anton-vlasenko Aug 24, 2021
8772bf4
4rd attempt to fix the failing test.
anton-vlasenko Aug 24, 2021
123c0af
5th attempt to fix the failing test.
anton-vlasenko Aug 24, 2021
7c8f6c5
A small change to trigger CI checks.
anton-vlasenko Aug 24, 2021
864d41b
Remove irrelevant comment.
anton-vlasenko Aug 25, 2021
dbf2cb4
Change REST API endpoint url because it was changed in https://github…
anton-vlasenko Aug 25, 2021
cf65b1a
1. Fix parameter names (we should use id and instance parameters).
anton-vlasenko Aug 25, 2021
3930f67
1. Fix parameter names (we should use id and instance parameters).
anton-vlasenko Aug 25, 2021
b360549
1. Revert endpoint and use /render again (because it was changed in t…
anton-vlasenko Aug 26, 2021
6be25ae
Fix request parameters.
anton-vlasenko Aug 26, 2021
145a379
Get rid of the id_base parameter.
anton-vlasenko Aug 30, 2021
8b1507f
Don't send request parameters if the instance is empty.
anton-vlasenko Aug 30, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions packages/e2e-tests/specs/widgets/editing-widgets.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -633,12 +633,14 @@ describe( 'Widgets screen', () => {

// Wait for the Legacy Widget block's preview iframe to load.
const frame = await new Promise( ( resolve ) => {
const checkFrame = async ( candidateFrame ) => {
const url = await candidateFrame.url();
if ( url.includes( 'legacy-widget-preview' ) ) {
const checkFrame = async () => {
const frameElement = await page.$(
'iframe.wp-block-legacy-widget__edit-preview-iframe'
);
if ( frameElement ) {
page.off( 'frameattached', checkFrame );
page.off( 'framenavigated', checkFrame );
resolve( candidateFrame );
resolve( frameElement.contentFrame() );
}
};
page.on( 'frameattached', checkFrame );
Expand Down
113 changes: 68 additions & 45 deletions packages/widgets/src/blocks/legacy-widget/edit/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,57 +7,88 @@ import classnames from 'classnames';
* WordPress dependencies
*/
import { useRefEffect } from '@wordpress/compose';
import { addQueryArgs } from '@wordpress/url';
import { useState } from '@wordpress/element';
import { Placeholder, Spinner, Disabled } from '@wordpress/components';
import { useEffect, useState } from '@wordpress/element';
import { Disabled, Placeholder, Spinner } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import apiFetch from '@wordpress/api-fetch';

export default function Preview( { idBase, instance, isVisible } ) {
const [ isLoaded, setIsLoaded ] = useState( false );
const [ srcDoc, setSrcDoc ] = useState( '' );

useEffect( () => {
const abortController =
typeof window.AbortController === 'undefined'
? undefined
: new window.AbortController();

async function fetchPreviewHTML() {
const restRoute = `/wp/v2/widget-types/${ idBase }/render`;
return await apiFetch( {
path: restRoute,
method: 'POST',
signal: abortController?.signal,
data: instance ? { instance } : {},
} );
}

fetchPreviewHTML()
.then( ( response ) => {
setSrcDoc( response.preview );
} )
.catch( ( error ) => {
if ( 'AbortError' === error.name ) {
// We don't want to log aborted requests.
return;
}
throw error;
} );

return () => abortController?.abort();
}, [ idBase, instance ] );

// Resize the iframe on either the load event, or when the iframe becomes visible.
const ref = useRefEffect(
( iframe ) => {
// Only set height if the iframe is loaded,
// or it will grow to an unexpected large height in Safari if it's hidden initially.
if ( isLoaded ) {
// If the preview frame has another origin then this won't work.
// One possible solution is to add custom script to call `postMessage` in the preview frame.
// Or, better yet, we migrate away from iframe.
function setHeight() {
// Pick the maximum of these two values to account for margin collapsing.
const height = Math.max(
iframe.contentDocument.documentElement.offsetHeight,
iframe.contentDocument.body.offsetHeight
);
iframe.style.height = `${ height }px`;
}
if ( ! isLoaded ) {
return;
}
// If the preview frame has another origin then this won't work.
// One possible solution is to add custom script to call `postMessage` in the preview frame.
// Or, better yet, we migrate away from iframe.
function setHeight() {
// Pick the maximum of these two values to account for margin collapsing.
const height = Math.max(
iframe.contentDocument.documentElement.offsetHeight,
iframe.contentDocument.body.offsetHeight
);
iframe.style.height = `${ height }px`;
}

const {
IntersectionObserver,
} = iframe.ownerDocument.defaultView;
const { IntersectionObserver } = iframe.ownerDocument.defaultView;

// Observe for intersections that might cause a change in the height of
// the iframe, e.g. a Widget Area becoming expanded.
const intersectionObserver = new IntersectionObserver(
( [ entry ] ) => {
if ( entry.isIntersecting ) {
setHeight();
}
},
{
threshold: 1,
// Observe for intersections that might cause a change in the height of
// the iframe, e.g. a Widget Area becoming expanded.
const intersectionObserver = new IntersectionObserver(
( [ entry ] ) => {
if ( entry.isIntersecting ) {
setHeight();
}
);
intersectionObserver.observe( iframe );
},
{
threshold: 1,
}
);
intersectionObserver.observe( iframe );

iframe.addEventListener( 'load', setHeight );
iframe.addEventListener( 'load', setHeight );

return () => {
intersectionObserver.disconnect();
iframe.removeEventListener( 'load', setHeight );
};
}
return () => {
intersectionObserver.disconnect();
iframe.removeEventListener( 'load', setHeight );
};
},
[ isLoaded ]
);
Expand Down Expand Up @@ -93,15 +124,7 @@ export default function Preview( { idBase, instance, isVisible } ) {
ref={ ref }
className="wp-block-legacy-widget__edit-preview-iframe"
title={ __( 'Legacy Widget Preview' ) }
// TODO: This chokes when the query param is too big.
// Ideally, we'd render a <ServerSideRender>. Maybe by
// rendering one in an iframe via a portal.
src={ addQueryArgs( 'widgets.php', {
'legacy-widget-preview': {
idBase,
instance,
},
} ) }
srcDoc={ srcDoc }
onLoad={ ( event ) => {
// To hide the scrollbars of the preview frame for some edge cases,
// such as negative margins in the Gallery Legacy Widget.
Expand Down