Skip to content
This repository was archived by the owner on Feb 6, 2023. It is now read-only.

Commit 6df3808

Browse files
Jainil Parekhfacebook-github-bot
Jainil Parekh
authored andcommitted
Fix paste handling for images with role="presentation"
Summary: Since draft.js replaces pasted images as a camera emoji to indicate pasted content, text copied as: {F136101602} which is copied to clipboard as ``` "<meta charset='utf-8'><span style="color: rgb(29, 33, 41); font-family: system-ui, -apple-system, system-ui, &quot;.SFNSText-Regular&quot;, sans-serif; font-size: 24px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 300; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">hello<span> </span></span><span class="_5mfr _47e3" style="line-height: 0; vertical-align: middle; margin: 0px 1px; font-family: system-ui, -apple-system, system-ui, &quot;.SFNSText-Regular&quot;, sans-serif; color: rgb(29, 33, 41); font-size: 24px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 300; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;"><img class="img" height="24" role="presentation" src="https://static.xx.fbcdn.net/images/emoji.php/v9/f4a/2/24/1f600.png" width="24" alt="" style="border: 0px; vertical-align: -3px; margin-top: 0px;"><span class="_7oe" style="display: inline; font-size: 0px; width: 0px; margin-bottom: 0px; font-family: inherit;">?</span></span>" ``` essentially `<span><img /><span>...</span></span>` when pasted, renders as: {F136101606} This behavior is not required when pasting images that are for presentation only, so adding the camera emoji is skipped for this use case. This is an update to the functionality added in #1378 Rolling this out with gatekeeper `draftjs_fix_paste_for_img` Differential Revision: D9333247 fbshipit-source-id: 772229521b4457ea2a6efd726715710c03c4887d
1 parent 9f0d115 commit 6df3808

6 files changed

+50
-8
lines changed

src/model/encoding/__tests__/__snapshots__/convertFromHTMLToContentBlocks-test.js.snap

+2
Original file line numberDiff line numberDiff line change
@@ -1539,6 +1539,8 @@ exports[`img with data protocol should be correctly parsed 1`] = `"📷"`;
15391539

15401540
exports[`img with http protocol should have camera emoji content 1`] = `"📷"`;
15411541

1542+
exports[`img with role presentation should not be rendered 1`] = `null`;
1543+
15421544
exports[`must convert root ContentBlockNodes to matching ContentBlock nodes for <blockquote /> 1`] = `true`;
15431545

15441546
exports[`must convert root ContentBlockNodes to matching ContentBlock nodes for <div /> 1`] = `true`;

src/model/encoding/__tests__/__snapshots__/convertFromHTMLToContentBlocks2-test.js.snap

+2
Original file line numberDiff line numberDiff line change
@@ -2486,6 +2486,8 @@ exports[`img with data protocol should be correctly parsed 1`] = `"📷"`;
24862486

24872487
exports[`img with http protocol should have camera emoji content 1`] = `"📷"`;
24882488

2489+
exports[`img with role presentation should not be rendered 1`] = `Array []`;
2490+
24892491
exports[`must convert root ContentBlockNodes to matching ContentBlock nodes for <blockquote /> 1`] = `true`;
24902492

24912493
exports[`must convert root ContentBlockNodes to matching ContentBlock nodes for <div /> 1`] = `true`;

src/model/encoding/__tests__/convertFromHTMLToContentBlocks-test.js

+14-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,13 @@ const normalizeBlock = block => {
6060

6161
const toggleExperimentalTreeDataSupport = enabled => {
6262
jest.doMock('gkx', () => name => {
63-
return name === 'draft_tree_data_support' ? enabled : false;
63+
if (name === 'draft_tree_data_support') {
64+
return enabled;
65+
}
66+
if (name === 'draftjs_fix_paste_for_img') {
67+
return true;
68+
}
69+
return false;
6470
});
6571
};
6672

@@ -152,6 +158,13 @@ test('img with data protocol should be correctly parsed', () => {
152158
expect(blocks.contentBlocks[0].text).toMatchSnapshot();
153159
});
154160

161+
test('img with role presentation should not be rendered', () => {
162+
const blocks = convertFromHTMLToContentBlocks(
163+
`<img src="${IMAGE_DATA_URL}" role="presentation">`,
164+
);
165+
expect(blocks.contentBlocks).toMatchSnapshot();
166+
});
167+
155168
test('converts nested html blocks when experimentalTreeDataSupport is enabled', () => {
156169
const html_string = `
157170
<blockquote>

src/model/encoding/__tests__/convertFromHTMLToContentBlocks2-test.js

+14-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,13 @@ const normalizeBlock = block => {
6060

6161
const toggleExperimentalTreeDataSupport = enabled => {
6262
jest.doMock('gkx', () => name => {
63-
return name === 'draft_tree_data_support' ? enabled : false;
63+
if (name === 'draft_tree_data_support') {
64+
return enabled;
65+
}
66+
if (name === 'draftjs_fix_paste_for_img') {
67+
return true;
68+
}
69+
return false;
6470
});
6571
};
6672

@@ -152,6 +158,13 @@ test('img with data protocol should be correctly parsed', () => {
152158
expect(blocks.contentBlocks[0].text).toMatchSnapshot();
153159
});
154160

161+
test('img with role presentation should not be rendered', () => {
162+
const blocks = convertFromHTMLToContentBlocks(
163+
`<img src="${IMAGE_DATA_URL}" role="presentation">`,
164+
);
165+
expect(blocks.contentBlocks).toMatchSnapshot();
166+
});
167+
155168
test('converts nested html blocks when experimentalTreeDataSupport is enabled', () => {
156169
const html_string = `
157170
<blockquote>

src/model/encoding/convertFromHTMLToContentBlocks.js

+9-3
Original file line numberDiff line numberDiff line change
@@ -446,10 +446,16 @@ const genFragment = (
446446
});
447447
// Forcing this node to have children because otherwise no entity will be
448448
// created for this node.
449-
// The child text node cannot just have a space or return as content -
450-
// we strip those out.
449+
// The child text node cannot just have a space or return as content (since
450+
// we strip those out), unless the image is for presentation only.
451451
// See https://github.com/facebook/draft-js/issues/231 for some context.
452-
node.textContent = '\ud83d\udcf7';
452+
if (gkx('draftjs_fix_paste_for_img')) {
453+
if (node.getAttribute('role') !== 'presentation') {
454+
node.textContent = '\ud83d\udcf7';
455+
}
456+
} else {
457+
node.textContent = '\ud83d\udcf7';
458+
}
453459

454460
// TODO: update this when we remove DraftEntity entirely
455461
inEntity = DraftEntity.__create('IMAGE', 'MUTABLE', entityConfig || {});

src/model/encoding/convertFromHTMLToContentBlocks2.js

+9-3
Original file line numberDiff line numberDiff line change
@@ -534,11 +534,17 @@ class ContentBlocksBuilder {
534534
entityConfig,
535535
);
536536

537-
// The child text node cannot just have a space or return as content -
538-
// we strip those out.
537+
// The child text node cannot just have a space or return as content (since
538+
// we strip those out), unless the image is for presentation only.
539539
// See https://github.com/facebook/draft-js/issues/231 for some context.
540+
if (gkx('draftjs_fix_paste_for_img')) {
541+
if (node.getAttribute('role') !== 'presentation') {
542+
this._appendText('\ud83d\udcf7');
543+
}
544+
} else {
545+
this._appendText('\ud83d\udcf7');
546+
}
540547

541-
this._appendText('\ud83d\udcf7');
542548
this.currentEntity = null;
543549
}
544550

0 commit comments

Comments
 (0)