Skip to content

Commit

Permalink
[amp-iframe] Wrap iframe in shadow DOM and ContainWrapper (#35774)
Browse files Browse the repository at this point in the history
  • Loading branch information
dmanek committed Aug 26, 2021
1 parent 8889d8c commit 0438e56
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 48 deletions.
10 changes: 1 addition & 9 deletions extensions/amp-iframe/1.0/amp-iframe.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,7 @@ class AmpIframe extends BaseElement {
);
return Promise.reject('Resize height is < 100px');
}

return this.attemptChangeSize(height, width).catch(() => {
if (!this.getOverflowElement?.()) {
console./* OK */ warn(
'[overflow] element not found. Provide one to enable resizing.',
this.element
);
}
});
return this.attemptChangeSize(height, width);
}

/** @override */
Expand Down
3 changes: 3 additions & 0 deletions extensions/amp-iframe/1.0/base-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ BaseElement['props'] = {

/** @override */
BaseElement['layoutSizeDefined'] = true;

/** @override */
BaseElement['usesShadowDom'] = true;
87 changes: 55 additions & 32 deletions extensions/amp-iframe/1.0/component.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import * as Preact from '#preact';
import {useCallback, useEffect, useRef} from '#preact';
import {useCallback, useEffect, useMemo, useRef} from '#preact';
import {MessageType} from '#core/3p-frame-messaging';
import {toWin} from '#core/window';
import {ContainWrapper} from '#preact/component';
import {setStyle} from '#core/dom/style';

const NOOP = () => {};
const FULL_HEIGHT = '100%';

/**
* @param {!IframeDef.Props} props
Expand All @@ -14,6 +15,7 @@ export function Iframe({
allowFullScreen,
allowPaymentRequest,
allowTransparency,
iframeStyle,
onLoad = NOOP,
referrerPolicy,
requestResize,
Expand All @@ -25,12 +27,19 @@ export function Iframe({
const iframeRef = useRef();
const dataRef = useRef(null);
const isIntersectingRef = useRef(null);
const containerRef = useRef(null);

const attemptResize = useCallback(() => {
const iframe = iframeRef.current;
if (!iframe) {
const updateContainerSize = (height, width) => {
const container = containerRef.current;
if (!container) {
return;
}
setStyle(container, 'width', width, 'px');
setStyle(container, 'height', height, 'px');
};

const attemptResize = useCallback(() => {
const iframe = iframeRef.current;
let height = Number(dataRef.current.height);
let width = Number(dataRef.current.width);
if (!height && !width) {
Expand All @@ -47,24 +56,16 @@ export function Iframe({
width = iframe./*OK*/ offsetWidth;
}
if (requestResize) {
// Currently `requestResize` is called twice:
// 1. when post message is received in viewport
// 2. when exiting viewport
// This could be optimized by reducing to one call by assessing when to call.
requestResize(height, width).then(() => {
iframe.height = FULL_HEIGHT;
iframe.width = FULL_HEIGHT;
});
// Currently `requestResize` is called twice when:
// 1. post message is received in viewport
// 2. exiting viewport
// This could be optimized by reducing to one call.
requestResize(height, width);
} else if (isIntersectingRef.current === false) {
// attemptResize can be called before the IntersectionObserver starts observing
// the component if an event is fired immediately. Therefore we check
// isIntersectingRef has changed via isIntersectingRef.current === false.
if (width) {
iframe.width = width;
}
if (height) {
iframe.height = height;
}
updateContainerSize(height, width);
}
}, [requestResize]);

Expand All @@ -84,7 +85,7 @@ export function Iframe({
if (!iframe) {
return;
}
const win = iframe && toWin(iframe.ownerDocument.defaultView);
const win = toWin(iframe.ownerDocument.defaultView);
if (!win) {
return;
}
Expand All @@ -105,19 +106,41 @@ export function Iframe({
};
}, [attemptResize, handlePostMessage]);

const contentProps = useMemo(
() => ({
src,
srcdoc,
sandbox,
allowFullScreen,
allowPaymentRequest,
allowTransparency,
referrerPolicy,
onLoad,
frameBorder: '0',
}),
[
src,
srcdoc,
sandbox,
allowFullScreen,
allowPaymentRequest,
allowTransparency,
referrerPolicy,
onLoad,
]
);

return (
<iframe
ref={iframeRef}
src={src}
srcdoc={srcdoc}
sandbox={sandbox}
allowfullscreen={allowFullScreen}
allowpaymentrequest={allowPaymentRequest}
allowtransparency={allowTransparency}
referrerpolicy={referrerPolicy}
onload={onLoad}
frameBorder="0"
<ContainWrapper
contentAs="iframe"
contentProps={contentProps}
contentRef={iframeRef}
contentStyle={{'box-sizing': 'border-box', ...iframeStyle}}
ref={containerRef}
size
layout
paint
{...rest}
></iframe>
/>
);
}
14 changes: 7 additions & 7 deletions extensions/amp-iframe/1.0/storybook/Basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ export default {
export const _default = () => {
return (
<Iframe
style={{width: 800, height: 600, borderWidth: 2}}
style={{width: 800, height: 600}}
iframeStyle={{border: '1px solid black'}}
src="https://www.wikipedia.org/"
title="Wikipedia"
></Iframe>
Expand All @@ -21,9 +22,8 @@ export const _default = () => {
export const WithIntersectingIframe = () => {
return (
<Iframe
style={{borderWidth: 2}}
width="100"
height="100"
style={{width: 100, height: 100}}
iframeStyle={{border: '1px solid black'}}
sandbox="allow-scripts allow-same-origin"
resizable
src="/examples/bento/amp-iframe-resizing-example.html"
Expand All @@ -44,15 +44,15 @@ export const WithResizableIframe = () => {
<div>
<h1>{textAbove}</h1>
<Iframe
style={{borderWidth: 2}}
width="100"
height="100"
style={{width: 100, height: 100}}
iframeStyle={{border: '1px solid black'}}
sandbox="allow-scripts allow-same-origin"
resizable
src="/examples/bento/amp-iframe-resizing-example.html"
>
<div placeholder>Placeholder</div>
</Iframe>
<p>The above iframe should resize to 300x300px when visible</p>
<h1>{textBelow}</h1>
</div>
);
Expand Down

0 comments on commit 0438e56

Please sign in to comment.