Skip to content

Commit

Permalink
Fix 277159: Content is too Narrow when pasting divs and div is treate…
Browse files Browse the repository at this point in the history
…d a general block #2661
  • Loading branch information
BryanValverdeU authored May 29, 2024
1 parent ffdb5bd commit a7299c2
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { FormatParser, SizeFormat } from 'roosterjs-content-model-types';
*/
export const containerSizeFormatParser: FormatParser<SizeFormat> = (format, element) => {
// For pasted content, there may be existing width generated by browser from the temp DIV. So we need to remove it.
if (element.tagName == 'DIV') {
if (element.tagName == 'DIV' || element.tagName == 'P') {
delete format.width;
delete format.height;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { ValueSanitizer } from 'roosterjs-content-model-types';

/**
* @internal
*/
export const DefaultSanitizers: Record<string, ValueSanitizer> = {
width: divParagraphSanitizer,
height: divParagraphSanitizer,
'inline-size': divParagraphSanitizer,
'block-size': divParagraphSanitizer,
};

/**
* @internal
* exported only for unit test
*/
export function divParagraphSanitizer(value: string, tagName: string): string | null {
const tag = tagName.toLowerCase();
if (tag == 'div' || tag == 'p') {
return null;
}
return value;
}
51 changes: 49 additions & 2 deletions packages/roosterjs-content-model-plugins/lib/paste/PastePlugin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { addParser } from './utils/addParser';
import { BorderKeys } from 'roosterjs-content-model-dom';
import { BorderKeys, getObjectKeys } from 'roosterjs-content-model-dom';
import { chainSanitizerCallback } from './utils/chainSanitizerCallback';
import { DefaultSanitizers } from './DefaultSanitizers';
import { deprecatedBorderColorParser } from './utils/deprecatedColorParser';
import { getPasteSource } from './pasteSourceValidations/getPasteSource';
import { parseLink } from './utils/linkParser';
Expand All @@ -9,9 +11,11 @@ import { processPastedContentFromPowerPoint } from './PowerPoint/processPastedCo
import { processPastedContentFromWordDesktop } from './WordDesktop/processPastedContentFromWordDesktop';
import { processPastedContentWacComponents } from './WacComponents/processPastedContentWacComponents';
import type {
BeforePasteEvent,
BorderFormat,
ContentModelBlockFormat,
ContentModelTableCellFormat,
DomToModelOptionForSanitizing,
EditorPlugin,
FormatParser,
IEditor,
Expand All @@ -33,7 +37,21 @@ export class PastePlugin implements EditorPlugin {
* @param unknownTagReplacement Replace solution of unknown tags, default behavior is to replace with SPAN
* @param allowExcelNoBorderTable Allow table copied from Excel without border
*/
constructor(private allowExcelNoBorderTable?: boolean) {}
constructor(
private allowExcelNoBorderTable?: boolean,
private domToModelForSanitizing: Pick<
DomToModelOptionForSanitizing,
| 'additionalAllowedTags'
| 'additionalDisallowedTags'
| 'styleSanitizers'
| 'attributeSanitizers'
> = {
styleSanitizers: DefaultSanitizers,
additionalAllowedTags: [],
additionalDisallowedTags: [],
attributeSanitizers: {},
}
) {}

/**
* Get name of this plugin
Expand Down Expand Up @@ -116,6 +134,35 @@ export class PastePlugin implements EditorPlugin {
addParser(event.domToModelOption, 'block', blockElementParser);
addParser(event.domToModelOption, 'listLevel', blockElementParser);
}

this.setEventSanitizers(event);
}

private setEventSanitizers(event: BeforePasteEvent) {
if (this.domToModelForSanitizing) {
const {
styleSanitizers,
attributeSanitizers,
additionalAllowedTags,
additionalDisallowedTags,
} = this.domToModelForSanitizing;
getObjectKeys(styleSanitizers).forEach(key =>
chainSanitizerCallback(
event.domToModelOption.styleSanitizers,
key,
styleSanitizers[key]
)
);
getObjectKeys(attributeSanitizers).forEach(key =>
chainSanitizerCallback(
event.domToModelOption.attributeSanitizers,
key,
attributeSanitizers[key]
)
);
event.domToModelOption.additionalAllowedTags.push(...additionalAllowedTags);
event.domToModelOption.additionalDisallowedTags.push(...additionalDisallowedTags);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type { ValueSanitizer } from 'roosterjs-content-model-types';

/**
* @internal
* Chain all callback for an style sanitizer
* @param map The source callback map
* @param name Name of the property to chain
* @param newCallback A new callback to process the given name on the given map.
*/
export function chainSanitizerCallback(
map: Record<string, ValueSanitizer>,
name: string,
newCallback: ValueSanitizer
) {
const finalCb =
typeof newCallback == 'function'
? newCallback
: (value: string) => (newCallback ? value : null);
if (!map[name]) {
map[name] = finalCb;
} else {
const originalCallback = map[name];
map[name] = (value: string, tagName: string) => {
const og =
typeof originalCallback == 'function'
? originalCallback(value, tagName)
: originalCallback
? value
: false;
if (!og) {
return null;
} else {
return finalCb(og, tagName);
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ describe('Content Model Paste Plugin Test', () => {
domToModelOption: {
additionalAllowedTags: [],
additionalDisallowedTags: [],
additionalFormatParsers: {},
formatParserOverride: {},
processorOverride: {},
styleSanitizers: {},
attributeSanitizers: {},
} as any,
};
});
Expand Down Expand Up @@ -158,6 +163,53 @@ describe('Content Model Paste Plugin Test', () => {

expect(addParser.addParser).toHaveBeenCalledTimes(DEFAULT_TIMES_ADD_PARSER_CALLED);
expect(setProcessor.setProcessor).toHaveBeenCalledTimes(0);
expect(event.domToModelOption.additionalDisallowedTags.length).toEqual(0);
expect(event.domToModelOption.additionalAllowedTags.length).toEqual(0);
expect(Object.keys(event.domToModelOption.attributeSanitizers).length).toEqual(0);
expect(Object.keys(event.domToModelOption.styleSanitizers).length).toEqual(4);
});

it('Default with customized Sanitizing option', () => {
spyOn(getPasteSource, 'getPasteSource').and.returnValue('default');

plugin = new PastePlugin(undefined, {
additionalAllowedTags: ['', '', ''],
additionalDisallowedTags: ['', '', ''],
attributeSanitizers: {
'1': true,
'2': true,
},
styleSanitizers: {
'1': true,
'2': true,
},
});

plugin.initialize(editor);
plugin.onPluginEvent(event);

expect(addParser.addParser).toHaveBeenCalledTimes(DEFAULT_TIMES_ADD_PARSER_CALLED);
expect(setProcessor.setProcessor).toHaveBeenCalledTimes(0);
expect(event.domToModelOption.additionalDisallowedTags.length).toEqual(3);
expect(event.domToModelOption.additionalAllowedTags.length).toEqual(3);
expect(Object.keys(event.domToModelOption.attributeSanitizers).length).toEqual(2);
expect(Object.keys(event.domToModelOption.styleSanitizers).length).toEqual(2);
});

it('Value set to undefined.', () => {
spyOn(getPasteSource, 'getPasteSource').and.returnValue('default');

plugin = new PastePlugin(undefined, undefined);

plugin.initialize(editor);
plugin.onPluginEvent(event);

expect(addParser.addParser).toHaveBeenCalledTimes(DEFAULT_TIMES_ADD_PARSER_CALLED);
expect(setProcessor.setProcessor).toHaveBeenCalledTimes(0);
expect(event.domToModelOption.additionalDisallowedTags.length).toEqual(0);
expect(event.domToModelOption.additionalAllowedTags.length).toEqual(0);
expect(Object.keys(event.domToModelOption.attributeSanitizers).length).toEqual(0);
expect(Object.keys(event.domToModelOption.styleSanitizers).length).toEqual(4);
});

it('Google Sheets', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { divParagraphSanitizer } from '../../../lib/paste/DefaultSanitizers';

divParagraphSanitizer;

describe('divParagraphSanitizer', () => {
it('handle div', () => {
const result = divParagraphSanitizer('100px', 'div');
expect(result).toBeNull();
});
it('handle p', () => {
const result = divParagraphSanitizer('100px', 'p');
expect(result).toBeNull();
});
it('handle image', () => {
const result = divParagraphSanitizer('100px', 'image');
expect(result).toEqual('100px');
});
});

0 comments on commit a7299c2

Please sign in to comment.