Skip to content

Commit

Permalink
[RNMobile] Embed block: Implement specific Embed preview (#33426)
Browse files Browse the repository at this point in the history
* Created an EmbedPreview component to house the caption.

* Disabled the placeholder mode temporarily until the linking is enabled.

* added the react-native-web-view package.

* linked react-native-web-view to ios

* integrated react-native-web-view with android

* initial integration of WebView into the embed-preview component.

* added project configurations for react-native-webview android

* Add sandbox component native version

* Use webview to preview embed block

* Update aspect ratio calculation in sandbox component

* Add native styles to sandbox component

* Open embed content in external browser

* Add comment to sandbox webview

* Update react-native-webview package to wp-fork

* Bump react-native-webview version

* Bump react-native-webview version

* Use provider url as base url for embed webview

* Add forceRender param to trySandbox

* Handle case of setting empty URL after preview

* Enable embed preview interaction when selected

* Add max allowed requests to embed preview

* Prevent navigation in embed preview on Android

* Recreate WebView in Android on orientation change

* Disable embed preview interaction

* Remove unused clientId prop from embed web version

* Enable inline preview only in dev mode

* Remove URL from embed block internal state

I noticed that for the mobile version we don't really need to keep the URL in the internal state, as we were only modifying it once it changed, and that's already being handled with the url block's attribute.

* Use memo in embed preview component

* Use memo in sandbox component

* Rename iframe html to content html and update logic

* Bump react-native-webview package

* Add comments to explain the postMessage function

* Remove onBlur prop from embed preview

* Add sandbox classnames

* Use url instead of provider url as key in sandbox component

* Stop passing scripts to sandbox component

* Add size style calculation to sandbox

* Prevent calling updateContentHtml on very render

* Reset sandbox size when device orientation changes

* Update pods in react-native-editor demo project

Co-authored-by: Joel Dean <jdeanjj1000@gmail.com>
  • Loading branch information
fluiddot and jd-alexander committed Aug 11, 2021
1 parent fce770a commit 8ff6687
Show file tree
Hide file tree
Showing 13 changed files with 396 additions and 31 deletions.
18 changes: 17 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 20 additions & 16 deletions packages/block-library/src/embed/edit.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ import EmbedPlaceholder from './embed-placeholder';
import EmbedPreview from './embed-preview';
import EmbedBottomSheet from './embed-bottom-sheet';

/**
* External dependencies
*/
import classnames from 'classnames';

/**
* WordPress dependencies
*/
Expand All @@ -28,7 +33,7 @@ import { View } from '@wordpress/primitives';

const EmbedEdit = ( props ) => {
const {
attributes: { providerNameSlug, responsive, url: attributesUrl },
attributes: { providerNameSlug, previewable, responsive, url },
attributes,
isSelected,
onReplace,
Expand All @@ -45,8 +50,6 @@ const EmbedEdit = ( props ) => {
const { icon, title } =
getEmbedInfoByProvider( providerNameSlug ) || defaultEmbedInfo;

const [ url, setURL ] = useState( attributesUrl );

const { wasBlockJustInserted } = useSelect(
( select ) => ( {
wasBlockJustInserted: select(
Expand All @@ -66,12 +69,12 @@ const EmbedEdit = ( props ) => {
isPreviewEmbedFallback,
isRequestingEmbedPreview,
} = select( coreStore );
if ( ! attributesUrl ) {
if ( ! url ) {
return { fetching: false, cannotEmbed: false };
}

const embedPreview = getEmbedPreview( attributesUrl );
const previewIsFallback = isPreviewEmbedFallback( attributesUrl );
const embedPreview = getEmbedPreview( url );
const previewIsFallback = isPreviewEmbedFallback( url );

// The external oEmbed provider does not exist. We got no type info and no html.
const badEmbedProvider =
Expand All @@ -89,16 +92,15 @@ const EmbedEdit = ( props ) => {
// if there is an `attributesUrl` set but there is no data in
// `embedPreview` which represents the response returned from the API.
const isFetching =
isRequestingEmbedPreview( attributesUrl ) ||
( attributesUrl && ! embedPreview );
isRequestingEmbedPreview( url ) || ( url && ! embedPreview );

return {
preview: validPreview ? embedPreview : undefined,
fetching: isFetching,
cannotEmbed: ! validPreview || previewIsFallback,
};
},
[ attributesUrl ]
[ url ]
);

/**
Expand All @@ -124,11 +126,10 @@ const EmbedEdit = ( props ) => {
}
// At this stage, we're not fetching the preview and know it can't be embedded,
// so try removing any trailing slash, and resubmit.
const newURL = attributesUrl.replace( /\/$/, '' );
setURL( newURL );
const newURL = url.replace( /\/$/, '' );
setIsEditingURL( false );
setAttributes( { url: newURL } );
}, [ preview?.html, attributesUrl ] );
}, [ preview?.html, url ] );

// Handle incoming preview
useEffect( () => {
Expand Down Expand Up @@ -166,6 +167,8 @@ const EmbedEdit = ( props ) => {
}

const showEmbedPlaceholder = ! preview || cannotEmbed;
const { type, className: classFromPreview } = getMergedAttributes();
const className = classnames( classFromPreview, props.className );

return (
<>
Expand All @@ -190,11 +193,16 @@ const EmbedEdit = ( props ) => {
/>
<View { ...blockProps }>
<EmbedPreview
className={ className }
clientId={ clientId }
icon={ icon }
insertBlocksAfter={ insertBlocksAfter }
isSelected={ isSelected }
label={ title }
onFocus={ onFocus }
preview={ preview }
previewable={ previewable }
type={ type }
url={ url }
/>
</View>
Expand All @@ -205,10 +213,6 @@ const EmbedEdit = ( props ) => {
isVisible={ isEditingURL }
onClose={ () => setIsEditingURL( false ) }
onSubmit={ ( value ) => {
// On native, the URL change is only notified when submitting,
// and not via 'onChange', so we have to explicitly set the URL.
setURL( value );

setIsEditingURL( false );
setAttributes( { url: value } );
} }
Expand Down
77 changes: 67 additions & 10 deletions packages/block-library/src/embed/embed-preview.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
import { TouchableWithoutFeedback } from 'react-native';
import { isEmpty } from 'lodash';
import classnames from 'classnames/dedupe';

/**
* WordPress dependencies
Expand All @@ -11,21 +12,27 @@ import { View } from '@wordpress/primitives';

import { BlockCaption } from '@wordpress/block-editor';
import { __, sprintf } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
import { memo, useState } from '@wordpress/element';
import { SandBox } from '@wordpress/components';

/**
* Internal dependencies
*/
import { getPhotoHtml } from './util';
import EmbedNoPreview from './embed-no-preview';

const EmbedPreview = ( {
className,
clientId,
icon,
insertBlocksAfter,
isSelected,
label,
onBlur,
onFocus,
preview,
previewable,
type,
url,
} ) => {
const [ isCaptionSelected, setIsCaptionSelected ] = useState( false );

Expand Down Expand Up @@ -53,31 +60,81 @@ const EmbedPreview = ( {
}
}

const { provider_url: providerUrl } = preview;
const html = 'photo' === type ? getPhotoHtml( preview ) : preview.html;
const parsedHost = new URL( url ).host.split( '.' );
const parsedHostBaseUrl = parsedHost
.splice( parsedHost.length - 2, parsedHost.length - 1 )
.join( '.' );
const iframeTitle = sprintf(
// translators: %s: host providing embed content e.g: www.youtube.com
__( 'Embedded content from %s' ),
parsedHostBaseUrl
);
const sandboxClassnames = classnames(
type,
className,
'wp-block-embed__wrapper'
);

const embedWrapper =
/* We should render here: <WpEmbedPreview html={ html } /> */
'wp-embed' === type ? null : (
<>
<TouchableWithoutFeedback
onPress={ () => {
if ( onFocus ) {
onFocus();
}
if ( isCaptionSelected ) {
setIsCaptionSelected( false );
}
} }
>
<View pointerEvents="box-only">
<SandBox
html={ html }
title={ iframeTitle }
type={ sandboxClassnames }
providerUrl={ providerUrl }
url={ url }
/>
</View>
</TouchableWithoutFeedback>
</>
);

return (
<TouchableWithoutFeedback
accessible={ ! isSelected }
onPress={ onEmbedPreviewPress }
disabled={ ! isSelected }
>
<View>
<EmbedNoPreview
label={ label }
icon={ icon }
isSelected={ isSelected }
onPress={ () => setIsCaptionSelected( false ) }
/>
{
// eslint-disable-next-line no-undef
__DEV__ && previewable ? (
embedWrapper
) : (
<EmbedNoPreview
label={ label }
icon={ icon }
isSelected={ isSelected }
onPress={ () => setIsCaptionSelected( false ) }
/>
)
}
<BlockCaption
accessibilityLabelCreator={ accessibilityLabelCreator }
accessible
clientId={ clientId }
insertBlocksAfter={ insertBlocksAfter }
isSelected={ isCaptionSelected }
onBlur={ onBlur }
onFocus={ onFocusCaption }
/>
</View>
</TouchableWithoutFeedback>
);
};

export default EmbedPreview;
export default memo( EmbedPreview );
1 change: 1 addition & 0 deletions packages/components/src/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export { default as __experimentalText } from './text';
export { default as ExternalLink } from './external-link';
export { default as TextControl } from './text-control';
export { default as ToggleControl } from './toggle-control';
export { default as SandBox } from './sandbox';
export { default as SearchControl } from './search-control';
export { default as SelectControl } from './select-control';
export { default as RangeControl } from './range-control';
Expand Down
Loading

0 comments on commit 8ff6687

Please sign in to comment.