Skip to content

Commit

Permalink
backup
Browse files Browse the repository at this point in the history
  • Loading branch information
BryanValverdeU committed Apr 25, 2023
1 parent 89e8e73 commit e08d718
Show file tree
Hide file tree
Showing 6 changed files with 270 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,13 @@ export const createPasteModel: CreatePasteModel = (
event
);

return domToContentModel(fragment, core.api.createEditorContext(core), {
processorOverride: {
element: (group, element, context) => {
const wasHandled =
event.elementProcessors.length > 0 &&
event.elementProcessors.some(p => p(group, element, context));
const model = domToContentModel(
fragment,
core.api.createEditorContext(core),
event.domToModelOption
);

if (!wasHandled) {
context.defaultElementProcessors.element(group, element, context);
}
},
},
});
return model;
};

function createBeforePasteEvent(
Expand All @@ -60,6 +54,6 @@ function createBeforePasteEvent(
htmlBefore: '',
htmlAfter: '',
htmlAttributes: {},
elementProcessors: [],
domToModelOption: {},
};
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import ContentModelBeforePasteEvent from '../../../publicTypes/event/ContentModelBeforePasteEvent';
import { getPasteSource } from 'roosterjs-editor-dom';
import { getPasteSource, safeInstanceOf } from 'roosterjs-editor-dom';
import { handleExcelOnline } from './handleExcelOnline';
import { handleWacComponents } from './handleWacComponents';
import { IContentModelEditor } from '../../../publicTypes/IContentModelEditor';
import { wordDesktopElementProcessor } from './WordDesktopProcessor/wordDesktopElementProcessor';
import {
Expand All @@ -10,6 +12,34 @@ import {
PluginEventType,
} from 'roosterjs-editor-types';

const WAC_CLASSES = [
'BulletListStyle',
'OutlineElement',
'NumberListStyle',
'OutlineElement',
'WACImageContainer',
'ListContainerWrapper',
'BulletListStyle',
'NumberListStyle',
'WACImageContainer',
'Superscript',
];
const deprecatedColorParser = (
format: import('c:/Users/bvalverde/Desktop/Newfolder/roosterjs/packages/roosterjs-content-model/lib/index').ContentModelSegmentFormat,
element: HTMLElement,
_context: import('c:/Users/bvalverde/Desktop/Newfolder/roosterjs/packages/roosterjs-content-model/lib/index').DomToModelContext,
defaultStyles: Readonly<Partial<CSSStyleDeclaration>>
): void => {
console.log(element);
if (DeprecatedColorList.indexOf(element.style.backgroundColor) > -1) {
format.backgroundColor = defaultStyles.backgroundColor;
element.style.backgroundColor = defaultStyles.backgroundColor ?? '';
}
if (DeprecatedColorList.indexOf(element.style.color) > -1) {
format.textColor = defaultStyles.color;
element.style.color = defaultStyles.color ?? '';
}
};
/**
* ContentModelFormat plugins helps editor to do formatting on top of content model.
* This includes:
Expand All @@ -18,6 +48,12 @@ import {
export default class ContentModelFormatPlugin implements EditorPlugin {
private editor: IContentModelEditor | null = null;

/**
* Construct a new instance of Paste class
* @param unknownTagReplacement Replace solution of unknown tags, default behavior is to replace with SPAN
*/
constructor(private unknownTagReplacement: string = 'SPAN') {}

/**
* Get name of this plugin
*/
Expand Down Expand Up @@ -52,26 +88,118 @@ export default class ContentModelFormatPlugin implements EditorPlugin {
* @param event The event to handle:
*/
onPluginEvent(event: PluginEvent) {
if (!this.editor) {
if (!this.editor || event.eventType != PluginEventType.BeforePaste) {
return;
}

switch (event.eventType) {
case PluginEventType.BeforePaste:
const ev = event as ContentModelBeforePasteEvent;
if (!ev.elementProcessors) {
return;
}
const pasteSource = getPasteSource(event, false);
switch (pasteSource) {
case KnownPasteSourceType.WordDesktop:
ev.elementProcessors.push(wordDesktopElementProcessor);
break;

default:
break;
}
const ev = event as ContentModelBeforePasteEvent;
if (!ev.domToModelOption.processorOverride) {
ev.domToModelOption.processorOverride = {};
}
const pasteSource = getPasteSource(event, false);
switch (pasteSource) {
case KnownPasteSourceType.WordDesktop:
ev.domToModelOption.processorOverride.element = wordDesktopElementProcessor;
break;
case KnownPasteSourceType.ExcelOnline:
handleExcelOnline(ev);
break;
case KnownPasteSourceType.WacComponents:
event.sanitizingOption.additionalAllowedCssClasses.push(...WAC_CLASSES);

handleWacComponents(ev);
break;

default:
break;
}
sanitizeHtmlColorsFromPastedContent(ev);
sanitizeLinks(ev);

event.sanitizingOption.unknownTagReplacement = this.unknownTagReplacement;
}
}

/**
* @internal
* List of deprecated colors that should be removed
*/

export const DeprecatedColorList: string[] = [
'activeborder',
'activecaption',
'appworkspace',
'background',
'buttonhighlight',
'buttonshadow',
'captiontext',
'inactiveborder',
'inactivecaption',
'inactivecaptiontext',
'infobackground',
'infotext',
'menu',
'menutext',
'scrollbar',
'threeddarkshadow',
'threedface',
'threedhighlight',
'threedlightshadow',
'threedfhadow',
'window',
'windowframe',
'windowtext',
];
function sanitizeHtmlColorsFromPastedContent(ev: ContentModelBeforePasteEvent) {
if (!ev.domToModelOption.additionalFormatParsers) {
ev.domToModelOption.additionalFormatParsers = {};
}
if (!ev.domToModelOption.additionalFormatParsers.segment) {
ev.domToModelOption.additionalFormatParsers.segment = [];
}
if (!ev.domToModelOption.additionalFormatParsers.segmentOnBlock) {
ev.domToModelOption.additionalFormatParsers.segmentOnBlock = [];
}
ev.domToModelOption.additionalFormatParsers.segment.push(deprecatedColorParser);
ev.domToModelOption.additionalFormatParsers.segmentOnBlock.push(deprecatedColorParser);
}

const HTTP = 'http:';
const HTTPS = 'https:';
const NOTES = 'notes:';

function sanitizeLinks(ev: ContentModelBeforePasteEvent) {
if (!ev.domToModelOption.additionalFormatParsers) {
ev.domToModelOption.additionalFormatParsers = {};
}
if (!ev.domToModelOption.additionalFormatParsers.link) {
ev.domToModelOption.additionalFormatParsers.link = [];
}

ev.domToModelOption.additionalFormatParsers.link.push(
(format, element, context, defaultStyle) => {
if (!safeInstanceOf(element, 'HTMLAnchorElement')) {
return;
}

let url: URL | undefined;
try {
url = new URL(element.href);
} catch {
url = undefined;
}

if (
!url ||
!(
url.protocol === HTTP ||
url.protocol === HTTPS ||
url.protocol === NOTES
) /* whitelist Notes protocol */
) {
element.removeAttribute('href');
format.href = '';
}
}
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { addBlock } from '../../../../modelApi/common/addBlock';
import { ContentModelBlockGroup } from '../../../../publicTypes/group/ContentModelBlockGroup';
import { createListItem } from '../../../../modelApi/creators/createListItem';
import { DomToModelContext } from '../../../../publicTypes/context/DomToModelContext';
import { ElementProcessor } from 'roosterjs-content-model/lib/publicTypes';
import { getStyles, safeInstanceOf } from 'roosterjs-editor-dom';
import { NodeType } from 'roosterjs-editor-types';
import { parseFormat } from '../../../../domToModel/utils/parseFormat';
import { PasteElementProcessor } from '../../../../publicTypes/event/PasteElementProcessor';

const MSO_COMMENT_ANCHOR_HREF_REGEX = /#_msocom_/;
const MSO_SPECIAL_CHARACTER = 'mso-special-character';
Expand All @@ -15,13 +15,18 @@ const MSO_ELEMENT_COMMENT_LIST = 'comment-list';
const MSO_LIST = 'mso-list';
const MSO_LIST_IGNORE = 'ignore';

export const wordDesktopElementProcessor: PasteElementProcessor<HTMLElement> = (
export const wordDesktopElementProcessor: ElementProcessor<HTMLElement> = (
group,
element,
context
) => {
const styles = getStyles(element);
return processWordList(styles, group, element, context) || processWordCommand(styles, element);
const wasHandled =
processWordList(styles, group, element, context) || processWordCommand(styles, element);

if (!wasHandled) {
context.defaultElementProcessors.element(group, element, context);
}
};

function processWordCommand(styles: Record<string, string>, element: HTMLElement) {
Expand Down Expand Up @@ -77,7 +82,6 @@ function processWordList(
addBlock(group, listItem);
return true;
}

return false;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import ContentModelBeforePasteEvent from '../../../publicTypes/event/ContentModelBeforePasteEvent';

const DEFAULT_BORDER_STYLE = 'solid 1px #d4d4d4';

export function handleExcelOnline(ev: ContentModelBeforePasteEvent) {
if (!ev.domToModelOption.formatParserOverride) {
ev.domToModelOption.formatParserOverride = {};
}

if (!ev.domToModelOption.processorOverride) {
ev.domToModelOption.processorOverride = {};
}

ev.domToModelOption.processorOverride.element = (group, element, context) => {
if (element.tagName.toLowerCase() === 'div' && element.getAttribute('data-ccp-timestamp')) {
context.elementProcessors.child(group, element, context);
} else {
context.defaultElementProcessors.element(group, element, context);
}
};

ev.domToModelOption.formatParserOverride.border = (format, element) => {
if (element.style.border === 'none') {
format.borderBottom = DEFAULT_BORDER_STYLE;
format.borderRight = DEFAULT_BORDER_STYLE;
format.borderTop = DEFAULT_BORDER_STYLE;
format.borderLeft = DEFAULT_BORDER_STYLE;
}
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import ContentModelBeforePasteEvent from '../../../publicTypes/event/ContentModelBeforePasteEvent';
import { matchesSelector } from 'roosterjs-editor-dom';

const WAC_IDENTIFY_SELECTOR =
'ul[class^="BulletListStyle"]>.OutlineElement,ol[class^="NumberListStyle"]>.OutlineElement,span.WACImageContainer';
const WORD_ONLINE_IDENTIFYING_SELECTOR =
'div.ListContainerWrapper>ul[class^="BulletListStyle"],div.ListContainerWrapper>ol[class^="NumberListStyle"],span.WACImageContainer > img';
export const LIST_CONTAINER_ELEMENT_CLASS_NAME = 'ListContainerWrapper';
const IMAGE_CONTAINER_ELEMENT_CLASS_NAME = 'WACImageContainer';

export function handleWacComponents(ev: ContentModelBeforePasteEvent) {
if (!ev.domToModelOption.additionalFormatParsers) {
ev.domToModelOption.additionalFormatParsers = {};
ev.domToModelOption.additionalFormatParsers.segment = [];
}
if (!ev.domToModelOption.processorOverride) {
ev.domToModelOption.processorOverride = {};
}

ev.domToModelOption.additionalFormatParsers.segment!.push((format, element, context) => {
const verticalAlign = element.style.verticalAlign;
if (verticalAlign === 'super') {
format.superOrSubScriptSequence = 'super';
}
if (verticalAlign === 'sub') {
format.superOrSubScriptSequence = 'sub';
}
});

ev.domToModelOption.processorOverride.element = (group, element, context) => {
if (matchesSelector(element, WAC_IDENTIFY_SELECTOR)) {
element.style.removeProperty('display');
element.style.removeProperty('margin');
}
if (element.classList.contains(LIST_CONTAINER_ELEMENT_CLASS_NAME)) {
context.elementProcessors.child(group, element, context);
return;
}

if (element.parentElement?.classList.contains(IMAGE_CONTAINER_ELEMENT_CLASS_NAME)) {
return;
}

context.defaultElementProcessors.element(group, element, context);
};

ev.domToModelOption.processorOverride.li = (group, element, context) => {
context.defaultElementProcessors.li?.(group, element, context);
const { listFormat } = context;
const listParent = listFormat.listParent;
if (listParent) {
const lastblock = listParent.blocks[listParent.blocks.length - 1];
if (lastblock.blockType == 'BlockGroup' && lastblock.blockGroupType == 'ListItem') {
const currentLevel = lastblock.levels[lastblock.levels.length - 1];

// Get item level from 'data-aria-level' attribute
let level = parseInt(element.getAttribute('data-aria-level') ?? '');

if (level > lastblock.levels.length) {
while (level != lastblock.levels.length) {
lastblock.levels.push(currentLevel);
}
} else {
lastblock.levels.splice(level, lastblock.levels.length - 1);
lastblock.levels[level - 1] = currentLevel;
}
}
}
};
}

/**
* @internal
*/
export function isWordOnlineWithList(fragment: DocumentFragment): boolean {
return !!(fragment && fragment.querySelector(WORD_ONLINE_IDENTIFYING_SELECTOR));
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PasteElementProcessor } from './PasteElementProcessor';
import { DomToModelOption } from '../IContentModelEditor';
import {
BeforePasteEvent,
BeforePasteEventData,
Expand All @@ -10,11 +10,9 @@ import {
*/
export interface ContentModelBeforePasteEventData extends BeforePasteEventData {
/**
* Element processors to use when pasting.
* If the a processor function in the array returns true, means that the element procesing was done by the function.
* If all the processors return false, the default processor will be used instead.
* domToModel Options to use when creating the content model from the paste fragment
*/
elementProcessors: PasteElementProcessor<HTMLElement>[];
domToModelOption: Partial<DomToModelOption>;
}

/**
Expand Down

0 comments on commit e08d718

Please sign in to comment.