diff --git a/packages/block-editor/src/components/rich-text/use-paste-handler.js b/packages/block-editor/src/components/rich-text/use-paste-handler.js index eafaba19912f61..9f10932b86a9ef 100644 --- a/packages/block-editor/src/components/rich-text/use-paste-handler.js +++ b/packages/block-editor/src/components/rich-text/use-paste-handler.js @@ -8,9 +8,6 @@ import { pasteHandler, findTransform, getBlockTransforms, - htmlToBlocks, - hasBlockSupport, - getBlockContent, } from '@wordpress/blocks'; import { isEmpty, @@ -47,15 +44,6 @@ function adjustLines( value, isMultiline ) { return replace( value, new RegExp( LINE_SEPARATOR, 'g' ), '\n' ); } -function maybeInline( blocks, mode ) { - if ( mode !== 'AUTO' ) return blocks; - if ( blocks.length !== 1 ) return blocks; - const [ block ] = blocks; - if ( ! hasBlockSupport( block.name, '__unstablePasteTextInline', false ) ) - return blocks; - return getBlockContent( block ); -} - export function usePasteHandler( props ) { const propsRef = useRef( props ); propsRef.current = props; @@ -224,16 +212,17 @@ export function usePasteHandler( props ) { // If the data comes from a rich text instance, we can directly use it // without filtering the data. The filters are only meant for externally // pasted content and remove inline styles. - const isInternal = !! clipboardData.getData( 'rich-text' ); - const content = isInternal - ? maybeInline( htmlToBlocks( html ), mode ) - : pasteHandler( { - HTML: html, - plainText, - mode, - tagName, - preserveWhiteSpace, - } ); + const content = pasteHandler( { + HTML: html, + plainText, + mode, + tagName, + preserveWhiteSpace, + // If the data comes from a rich text instance, we can directly + // use it without filtering the data. The filters are only meant + // for externally pasted content and remove inline styles. + disableFilters: !! clipboardData.getData( 'rich-text' ), + } ); if ( typeof content === 'string' ) { let valueToInsert = create( { html: content } ); diff --git a/packages/blocks/README.md b/packages/blocks/README.md index de2500fc199d25..f05c4474f8be53 100644 --- a/packages/blocks/README.md +++ b/packages/blocks/README.md @@ -471,6 +471,7 @@ _Parameters_ - _options.mode_ `[string]`: Handle content as blocks or inline content. _ 'AUTO': Decide based on the content passed. _ 'INLINE': Always handle as inline content, and return string. \* 'BLOCKS': Always handle as blocks, and return array of blocks. - _options.tagName_ `[Array]`: The tag into which content will be inserted. - _options.preserveWhiteSpace_ `[boolean]`: Whether or not to preserve consequent white space. +- _options.disableFilters_ `[boolean]`: _Returns_ diff --git a/packages/blocks/src/api/raw-handling/paste-handler.js b/packages/blocks/src/api/raw-handling/paste-handler.js index c4ad40e0b1f509..97f3750a390365 100644 --- a/packages/blocks/src/api/raw-handling/paste-handler.js +++ b/packages/blocks/src/api/raw-handling/paste-handler.js @@ -8,7 +8,6 @@ import { getPhrasingContentSchema, removeInvalidHTML } from '@wordpress/dom'; */ import { htmlToBlocks } from './html-to-blocks'; import { hasBlockSupport } from '../registration'; -import { getBlockInnerHTML } from '../serializer'; import parse from '../parser'; import normaliseBlocks from './normalise-blocks'; import specialCommentConverter from './special-comment-converter'; @@ -66,6 +65,37 @@ function filterInlineHTML( HTML, preserveWhiteSpace ) { return HTML; } +/** + * If we're allowed to return inline content, and there is only one inlineable + * block, and the original plain text content does not have any line breaks, + * then treat it as inline paste. + * + * @param {Object} options + * @param {Array} options.blocks + * @param {string} options.plainText + * @param {string} options.mode + */ +function maybeConvertParagraphToInline( { blocks, plainText, mode } ) { + if ( + mode === 'AUTO' && + blocks.length === 1 && + hasBlockSupport( blocks[ 0 ].name, '__unstablePasteTextInline', false ) + ) { + const trimRegex = /^[\n]+|[\n]+$/g; + // Don't catch line breaks at the start or end. + const trimmedPlainText = plainText.replace( trimRegex, '' ); + + if ( + trimmedPlainText !== '' && + trimmedPlainText.indexOf( '\n' ) === -1 + ) { + return blocks[ 0 ].attributes.content; + } + } + + return blocks; +} + /** * Converts an HTML string to known blocks. Strips everything else. * @@ -79,6 +109,7 @@ function filterInlineHTML( HTML, preserveWhiteSpace ) { * @param {Array} [options.tagName] The tag into which content will be inserted. * @param {boolean} [options.preserveWhiteSpace] Whether or not to preserve consequent white space. * + * @param {boolean} [options.disableFilters] * @return {Array|string} A list of blocks or a string, depending on `handlerMode`. */ export function pasteHandler( { @@ -87,6 +118,7 @@ export function pasteHandler( { mode = 'AUTO', tagName, preserveWhiteSpace, + disableFilters, } ) { // First of all, strip any meta tags. HTML = HTML.replace( /]+>/g, '' ); @@ -121,6 +153,17 @@ export function pasteHandler( { HTML = HTML.normalize(); } + if ( disableFilters ) { + // If the data comes from a rich text instance, we can directly use it + // without filtering the data. The filters are only meant for externally + // pasted content and remove inline styles. + return maybeConvertParagraphToInline( { + blocks: htmlToBlocks( HTML, pasteHandler ), + plainText, + mode, + } ); + } + // Parse Markdown (and encoded HTML) if: // * There is a plain text version. // * There is no HTML version, or it has no formatting. @@ -222,25 +265,6 @@ export function pasteHandler( { // If we're allowed to return inline content, and there is only one // inlineable block, and the original plain text content does not have any // line breaks, then treat it as inline paste. - if ( - mode === 'AUTO' && - blocks.length === 1 && - hasBlockSupport( blocks[ 0 ].name, '__unstablePasteTextInline', false ) - ) { - const trimRegex = /^[\n]+|[\n]+$/g; - // Don't catch line breaks at the start or end. - const trimmedPlainText = plainText.replace( trimRegex, '' ); - - if ( - trimmedPlainText !== '' && - trimmedPlainText.indexOf( '\n' ) === -1 - ) { - return removeInvalidHTML( - getBlockInnerHTML( blocks[ 0 ] ), - phrasingContentSchema - ).replace( trimRegex, '' ); - } - } - return blocks; + return maybeConvertParagraphToInline( { blocks, plainText, mode } ); } diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/rich-text.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/rich-text.test.js.snap index bad38bd526ccf4..51e892511fc21b 100644 --- a/packages/e2e-tests/specs/editor/various/__snapshots__/rich-text.test.js.snap +++ b/packages/e2e-tests/specs/editor/various/__snapshots__/rich-text.test.js.snap @@ -26,11 +26,11 @@ exports[`RichText should apply multiple formats when selection is collapsed 1`] exports[`RichText should copy/paste heading 1`] = ` " -