Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
113 changes: 61 additions & 52 deletions packages/block-library/src/embed/edit.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,30 @@
/**
* External dependencies
*/
import clsx from 'clsx';

/**
* WordPress dependencies
*/
import { __, _x, sprintf } from '@wordpress/i18n';
import { useState, useEffect } from '@wordpress/element';
import { useDispatch, useSelect } from '@wordpress/data';
import {
useBlockProps,
store as blockEditorStore,
} from '@wordpress/block-editor';
import { store as coreStore } from '@wordpress/core-data';
import { View } from '@wordpress/primitives';
import { Caption } from '../utils/caption';

/**
* Internal dependencies
*/
import {
createUpgradedEmbedBlock,
findMoreSuitableBlock,
getClassNames,
rewriteXToTwitter,
removeAspectRatioClasses,
fallback,
getEmbedInfoByProvider,
Expand All @@ -15,23 +36,6 @@ import EmbedLoading from './embed-loading';
import EmbedPlaceholder from './embed-placeholder';
import EmbedPreview from './embed-preview';

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

/**
* WordPress dependencies
*/
import { __, _x, sprintf } from '@wordpress/i18n';
import { useState, useEffect } from '@wordpress/element';
import { useDispatch, useSelect } from '@wordpress/data';
import { useBlockProps } from '@wordpress/block-editor';
import { store as coreStore } from '@wordpress/core-data';
import { View } from '@wordpress/primitives';
import { getAuthority } from '@wordpress/url';
import { Caption } from '../utils/caption';

const EmbedEdit = ( props ) => {
const {
attributes: {
Expand All @@ -58,6 +62,8 @@ const EmbedEdit = ( props ) => {
const [ url, setURL ] = useState( attributesUrl );
const [ isEditingURL, setIsEditingURL ] = useState( false );
const { invalidateResolution } = useDispatch( coreStore );
const { __unstableMarkNextChangeAsNotPersistent } =
useDispatch( blockEditorStore );

const {
preview,
Expand Down Expand Up @@ -131,63 +137,61 @@ const EmbedEdit = ( props ) => {
} );
}

// When the preview can't be embedded, retry without any trailing slash.
useEffect( () => {
if ( preview?.html || ! cannotEmbed || ! hasResolved ) {
if ( ! cannotEmbed || ! hasResolved || ! attributesUrl ) {
return;
}

// 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( /\/$/, '' );
if ( newURL === attributesUrl ) {
return;
}

setURL( newURL );
setIsEditingURL( false );
__unstableMarkNextChangeAsNotPersistent();
setAttributes( { url: newURL } );
}, [
preview?.html,
attributesUrl,
cannotEmbed,
hasResolved,
setAttributes,
__unstableMarkNextChangeAsNotPersistent,
] );

// Try a different provider in case the embed url is not supported.
// Apply preview-derived attributes once the preview resolves.
useEffect( () => {
if ( ! cannotEmbed || fetching || ! url ) {
if ( ! preview || isEditingURL ) {
return;
}

// Until X provider is supported in WordPress, as a workaround we use Twitter provider.
if ( getAuthority( url ) === 'x.com' ) {
const newURL = new URL( url );
newURL.host = 'twitter.com';
setAttributes( { url: newURL.toString() } );
}
}, [ url, cannotEmbed, fetching, setAttributes ] );
const mergedAttributes = getMergedAttributes();

// Handle incoming preview.
useEffect( () => {
if ( preview && ! isEditingURL ) {
// When obtaining an incoming preview,
// we set the attributes derived from the preview data.
const mergedAttributes = getMergedAttributes();
const hasChanges = Object.keys( mergedAttributes ).some(
( key ) => mergedAttributes[ key ] !== attributes[ key ]
if ( onReplace ) {
const upgradedBlock = createUpgradedEmbedBlock(
props,
mergedAttributes
);

if ( hasChanges ) {
setAttributes( mergedAttributes );
if ( upgradedBlock ) {
// Mutate via setAttributes; onReplace would remount the
// block and clear the URL textbox on undo.
__unstableMarkNextChangeAsNotPersistent();
setAttributes( upgradedBlock.attributes );
return;
}
}

if ( onReplace ) {
const upgradedBlock = createUpgradedEmbedBlock(
props,
mergedAttributes
);
const hasChanges = Object.keys( mergedAttributes ).some(
( key ) => mergedAttributes[ key ] !== attributes[ key ]
);

if ( upgradedBlock ) {
onReplace( upgradedBlock );
}
}
if ( hasChanges ) {
// Merge into the URL-submit undo level so a single undo
// reverts both the submit and the preview-driven attributes.
__unstableMarkNextChangeAsNotPersistent();
setAttributes( mergedAttributes );
}
}, [ preview, isEditingURL ] );

Expand Down Expand Up @@ -219,14 +223,19 @@ const EmbedEdit = ( props ) => {
event.preventDefault();
}

// If the embed URL was changed, we need to reset the aspect ratio class.
// To do this we have to remove the existing ratio class so it can be recalculated.
const rewrittenURL = rewriteXToTwitter( url );
const blockClass = removeAspectRatioClasses(
attributes.className
);

setURL( rewrittenURL );
setAttributes( {
url: rewrittenURL,
...findMoreSuitableBlock( rewrittenURL )
?.attributes,
className: blockClass,
} );
setIsEditingURL( false );
setAttributes( { url, className: blockClass } );
} }
value={ url }
cannotEmbed={ cannotEmbed }
Expand Down
128 changes: 71 additions & 57 deletions packages/block-library/src/embed/edit.native.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,3 @@
/**
* Internal dependencies
*/
import {
createUpgradedEmbedBlock,
getClassNames,
removeAspectRatioClasses,
fallback,
getEmbedInfoByProvider,
getMergedAttributesWithPreview,
} from './util';
import EmbedControls from './embed-controls';
import { embedContentIcon } from './icons';
import EmbedLoading from './embed-loading';
import EmbedPlaceholder from './embed-placeholder';
import EmbedPreview from './embed-preview';
import EmbedLinkSettings from './embed-link-settings';

/**
* External dependencies
*/
Expand All @@ -33,7 +15,25 @@ import {
} from '@wordpress/block-editor';
import { store as coreStore } from '@wordpress/core-data';
import { View } from '@wordpress/primitives';
import { getAuthority } from '@wordpress/url';
/**
* Internal dependencies
*/
import {
createUpgradedEmbedBlock,
findMoreSuitableBlock,
getClassNames,
rewriteXToTwitter,
removeAspectRatioClasses,
fallback,
getEmbedInfoByProvider,
getMergedAttributesWithPreview,
} from './util';
import EmbedControls from './embed-controls';
import { embedContentIcon } from './icons';
import EmbedLoading from './embed-loading';
import EmbedPlaceholder from './embed-placeholder';
import EmbedPreview from './embed-preview';
import EmbedLinkSettings from './embed-link-settings';

// The inline preview feature will be released progressible, for this reason
// the embed will only be considered previewable for the following providers list.
Expand Down Expand Up @@ -77,6 +77,8 @@ const EmbedEdit = ( props ) => {
const [ showEmbedBottomSheet, setShowEmbedBottomSheet ] =
useState( isEditingURL );
const { invalidateResolution } = useDispatch( coreStore );
const { __unstableMarkNextChangeAsNotPersistent } =
useDispatch( blockEditorStore );

const { preview, fetching, themeSupportsResponsive, cannotEmbed } =
useSelect(
Expand Down Expand Up @@ -150,50 +152,61 @@ const EmbedEdit = ( props ) => {
} );
};

// When the preview can't be embedded, retry without any trailing slash.
useEffect( () => {
if ( ! preview?.html || ! cannotEmbed || fetching ) {
if ( ! cannotEmbed || fetching || ! url ) {
return;
}
// 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 = url.replace( /\/$/, '' );
if ( newURL === url ) {
return;
}

setIsEditingURL( false );
__unstableMarkNextChangeAsNotPersistent();
setAttributes( { url: newURL } );
}, [ preview?.html, url, cannotEmbed, fetching ] );
}, [
url,
cannotEmbed,
fetching,
setAttributes,
__unstableMarkNextChangeAsNotPersistent,
] );

// Try a different provider in case the embed url is not supported.
// Apply preview-derived attributes once the preview resolves.
useEffect( () => {
if ( ! cannotEmbed || fetching || ! url ) {
if ( ! preview || isEditingURL ) {
return;
}

// Until X provider is supported in WordPress, as a workaround we use Twitter provider.
if ( getAuthority( url ) === 'x.com' ) {
const newURL = new URL( url );
newURL.host = 'twitter.com';
setAttributes( { url: newURL.toString() } );
}
}, [ url, cannotEmbed, fetching, setAttributes ] );
const mergedAttributes = getMergedAttributes();

// Handle incoming preview.
useEffect( () => {
if ( preview && ! isEditingURL ) {
// When obtaining an incoming preview,
// we set the attributes derived from the preview data.
const mergedAttributes = getMergedAttributes();
setAttributes( mergedAttributes );
if ( onReplace ) {
const upgradedBlock = createUpgradedEmbedBlock(
props,
mergedAttributes
);

if ( onReplace ) {
const upgradedBlock = createUpgradedEmbedBlock(
props,
mergedAttributes
);

if ( upgradedBlock ) {
onReplace( upgradedBlock );
}
if ( upgradedBlock ) {
// Mutate via setAttributes; onReplace would remount the
// block and clear the URL textbox on undo.
__unstableMarkNextChangeAsNotPersistent();
setAttributes( upgradedBlock.attributes );
return;
}
}

const hasChanges = Object.keys( mergedAttributes ).some(
( key ) => mergedAttributes[ key ] !== attributes[ key ]
);

if ( hasChanges ) {
// Merge into the URL-submit undo level so a single undo
// reverts both the submit and the preview-driven attributes.
__unstableMarkNextChangeAsNotPersistent();
setAttributes( mergedAttributes );
}
}, [ preview, isEditingURL ] );

useEffect(
Expand All @@ -203,19 +216,20 @@ const EmbedEdit = ( props ) => {

const onEditURL = useCallback(
( value ) => {
// If the embed URL was changed, we need to reset the aspect ratio class.
// To do this we have to remove the existing ratio class so it can be recalculated.
if ( attributes.url !== value ) {
const blockClass = removeAspectRatioClasses(
attributes.className
);
setAttributes( { className: blockClass } );
}
const rewrittenURL = rewriteXToTwitter( value );
const urlChanged = attributes.url !== rewrittenURL;

// The order of the following calls is important, we need to update the URL attribute before changing `isEditingURL`,
// otherwise the side-effect that potentially replaces the block when updating the local state won't use the new URL
// for creating the new block.
setAttributes( { url: value } );
setAttributes( {
url: rewrittenURL,
...findMoreSuitableBlock( rewrittenURL )?.attributes,
// If the embed URL was changed, reset the aspect ratio class so it can be recalculated.
...( urlChanged && {
className: removeAspectRatioClasses( attributes.className ),
} ),
} );
setIsEditingURL( false );
},
[ attributes, setAttributes ]
Expand Down
10 changes: 8 additions & 2 deletions packages/block-library/src/embed/transforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import { createBlock } from '@wordpress/blocks';
* Internal dependencies
*/
import metadata from './block.json';
import { removeAspectRatioClasses } from './util';
import {
findMoreSuitableBlock,
rewriteXToTwitter,
removeAspectRatioClasses,
} from './util';

const { name: EMBED_BLOCK } = metadata;

Expand All @@ -23,8 +27,10 @@ const transforms = {
/^\s*(https?:\/\/\S+)\s*$/i.test( node.textContent ) &&
node.textContent?.match( /https/gi )?.length === 1,
transform: ( node ) => {
const url = rewriteXToTwitter( node.textContent.trim() );
return createBlock( EMBED_BLOCK, {
url: node.textContent.trim(),
url,
...findMoreSuitableBlock( url )?.attributes,
} );
},
},
Expand Down
Loading
Loading