EmbedModal: abstract embed code to new SafeEmbed component

This commit is contained in:
Alex Gleason 2022-08-21 12:22:06 -04:00
parent 33e13aa6e2
commit 0dd0742752
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
2 changed files with 60 additions and 27 deletions

View File

@ -0,0 +1,49 @@
import React, { useEffect, useRef } from 'react';
interface ISafeEmbed {
/** Styles for the outer frame element. */
className?: string,
/** Space-separate list of restrictions to ALLOW for the iframe. */
sandbox?: string,
/** Unique title for the iframe. */
title: string,
/** HTML body to embed. */
html?: string,
}
/** Safely embeds arbitrary HTML content on the page (by putting it in an iframe). */
const SafeEmbed: React.FC<ISafeEmbed> = ({
className,
sandbox,
title,
html,
}) => {
const iframe = useRef<HTMLIFrameElement>(null);
useEffect(() => {
const iframeDocument = iframe.current?.contentWindow?.document;
if (iframeDocument && html) {
iframeDocument.open();
iframeDocument.write(html);
iframeDocument.close();
iframeDocument.body.style.margin = '0';
const innerFrame = iframeDocument.querySelector('iframe');
if (innerFrame) {
innerFrame.width = '100%';
}
}
}, [iframe.current, html]);
return (
<iframe
ref={iframe}
className={className}
sandbox={sandbox}
title={title}
/>
);
};
export default SafeEmbed;

View File

@ -1,7 +1,8 @@
import React, { useState, useEffect, useRef } from 'react';
import React, { useState, useEffect } from 'react';
import { FormattedMessage } from 'react-intl';
import api from 'soapbox/api';
import SafeEmbed from 'soapbox/components/safe-embed';
import { Modal, Stack, Text, Input } from 'soapbox/components/ui';
import { useAppDispatch } from 'soapbox/hooks';
@ -20,33 +21,17 @@ interface IEmbedModal {
const EmbedModal: React.FC<IEmbedModal> = ({ url, onError }) => {
const dispatch = useAppDispatch();
const iframe = useRef<HTMLIFrameElement>(null);
const [oembed, setOembed] = useState<any>(null);
const [html, setHtml] = useState('');
useEffect(() => {
dispatch(fetchEmbed(url)).then(({ data }) => {
if (!iframe.current?.contentWindow) return;
setOembed(data);
const iframeDocument = iframe.current.contentWindow.document;
iframeDocument.open();
iframeDocument.write(data.html);
iframeDocument.close();
const innerFrame = iframeDocument.querySelector('iframe');
iframeDocument.body.style.margin = '0';
if (innerFrame) {
innerFrame.width = '100%';
if (data?.html) {
setHtml(data.html);
}
}).catch(error => {
onError(error);
});
}, [!!iframe.current]);
}, []);
const handleInputClick: React.MouseEventHandler<HTMLInputElement> = (e) => {
e.currentTarget.select();
@ -63,21 +48,20 @@ const EmbedModal: React.FC<IEmbedModal> = ({ url, onError }) => {
<Input
type='text'
readOnly
value={oembed?.html || ''}
value={html}
onClick={handleInputClick}
/>
</Stack>
<iframe
<SafeEmbed
className='inline-flex rounded-xl overflow-hidden max-w-full'
frameBorder='0'
ref={iframe}
sandbox='allow-same-origin'
title='preview'
title='embedded-status'
html={html}
/>
</Stack>
</Modal>
);
};
export default EmbedModal;
export default EmbedModal;