-
Notifications
You must be signed in to change notification settings - Fork 4.3k
/
preview.js
121 lines (112 loc) · 3.52 KB
/
preview.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/**
* External dependencies
*/
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 { __ } from '@wordpress/i18n';
export default function Preview( { idBase, instance, isVisible } ) {
const [ isLoaded, setIsLoaded ] = useState( false );
// 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`;
}
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,
}
);
intersectionObserver.observe( iframe );
iframe.addEventListener( 'load', setHeight );
return () => {
intersectionObserver.disconnect();
iframe.removeEventListener( 'load', setHeight );
};
}
},
[ isLoaded ]
);
return (
<>
{ /*
While the iframe contents are loading, we move the iframe off-screen
and display a placeholder instead. This ensures that the user
doesn't see the iframe resize (which looks really janky). We have to
move the iframe off-screen instead of hiding it because web browsers
will not trigger onLoad if the iframe is hidden.
*/ }
{ isVisible && ! isLoaded && (
<Placeholder>
<Spinner />
</Placeholder>
) }
<div
className={ classnames(
'wp-block-legacy-widget__edit-preview',
{
'is-offscreen': ! isVisible || ! isLoaded,
}
) }
>
<Disabled>
{ /*
We use an iframe so that the widget has an opportunity to
load scripts and styles that it needs to run.
*/ }
<iframe
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,
},
} ) }
onLoad={ ( event ) => {
// To hide the scrollbars of the preview frame for some edge cases,
// such as negative margins in the Gallery Legacy Widget.
// It can't be scrolled anyway.
// TODO: Ideally, this should be fixed in core.
event.target.contentDocument.body.style.overflow =
'hidden';
setIsLoaded( true );
} }
height={ 100 }
/>
</Disabled>
</div>
</>
);
}