Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rich text: use getPasteEventData #55048

Merged
merged 2 commits into from
Oct 4, 2023
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
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
Loading