Skip to content

Commit

Permalink
Rich text: use getPasteEventData (#55048)
Browse files Browse the repository at this point in the history
  • Loading branch information
ellatrix authored Oct 4, 2023
1 parent c4e10d3 commit fff4d56
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
*/
import { useRef } from '@wordpress/element';
import { useRefEffect } from '@wordpress/compose';
import { getFilesFromDataTransfer } from '@wordpress/dom';
import {
pasteHandler,
findTransform,
Expand All @@ -17,7 +16,7 @@ import { isURL } from '@wordpress/url';
*/
import { addActiveFormats, isShortcode } from './utils';
import { splitValue } from './split-value';
import { shouldDismissPastedFiles } from '../../utils/pasting';
import { getPasteEventData } from '../../utils/pasting';

/** @typedef {import('@wordpress/rich-text').RichTextValue} RichTextValue */

Expand All @@ -44,33 +43,7 @@ export function usePasteHandler( props ) {
return;
}

const { clipboardData } = event;

let plainText = '';
let html = '';

// IE11 only supports `Text` as an argument for `getData` and will
// otherwise throw an invalid argument error, so we try the standard
// arguments first, then fallback to `Text` if they fail.
try {
plainText = clipboardData.getData( 'text/plain' );
html = clipboardData.getData( 'text/html' );
} catch ( error1 ) {
try {
html = clipboardData.getData( 'Text' );
} catch ( error2 ) {
// Some browsers like UC Browser paste plain text by default and
// don't support clipboardData at all, so allow default
// behaviour.
return;
}
}

// Remove Windows-specific metadata appended within copied HTML text.
html = removeWindowsFragments( html );

// Strip meta tag.
html = removeCharsetMetaTag( html );
const { plainText, html, files } = getPasteEventData( event );

event.preventDefault();

Expand Down Expand Up @@ -103,8 +76,8 @@ export function usePasteHandler( props ) {
return;
}

const files = [ ...getFilesFromDataTransfer( clipboardData ) ];
const isInternal = clipboardData.getData( 'rich-text' ) === 'true';
const isInternal =
event.clipboardData.getData( 'rich-text' ) === 'true';

// 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
Expand All @@ -128,17 +101,7 @@ export function usePasteHandler( props ) {
// Allows us to ask for this information when we get a report.
// eslint-disable-next-line no-console
window.console.log( 'Received items:\n\n', files );
}

// Process any attached files, unless we infer that the files in
// question are redundant "screenshots" of the actual HTML payload,
// as created by certain office-type programs.
//
// @see shouldDismissPastedFiles
if (
files?.length &&
! shouldDismissPastedFiles( files, html, plainText )
) {
const fromTransforms = getBlockTransforms( 'from' );
const blocks = files
.reduce( ( accumulator, file ) => {
Expand Down Expand Up @@ -228,48 +191,3 @@ export function usePasteHandler( props ) {
};
}, [] );
}

/**
* Normalizes a given string of HTML to remove the Windows-specific "Fragment"
* comments and any preceding and trailing content.
*
* @param {string} html the html to be normalized
* @return {string} the normalized html
*/
function removeWindowsFragments( html ) {
const startStr = '<!--StartFragment-->';
const startIdx = html.indexOf( startStr );
if ( startIdx > -1 ) {
html = html.substring( startIdx + startStr.length );
} else {
// No point looking for EndFragment
return html;
}

const endStr = '<!--EndFragment-->';
const endIdx = html.indexOf( endStr );
if ( endIdx > -1 ) {
html = html.substring( 0, endIdx );
}

return html;
}

/**
* Removes the charset meta tag inserted by Chromium.
* See:
* - https://github.com/WordPress/gutenberg/issues/33585
* - https://bugs.chromium.org/p/chromium/issues/detail?id=1264616#c4
*
* @param {string} html the html to be stripped of the meta tag.
* @return {string} the cleaned html
*/
function removeCharsetMetaTag( html ) {
const metaTag = `<meta charset='utf-8'>`;

if ( html.startsWith( metaTag ) ) {
return html.slice( metaTag.length );
}

return html;
}
51 changes: 51 additions & 0 deletions packages/block-editor/src/utils/pasting.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,51 @@
*/
import { getFilesFromDataTransfer } from '@wordpress/dom';

/**
* Normalizes a given string of HTML to remove the Windows-specific "Fragment"
* comments and any preceding and trailing content.
*
* @param {string} html the html to be normalized
* @return {string} the normalized html
*/
function removeWindowsFragments( html ) {
const startStr = '<!--StartFragment-->';
const startIdx = html.indexOf( startStr );
if ( startIdx > -1 ) {
html = html.substring( startIdx + startStr.length );
} else {
// No point looking for EndFragment
return html;
}

const endStr = '<!--EndFragment-->';
const endIdx = html.indexOf( endStr );
if ( endIdx > -1 ) {
html = html.substring( 0, endIdx );
}

return html;
}

/**
* Removes the charset meta tag inserted by Chromium.
* See:
* - https://github.com/WordPress/gutenberg/issues/33585
* - https://bugs.chromium.org/p/chromium/issues/detail?id=1264616#c4
*
* @param {string} html the html to be stripped of the meta tag.
* @return {string} the cleaned html
*/
function removeCharsetMetaTag( html ) {
const metaTag = `<meta charset='utf-8'>`;

if ( html.startsWith( metaTag ) ) {
return html.slice( metaTag.length );
}

return html;
}

export function getPasteEventData( { clipboardData } ) {
let plainText = '';
let html = '';
Expand All @@ -24,6 +69,12 @@ export function getPasteEventData( { clipboardData } ) {
}
}

// Remove Windows-specific metadata appended within copied HTML text.
html = removeWindowsFragments( html );

// Strip meta tag.
html = removeCharsetMetaTag( html );

const files = getFilesFromDataTransfer( clipboardData );

if (
Expand Down

0 comments on commit fff4d56

Please sign in to comment.