From a562a7ced64ce066ee5dd6af0f522fb84ed02185 Mon Sep 17 00:00:00 2001 From: Bryan Valverde U Date: Thu, 14 Dec 2023 08:34:59 -0600 Subject: [PATCH] Remove comment highlight when pasting Content from Word Online (#2272) * init * fix build --- .../test/publicApi/model/pasteTest.ts | 2 +- .../lib/paste/WacComponents/constants.ts | 83 +++++++++++++++++++ .../processPastedContentWacComponents.ts | 58 ++++++------- .../documentContainWacElements.ts | 14 +--- .../test/paste/ContentModelPastePluginTest.ts | 2 +- .../documentContainWacElementsTest.ts | 66 +++++++++++++++ .../paste/processPastedContentFromWacTest.ts | 34 ++++++++ 7 files changed, 212 insertions(+), 47 deletions(-) create mode 100644 packages-content-model/roosterjs-content-model-plugins/lib/paste/WacComponents/constants.ts diff --git a/packages-content-model/roosterjs-content-model-core/test/publicApi/model/pasteTest.ts b/packages-content-model/roosterjs-content-model-core/test/publicApi/model/pasteTest.ts index b0e61a6a330..62cbb5d487d 100644 --- a/packages-content-model/roosterjs-content-model-core/test/publicApi/model/pasteTest.ts +++ b/packages-content-model/roosterjs-content-model-core/test/publicApi/model/pasteTest.ts @@ -270,7 +270,7 @@ describe('paste with content model & paste plugin', () => { pasteF.paste(editor!, clipboardData); expect(setProcessorF.setProcessor).toHaveBeenCalledTimes(4); - expect(addParserF.default).toHaveBeenCalledTimes(DEFAULT_TIMES_ADD_PARSER_CALLED + 4); + expect(addParserF.default).toHaveBeenCalledTimes(DEFAULT_TIMES_ADD_PARSER_CALLED + 5); expect(WacComponents.processPastedContentWacComponents).toHaveBeenCalledTimes(1); }); diff --git a/packages-content-model/roosterjs-content-model-plugins/lib/paste/WacComponents/constants.ts b/packages-content-model/roosterjs-content-model-plugins/lib/paste/WacComponents/constants.ts new file mode 100644 index 00000000000..2a3d7d5eb00 --- /dev/null +++ b/packages-content-model/roosterjs-content-model-plugins/lib/paste/WacComponents/constants.ts @@ -0,0 +1,83 @@ +/** + * @internal + **/ +export const WORD_ONLINE_TABLE_TEMP_ELEMENT_CLASSES: string[] = [ + 'TableInsertRowGapBlank', + 'TableColumnResizeHandle', + 'TableCellTopBorderHandle', + 'TableCellLeftBorderHandle', + 'TableHoverColumnHandle', + 'TableHoverRowHandle', +]; +/** + * @internal + **/ +export const BULLET_LIST_STYLE: string = 'BulletListStyle'; +/** + * @internal + **/ +export const NUMBER_LIST_STYLE: string = 'NumberListStyle'; +/** + * @internal + **/ +export const IMAGE_BORDER: string = 'WACImageBorder'; +/** + * @internal + **/ +export const IMAGE_CONTAINER: string = 'WACImageContainer'; +/** + * @internal + **/ +export const OUTLINE_ELEMENT: string = 'OutlineElement'; +/** + * @internal + **/ +export const PARAGRAPH: string = 'Paragraph'; +/** + * @internal + **/ +export const LIST_CONTAINER_ELEMENT_CLASS_NAME: string = 'ListContainerWrapper'; +/** + * @internal + **/ +export const TABLE_CONTAINER: string = 'TableContainer'; +/** + * @internal + **/ +export const COMMENT_HIGHLIGHT_CLASS: string = 'CommentHighlightRest'; +/** + * @internal + **/ +export const COMMENT_HIGHLIGHT_CLICKED_CLASS: string = 'CommentHighlightClicked'; +/** + * @internal + **/ +export const TEMP_ELEMENTS_CLASSES: string[] = [ + ...WORD_ONLINE_TABLE_TEMP_ELEMENT_CLASSES, + 'ListMarkerWrappingSpan', +]; +/** + * @internal + **/ +export const WAC_IDENTIFY_SELECTOR: string = + `ul[class^="${BULLET_LIST_STYLE}"]>.${OUTLINE_ELEMENT},ol[class^="${NUMBER_LIST_STYLE}"]>.${OUTLINE_ELEMENT},span.${IMAGE_CONTAINER},span.${IMAGE_BORDER},.${COMMENT_HIGHLIGHT_CLASS},.${COMMENT_HIGHLIGHT_CLICKED_CLASS},` + + WORD_ONLINE_TABLE_TEMP_ELEMENT_CLASSES.map(c => `table div[class^="${c}"]`).join(','); +/** + * @internal + **/ +export const CLASSES_TO_KEEP: string[] = [ + OUTLINE_ELEMENT, + IMAGE_CONTAINER, + ...TEMP_ELEMENTS_CLASSES, + PARAGRAPH, + IMAGE_BORDER, + TABLE_CONTAINER, + COMMENT_HIGHLIGHT_CLASS, + COMMENT_HIGHLIGHT_CLICKED_CLASS, + 'NumberListStyle', + 'ListContainerWrapper', + 'BulletListStyle', + 'TableCellContent', + 'WACImageContainer', + 'LineBreakBlob', +]; diff --git a/packages-content-model/roosterjs-content-model-plugins/lib/paste/WacComponents/processPastedContentWacComponents.ts b/packages-content-model/roosterjs-content-model-plugins/lib/paste/WacComponents/processPastedContentWacComponents.ts index 4d382fa7172..ab82d145b25 100644 --- a/packages-content-model/roosterjs-content-model-plugins/lib/paste/WacComponents/processPastedContentWacComponents.ts +++ b/packages-content-model/roosterjs-content-model-plugins/lib/paste/WacComponents/processPastedContentWacComponents.ts @@ -1,5 +1,14 @@ import addParser from '../utils/addParser'; import { setProcessor } from '../utils/setProcessor'; +import { + CLASSES_TO_KEEP, + COMMENT_HIGHLIGHT_CLASS, + COMMENT_HIGHLIGHT_CLICKED_CLASS, + LIST_CONTAINER_ELEMENT_CLASS_NAME, + TABLE_CONTAINER, + TEMP_ELEMENTS_CLASSES, + WAC_IDENTIFY_SELECTOR, +} from './constants'; import type { ContentModelBeforePasteEvent, ContentModelBlockFormat, @@ -11,41 +20,12 @@ import type { FormatParser, } from 'roosterjs-content-model-types'; -const WAC_IDENTIFY_SELECTOR = - 'ul[class^="BulletListStyle"]>.OutlineElement,ol[class^="NumberListStyle"]>.OutlineElement,span.WACImageContainer,span.WACImageBorder'; -const LIST_CONTAINER_ELEMENT_CLASS_NAME = 'ListContainerWrapper'; - -const PARAGRAPH = 'Paragraph'; -const TABLE_CONTAINER = 'TableContainer'; - -const TEMP_ELEMENTS_CLASSES = [ - 'TableInsertRowGapBlank', - 'TableColumnResizeHandle', - 'TableCellTopBorderHandle', - 'TableCellLeftBorderHandle', - 'TableHoverColumnHandle', - 'TableHoverRowHandle', - 'ListMarkerWrappingSpan', -]; - -const CLASSES_TO_KEEP = [ - 'OutlineElement', - 'NumberListStyle', - 'WACImageContainer', - 'ListContainerWrapper', - 'BulletListStyle', - ...TEMP_ELEMENTS_CLASSES, - 'TableCellContent', - PARAGRAPH, - 'WACImageContainer', - 'WACImageBorder', - TABLE_CONTAINER, - 'LineBreakBlob', -]; - const LIST_ELEMENT_TAGS = ['UL', 'OL', 'LI']; const LIST_ELEMENT_SELECTOR = LIST_ELEMENT_TAGS.join(','); +const COMMENT_BG_COLOR_REST = 'rgba(209, 209, 209, 0.5)'; +const COMMENTS_TEXT_HIGHLIGHT_CLICKED = 'rgba(197, 139, 204, 0.5)'; + /** * Wac components do not use sub and super tags, instead only add vertical align to a span. * This parser normalize the content for content model @@ -191,6 +171,19 @@ function shouldClearListContext( ); } +const wacCommentParser: FormatParser = ( + format: ContentModelSegmentFormat, + element: HTMLElement +): void => { + if ( + (element.className.includes(COMMENT_HIGHLIGHT_CLASS) && + element.style.backgroundColor == COMMENT_BG_COLOR_REST) || + (element.className.includes(COMMENT_HIGHLIGHT_CLICKED_CLASS) && + element.style.backgroundColor == COMMENTS_TEXT_HIGHLIGHT_CLICKED) + ) { + delete format.backgroundColor; + } +}; /** * @internal * Convert pasted content from Office Online @@ -203,6 +196,7 @@ export function processPastedContentWacComponents(ev: ContentModelBeforePasteEve addParser(ev.domToModelOption, 'listItemThread', wacListItemParser); addParser(ev.domToModelOption, 'listLevel', wacListLevelParser); addParser(ev.domToModelOption, 'container', wacBlockParser); + addParser(ev.domToModelOption, 'segment', wacCommentParser); setProcessor(ev.domToModelOption, 'element', wacElementProcessor); setProcessor(ev.domToModelOption, 'li', wacLiElementProcessor); diff --git a/packages-content-model/roosterjs-content-model-plugins/lib/paste/pasteSourceValidations/documentContainWacElements.ts b/packages-content-model/roosterjs-content-model-plugins/lib/paste/pasteSourceValidations/documentContainWacElements.ts index 295e29b819b..31574fcb313 100644 --- a/packages-content-model/roosterjs-content-model-plugins/lib/paste/pasteSourceValidations/documentContainWacElements.ts +++ b/packages-content-model/roosterjs-content-model-plugins/lib/paste/pasteSourceValidations/documentContainWacElements.ts @@ -1,18 +1,6 @@ +import { WAC_IDENTIFY_SELECTOR } from '../WacComponents/constants'; import type { GetSourceFunction } from './getPasteSource'; -const WORD_ONLINE_TABLE_TEMP_ELEMENT_CLASSES = [ - 'TableInsertRowGapBlank', - 'TableColumnResizeHandle', - 'TableCellTopBorderHandle', - 'TableCellLeftBorderHandle', - 'TableHoverColumnHandle', - 'TableHoverRowHandle', -]; - -const WAC_IDENTIFY_SELECTOR = - 'ul[class^="BulletListStyle"]>.OutlineElement,ol[class^="NumberListStyle"]>.OutlineElement,span.WACImageContainer,' + - WORD_ONLINE_TABLE_TEMP_ELEMENT_CLASSES.map(c => `table div[class^="${c}"]`).join(','); - /** * @internal * Check whether the fragment provided contain Wac Elements diff --git a/packages-content-model/roosterjs-content-model-plugins/test/paste/ContentModelPastePluginTest.ts b/packages-content-model/roosterjs-content-model-plugins/test/paste/ContentModelPastePluginTest.ts index faf5cf00b0d..d2bbdb28eb2 100644 --- a/packages-content-model/roosterjs-content-model-plugins/test/paste/ContentModelPastePluginTest.ts +++ b/packages-content-model/roosterjs-content-model-plugins/test/paste/ContentModelPastePluginTest.ts @@ -189,7 +189,7 @@ describe('Content Model Paste Plugin Test', () => { plugin.onPluginEvent(event); expect(WacFile.processPastedContentWacComponents).toHaveBeenCalledWith(event); - expect(addParser.default).toHaveBeenCalledTimes(DEFAULT_TIMES_ADD_PARSER_CALLED + 4); + expect(addParser.default).toHaveBeenCalledTimes(DEFAULT_TIMES_ADD_PARSER_CALLED + 5); expect(setProcessor.setProcessor).toHaveBeenCalledTimes(4); expect(chainSanitizerCallbackFile.default).toHaveBeenCalledTimes(1); }); diff --git a/packages-content-model/roosterjs-content-model-plugins/test/paste/pasteSourceValidations/documentContainWacElementsTest.ts b/packages-content-model/roosterjs-content-model-plugins/test/paste/pasteSourceValidations/documentContainWacElementsTest.ts index e499ab2dc66..9b4bd0813fd 100644 --- a/packages-content-model/roosterjs-content-model-plugins/test/paste/pasteSourceValidations/documentContainWacElementsTest.ts +++ b/packages-content-model/roosterjs-content-model-plugins/test/paste/pasteSourceValidations/documentContainWacElementsTest.ts @@ -91,4 +91,70 @@ describe('documentContainWacElements |', () => { expect(result).toBeTrue(); }); + + it('span.WACImageContainer', () => { + const fragment = document.createDocumentFragment(); + + const span = document.createElement('span'); + span.className = 'WACImageContainer'; + fragment.appendChild(span); + + const result = documentContainWacElements({ fragment }); + + expect(result).toBeTrue(); + }); + + it('span.WACImageBorder', () => { + const fragment = document.createDocumentFragment(); + + const span = document.createElement('span'); + span.className = 'WACImageBorder'; + fragment.appendChild(span); + + const result = documentContainWacElements({ fragment }); + + expect(result).toBeTrue(); + }); + + it('CommentHighlightRest', () => { + const fragment = document.createDocumentFragment(); + + const span = document.createElement('span'); + span.className = 'CommentHighlightRest'; + fragment.appendChild(span); + + const result = documentContainWacElements({ fragment }); + + expect(result).toBeTrue(); + }); + + it('CommentHighlightClicked', () => { + const fragment = document.createDocumentFragment(); + + const span = document.createElement('span'); + span.className = 'CommentHighlightClicked'; + fragment.appendChild(span); + + const result = documentContainWacElements({ fragment }); + + expect(result).toBeTrue(); + }); + + it('Table Temp Element TableCellTopBorderHandle', () => { + const fragment = document.createDocumentFragment(); + + const table = document.createElement('table'); + const tr = document.createElement('tr'); + const td = document.createElement('td'); + const div = document.createElement('div'); + div.className = 'TableCellTopBorderHandle'; + td.appendChild(div); + tr.appendChild(td); + table.appendChild(tr); + fragment.appendChild(table); + + const result = documentContainWacElements({ fragment }); + + expect(result).toBeTrue(); + }); }); diff --git a/packages-content-model/roosterjs-content-model-plugins/test/paste/processPastedContentFromWacTest.ts b/packages-content-model/roosterjs-content-model-plugins/test/paste/processPastedContentFromWacTest.ts index 5144dde363e..f5ce08c4c4f 100644 --- a/packages-content-model/roosterjs-content-model-plugins/test/paste/processPastedContentFromWacTest.ts +++ b/packages-content-model/roosterjs-content-model-plugins/test/paste/processPastedContentFromWacTest.ts @@ -2917,4 +2917,38 @@ describe('wordOnlineHandler', () => { result ); }); + + it('Comment Removal', () => { + runTest( + '
Test
', + '
Test
', + { + blockGroupType: 'Document', + blocks: [ + { + blockType: 'Paragraph', + segments: [{ segmentType: 'Text', text: 'Test', format: {} }], + format: {}, + }, + ], + } + ); + }); + + it('Comment Removal 2', () => { + runTest( + '
Test
', + '
Test
', + { + blockGroupType: 'Document', + blocks: [ + { + blockType: 'Paragraph', + segments: [{ segmentType: 'Text', text: 'Test', format: {} }], + format: {}, + }, + ], + } + ); + }); });