Skip to content

Commit

Permalink
Reuse pasteHandler for internal paste
Browse files Browse the repository at this point in the history
  • Loading branch information
ellatrix committed Aug 1, 2023
1 parent 09948a7 commit 992f0e4
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 45 deletions.
33 changes: 11 additions & 22 deletions packages/block-editor/src/components/rich-text/use-paste-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ import {
pasteHandler,
findTransform,
getBlockTransforms,
htmlToBlocks,
hasBlockSupport,
getBlockContent,
} from '@wordpress/blocks';
import {
isEmpty,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 } );
Expand Down
1 change: 1 addition & 0 deletions packages/blocks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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_

Expand Down
66 changes: 45 additions & 21 deletions packages/blocks/src/api/raw-handling/paste-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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.
*
Expand All @@ -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( {
Expand All @@ -87,6 +118,7 @@ export function pasteHandler( {
mode = 'AUTO',
tagName,
preserveWhiteSpace,
disableFilters,
} ) {
// First of all, strip any meta tags.
HTML = HTML.replace( /<meta[^>]+>/g, '' );
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 } );
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ exports[`RichText should apply multiple formats when selection is collapsed 1`]

exports[`RichText should copy/paste heading 1`] = `
"<!-- wp:heading -->
<h2 class=\\"wp-block-heading\\">Heading</h2>
<h2 class="wp-block-heading">Heading</h2>
<!-- /wp:heading -->
<!-- wp:heading -->
<h2 class=\\"wp-block-heading\\">Heading</h2>
<h2 class="wp-block-heading">Heading</h2>
<!-- /wp:heading -->"
`;

Expand Down

0 comments on commit 992f0e4

Please sign in to comment.