roosterjs-content-model-plugins 0.21.3 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/lib/edit/deleteSteps/deleteAllSegmentBefore.js +3 -0
  2. package/lib/edit/deleteSteps/deleteAllSegmentBefore.js.map +1 -1
  3. package/lib/edit/deleteSteps/deleteCollapsedSelection.js +3 -0
  4. package/lib/edit/deleteSteps/deleteCollapsedSelection.js.map +1 -1
  5. package/lib/edit/deleteSteps/deleteWordSelection.js +3 -0
  6. package/lib/edit/deleteSteps/deleteWordSelection.js.map +1 -1
  7. package/lib/edit/keyboardInput.js +1 -1
  8. package/lib/edit/keyboardInput.js.map +1 -1
  9. package/lib/paste/ContentModelPastePlugin.d.ts +3 -1
  10. package/lib/paste/ContentModelPastePlugin.js +5 -3
  11. package/lib/paste/ContentModelPastePlugin.js.map +1 -1
  12. package/lib/paste/Excel/processPastedContentFromExcel.d.ts +1 -1
  13. package/lib/paste/Excel/processPastedContentFromExcel.js +2 -2
  14. package/lib/paste/Excel/processPastedContentFromExcel.js.map +1 -1
  15. package/lib/paste/WacComponents/constants.d.ts +56 -0
  16. package/lib/paste/WacComponents/constants.js +86 -0
  17. package/lib/paste/WacComponents/constants.js.map +1 -0
  18. package/lib/paste/WacComponents/processPastedContentWacComponents.js +19 -34
  19. package/lib/paste/WacComponents/processPastedContentWacComponents.js.map +1 -1
  20. package/lib/paste/WordDesktop/WordMetadata.d.ts +9 -0
  21. package/lib/paste/WordDesktop/WordMetadata.js +3 -0
  22. package/lib/paste/WordDesktop/WordMetadata.js.map +1 -0
  23. package/lib/paste/WordDesktop/getStyleMetadata.d.ts +23 -0
  24. package/lib/paste/WordDesktop/getStyleMetadata.js +79 -0
  25. package/lib/paste/WordDesktop/getStyleMetadata.js.map +1 -0
  26. package/lib/paste/WordDesktop/processPastedContentFromWordDesktop.d.ts +2 -7
  27. package/lib/paste/WordDesktop/processPastedContentFromWordDesktop.js +14 -14
  28. package/lib/paste/WordDesktop/processPastedContentFromWordDesktop.js.map +1 -1
  29. package/lib/paste/WordDesktop/processWordLists.d.ts +2 -1
  30. package/lib/paste/WordDesktop/processWordLists.js +83 -85
  31. package/lib/paste/WordDesktop/processWordLists.js.map +1 -1
  32. package/lib/paste/pasteSourceValidations/documentContainWacElements.js +2 -11
  33. package/lib/paste/pasteSourceValidations/documentContainWacElements.js.map +1 -1
  34. package/lib/paste/pasteSourceValidations/getPasteSource.d.ts +2 -1
  35. package/lib/paste/pasteSourceValidations/getPasteSource.js.map +1 -1
  36. package/lib-amd/edit/deleteSteps/deleteAllSegmentBefore.js +3 -0
  37. package/lib-amd/edit/deleteSteps/deleteAllSegmentBefore.js.map +1 -1
  38. package/lib-amd/edit/deleteSteps/deleteCollapsedSelection.js +3 -0
  39. package/lib-amd/edit/deleteSteps/deleteCollapsedSelection.js.map +1 -1
  40. package/lib-amd/edit/deleteSteps/deleteWordSelection.js +3 -0
  41. package/lib-amd/edit/deleteSteps/deleteWordSelection.js.map +1 -1
  42. package/lib-amd/edit/keyboardInput.js +1 -1
  43. package/lib-amd/edit/keyboardInput.js.map +1 -1
  44. package/lib-amd/paste/ContentModelPastePlugin.d.ts +3 -1
  45. package/lib-amd/paste/ContentModelPastePlugin.js +5 -3
  46. package/lib-amd/paste/ContentModelPastePlugin.js.map +1 -1
  47. package/lib-amd/paste/Excel/processPastedContentFromExcel.d.ts +1 -1
  48. package/lib-amd/paste/Excel/processPastedContentFromExcel.js +2 -2
  49. package/lib-amd/paste/Excel/processPastedContentFromExcel.js.map +1 -1
  50. package/lib-amd/paste/WacComponents/constants.d.ts +56 -0
  51. package/lib-amd/paste/WacComponents/constants.js +87 -0
  52. package/lib-amd/paste/WacComponents/constants.js.map +1 -0
  53. package/lib-amd/paste/WacComponents/processPastedContentWacComponents.js +19 -35
  54. package/lib-amd/paste/WacComponents/processPastedContentWacComponents.js.map +1 -1
  55. package/lib-amd/paste/WordDesktop/WordMetadata.d.ts +9 -0
  56. package/lib-amd/paste/WordDesktop/WordMetadata.js +5 -0
  57. package/lib-amd/paste/WordDesktop/WordMetadata.js.map +1 -0
  58. package/lib-amd/paste/WordDesktop/getStyleMetadata.d.ts +23 -0
  59. package/lib-amd/paste/WordDesktop/getStyleMetadata.js +79 -0
  60. package/lib-amd/paste/WordDesktop/getStyleMetadata.js.map +1 -0
  61. package/lib-amd/paste/WordDesktop/processPastedContentFromWordDesktop.d.ts +2 -7
  62. package/lib-amd/paste/WordDesktop/processPastedContentFromWordDesktop.js +14 -15
  63. package/lib-amd/paste/WordDesktop/processPastedContentFromWordDesktop.js.map +1 -1
  64. package/lib-amd/paste/WordDesktop/processWordLists.d.ts +2 -1
  65. package/lib-amd/paste/WordDesktop/processWordLists.js +83 -85
  66. package/lib-amd/paste/WordDesktop/processWordLists.js.map +1 -1
  67. package/lib-amd/paste/pasteSourceValidations/documentContainWacElements.js +2 -12
  68. package/lib-amd/paste/pasteSourceValidations/documentContainWacElements.js.map +1 -1
  69. package/lib-amd/paste/pasteSourceValidations/getPasteSource.d.ts +2 -1
  70. package/lib-amd/paste/pasteSourceValidations/getPasteSource.js.map +1 -1
  71. package/lib-mjs/edit/deleteSteps/deleteAllSegmentBefore.js +3 -0
  72. package/lib-mjs/edit/deleteSteps/deleteAllSegmentBefore.js.map +1 -1
  73. package/lib-mjs/edit/deleteSteps/deleteCollapsedSelection.js +3 -0
  74. package/lib-mjs/edit/deleteSteps/deleteCollapsedSelection.js.map +1 -1
  75. package/lib-mjs/edit/deleteSteps/deleteWordSelection.js +3 -0
  76. package/lib-mjs/edit/deleteSteps/deleteWordSelection.js.map +1 -1
  77. package/lib-mjs/edit/keyboardInput.js +1 -1
  78. package/lib-mjs/edit/keyboardInput.js.map +1 -1
  79. package/lib-mjs/paste/ContentModelPastePlugin.d.ts +3 -1
  80. package/lib-mjs/paste/ContentModelPastePlugin.js +5 -3
  81. package/lib-mjs/paste/ContentModelPastePlugin.js.map +1 -1
  82. package/lib-mjs/paste/Excel/processPastedContentFromExcel.d.ts +1 -1
  83. package/lib-mjs/paste/Excel/processPastedContentFromExcel.js +2 -2
  84. package/lib-mjs/paste/Excel/processPastedContentFromExcel.js.map +1 -1
  85. package/lib-mjs/paste/WacComponents/constants.d.ts +56 -0
  86. package/lib-mjs/paste/WacComponents/constants.js +83 -0
  87. package/lib-mjs/paste/WacComponents/constants.js.map +1 -0
  88. package/lib-mjs/paste/WacComponents/processPastedContentWacComponents.js +12 -27
  89. package/lib-mjs/paste/WacComponents/processPastedContentWacComponents.js.map +1 -1
  90. package/lib-mjs/paste/WordDesktop/WordMetadata.d.ts +9 -0
  91. package/lib-mjs/paste/WordDesktop/WordMetadata.js +2 -0
  92. package/lib-mjs/paste/WordDesktop/WordMetadata.js.map +1 -0
  93. package/lib-mjs/paste/WordDesktop/getStyleMetadata.d.ts +23 -0
  94. package/lib-mjs/paste/WordDesktop/getStyleMetadata.js +76 -0
  95. package/lib-mjs/paste/WordDesktop/getStyleMetadata.js.map +1 -0
  96. package/lib-mjs/paste/WordDesktop/processPastedContentFromWordDesktop.d.ts +2 -7
  97. package/lib-mjs/paste/WordDesktop/processPastedContentFromWordDesktop.js +13 -12
  98. package/lib-mjs/paste/WordDesktop/processPastedContentFromWordDesktop.js.map +1 -1
  99. package/lib-mjs/paste/WordDesktop/processWordLists.d.ts +2 -1
  100. package/lib-mjs/paste/WordDesktop/processWordLists.js +84 -86
  101. package/lib-mjs/paste/WordDesktop/processWordLists.js.map +1 -1
  102. package/lib-mjs/paste/pasteSourceValidations/documentContainWacElements.js +1 -10
  103. package/lib-mjs/paste/pasteSourceValidations/documentContainWacElements.js.map +1 -1
  104. package/lib-mjs/paste/pasteSourceValidations/getPasteSource.d.ts +2 -1
  105. package/lib-mjs/paste/pasteSourceValidations/getPasteSource.js.map +1 -1
  106. package/package.json +5 -5
@@ -1 +1 @@
1
- {"version":3,"file":"processPastedContentFromWordDesktop.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-plugins/lib/paste/WordDesktop/processPastedContentFromWordDesktop.ts"],"names":[],"mappings":"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","sourcesContent":["import addParser from '../utils/addParser';\nimport { chainSanitizerCallback } from 'roosterjs-editor-dom';\nimport { getStyles } from '../utils/getStyles';\nimport { moveChildNodes } from 'roosterjs-content-model-dom';\nimport { processWordComments } from './processWordComments';\nimport { processWordList } from './processWordLists';\nimport { setProcessor } from '../utils/setProcessor';\nimport type {\n ContentModelBeforePasteEvent,\n ContentModelBlockFormat,\n ContentModelListItemFormat,\n ContentModelListItemLevelFormat,\n DomToModelContext,\n ElementProcessor,\n FormatParser,\n} from 'roosterjs-content-model-types';\n\nconst PERCENTAGE_REGEX = /%/;\nconst DEFAULT_BROWSER_LINE_HEIGHT_PERCENTAGE = 120;\n\n/**\n * @internal\n * Handles Pasted content when source is Word Desktop\n * @param ev ContentModelBeforePasteEvent\n */\nexport function processPastedContentFromWordDesktop(ev: ContentModelBeforePasteEvent) {\n setProcessor(ev.domToModelOption, 'element', wordDesktopElementProcessor);\n addParser(ev.domToModelOption, 'block', removeNonValidLineHeight);\n addParser(ev.domToModelOption, 'listLevel', listLevelParser);\n addParser(ev.domToModelOption, 'listItemElement', listItemElementParser);\n\n // Remove \"border:none\" for image to fix image resize behavior\n // We found a problem that when paste an image with \"border:none\" then the resize border will be\n // displayed incorrectly when resize it. So we need to drop this style\n chainSanitizerCallback(\n ev.sanitizingOption.cssStyleCallbacks,\n 'border',\n (value, element) => element.tagName != 'IMG' || value != 'none'\n );\n\n // Preserve <o:p> when its innerHTML is \"&nbsp;\" to avoid dropping an empty line\n chainSanitizerCallback(ev.sanitizingOption.elementCallbacks, 'O:P', element => {\n moveChildNodes(element);\n element.appendChild(element.ownerDocument.createTextNode('\\u00A0')); // &nbsp;\n return true;\n });\n}\n\n/**\n * @internal\n * Exported only for unit test\n */\nexport const wordDesktopElementProcessor: ElementProcessor<HTMLElement> = (\n group,\n element,\n context\n) => {\n const styles = getStyles(element);\n // Process Word Lists or Word Commands, otherwise use the default processor on this element.\n if (\n !(processWordList(styles, group, element, context) || processWordComments(styles, element))\n ) {\n context.defaultElementProcessors.element(group, element, context);\n }\n};\n\nfunction removeNonValidLineHeight(\n format: ContentModelBlockFormat,\n element: HTMLElement,\n context: DomToModelContext,\n defaultStyle: Readonly<Partial<CSSStyleDeclaration>>\n): void {\n //If the line height is less than the browser default line height, line between the text is going to be too narrow\n let parsedLineHeight: number;\n if (\n PERCENTAGE_REGEX.test(element.style.lineHeight) &&\n !isNaN((parsedLineHeight = parseInt(element.style.lineHeight))) &&\n parsedLineHeight < DEFAULT_BROWSER_LINE_HEIGHT_PERCENTAGE\n ) {\n format.lineHeight = defaultStyle.lineHeight;\n }\n}\n\nfunction listLevelParser(\n format: ContentModelListItemLevelFormat,\n element: HTMLElement,\n context: DomToModelContext,\n defaultStyle: Readonly<Partial<CSSStyleDeclaration>>\n): void {\n if (element.style.marginLeft != '') {\n format.marginLeft = defaultStyle.marginLeft;\n }\n\n format.marginBottom = undefined;\n}\n\nconst listItemElementParser: FormatParser<ContentModelListItemFormat> = (\n format: ContentModelListItemFormat,\n element: HTMLElement\n): void => {\n if (element.style.marginLeft) {\n format.marginLeft = undefined;\n }\n if (element.style.marginRight) {\n format.marginRight = undefined;\n }\n};\n"]}
1
+ {"version":3,"file":"processPastedContentFromWordDesktop.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-plugins/lib/paste/WordDesktop/processPastedContentFromWordDesktop.ts"],"names":[],"mappings":"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","sourcesContent":["import addParser from '../utils/addParser';\nimport getStyleMetadata from './getStyleMetadata';\nimport { chainSanitizerCallback } from 'roosterjs-editor-dom';\nimport { getStyles } from '../utils/getStyles';\nimport { moveChildNodes } from 'roosterjs-content-model-dom';\nimport { processWordComments } from './processWordComments';\nimport { processWordList } from './processWordLists';\nimport { setProcessor } from '../utils/setProcessor';\nimport type { WordMetadata } from './WordMetadata';\nimport type {\n ContentModelBeforePasteEvent,\n ContentModelBlockFormat,\n ContentModelListItemFormat,\n ContentModelListItemLevelFormat,\n DomToModelContext,\n ElementProcessor,\n FormatParser,\n} from 'roosterjs-content-model-types';\n\nconst PERCENTAGE_REGEX = /%/;\nconst DEFAULT_BROWSER_LINE_HEIGHT_PERCENTAGE = 120;\n\n/**\n * @internal\n * Handles Pasted content when source is Word Desktop\n * @param ev ContentModelBeforePasteEvent\n */\nexport function processPastedContentFromWordDesktop(\n ev: ContentModelBeforePasteEvent,\n trustedHTMLHandler: (text: string) => string\n) {\n const metadataMap: Map<string, WordMetadata> = getStyleMetadata(ev, trustedHTMLHandler);\n\n setProcessor(ev.domToModelOption, 'element', wordDesktopElementProcessor(metadataMap));\n addParser(ev.domToModelOption, 'block', removeNonValidLineHeight);\n addParser(ev.domToModelOption, 'listLevel', listLevelParser);\n addParser(ev.domToModelOption, 'listItemElement', listItemElementParser);\n\n // Remove \"border:none\" for image to fix image resize behavior\n // We found a problem that when paste an image with \"border:none\" then the resize border will be\n // displayed incorrectly when resize it. So we need to drop this style\n chainSanitizerCallback(\n ev.sanitizingOption.cssStyleCallbacks,\n 'border',\n (value, element) => element.tagName != 'IMG' || value != 'none'\n );\n\n // Preserve <o:p> when its innerHTML is \"&nbsp;\" to avoid dropping an empty line\n chainSanitizerCallback(ev.sanitizingOption.elementCallbacks, 'O:P', element => {\n moveChildNodes(element);\n element.appendChild(element.ownerDocument.createTextNode('\\u00A0')); // &nbsp;\n return true;\n });\n}\n\nconst wordDesktopElementProcessor = (\n metadataKey: Map<string, WordMetadata>\n): ElementProcessor<HTMLElement> => {\n return (group, element, context) => {\n const styles = getStyles(element);\n // Process Word Lists or Word Commands, otherwise use the default processor on this element.\n if (\n !(\n processWordList(styles, group, element, context, metadataKey) ||\n processWordComments(styles, element)\n )\n ) {\n context.defaultElementProcessors.element(group, element, context);\n }\n };\n};\n\nfunction removeNonValidLineHeight(\n format: ContentModelBlockFormat,\n element: HTMLElement,\n context: DomToModelContext,\n defaultStyle: Readonly<Partial<CSSStyleDeclaration>>\n): void {\n //If the line height is less than the browser default line height, line between the text is going to be too narrow\n let parsedLineHeight: number;\n if (\n PERCENTAGE_REGEX.test(element.style.lineHeight) &&\n !isNaN((parsedLineHeight = parseInt(element.style.lineHeight))) &&\n parsedLineHeight < DEFAULT_BROWSER_LINE_HEIGHT_PERCENTAGE\n ) {\n format.lineHeight = defaultStyle.lineHeight;\n }\n}\n\nfunction listLevelParser(\n format: ContentModelListItemLevelFormat,\n element: HTMLElement,\n context: DomToModelContext,\n defaultStyle: Readonly<Partial<CSSStyleDeclaration>>\n): void {\n if (element.style.marginLeft != '') {\n format.marginLeft = defaultStyle.marginLeft;\n }\n\n format.marginBottom = undefined;\n}\n\nconst listItemElementParser: FormatParser<ContentModelListItemFormat> = (\n format: ContentModelListItemFormat,\n element: HTMLElement\n): void => {\n if (element.style.marginLeft) {\n format.marginLeft = undefined;\n }\n if (element.style.marginRight) {\n format.marginRight = undefined;\n }\n};\n"]}
@@ -1,3 +1,4 @@
1
+ import type { WordMetadata } from './WordMetadata';
1
2
  import type { ContentModelBlockGroup, DomToModelContext } from 'roosterjs-content-model-types';
2
3
  /**
3
4
  * @internal
@@ -7,4 +8,4 @@ import type { ContentModelBlockGroup, DomToModelContext } from 'roosterjs-conten
7
8
  * @param context
8
9
  * @returns
9
10
  */
10
- export declare function processWordList(styles: Record<string, string>, group: ContentModelBlockGroup, element: HTMLElement, context: DomToModelContext): boolean;
11
+ export declare function processWordList(styles: Record<string, string>, group: ContentModelBlockGroup, element: HTMLElement, context: DomToModelContext, metadata: Map<string, WordMetadata>): boolean;
@@ -1,11 +1,12 @@
1
1
  import { __read, __spreadArray } from "tslib";
2
- import { getStyles } from '../utils/getStyles';
3
- import { addBlock, createListItem, createListLevel, isNodeOfType, parseFormat, } from 'roosterjs-content-model-dom';
2
+ import { getListStyleTypeFromString, updateListMetadata } from 'roosterjs-content-model-core';
3
+ import { addBlock, createListItem, createListLevel, parseFormat, } from 'roosterjs-content-model-dom';
4
4
  /** Word list metadata style name */
5
5
  var MSO_LIST = 'mso-list';
6
6
  var MSO_LIST_IGNORE = 'ignore';
7
- var LOOKUP_DEPTH = 5;
8
7
  var WORD_FIRST_LIST = 'l0';
8
+ var TEMPLATE_VALUE_REGEX = /%[0-9a-zA-Z]+/g;
9
+ var BULLET_METADATA = 'bullet';
9
10
  /**
10
11
  * @internal
11
12
  * @param styles
@@ -14,7 +15,8 @@ var WORD_FIRST_LIST = 'l0';
14
15
  * @param context
15
16
  * @returns
16
17
  */
17
- export function processWordList(styles, group, element, context) {
18
+ export function processWordList(styles, group, element, context, metadata) {
19
+ var _a;
18
20
  var listFormat = context.listFormat;
19
21
  if (!listFormat.wordKnownLevels) {
20
22
  listFormat.wordKnownLevels = new Map();
@@ -25,19 +27,22 @@ export function processWordList(styles, group, element, context) {
25
27
  if (wordListStyle.toLowerCase() === MSO_LIST_IGNORE) {
26
28
  return true;
27
29
  }
28
- var listProps = wordListStyle.split(' ');
30
+ var _b = __read(wordListStyle.split(' '), 2), lNumber = _b[0], level = _b[1];
29
31
  // Try get the list metadata from word, which follows this format: l1 level1 lfo2
30
32
  // If we are able to get the level property means we can process this element to be a list
31
- listFormat.wordLevel = listProps[1] && parseInt(listProps[1].substr('level'.length));
32
- listFormat.wordList = listProps[0] || WORD_FIRST_LIST;
33
+ listFormat.wordLevel = level && parseInt(level.substr('level'.length));
34
+ listFormat.wordList = lNumber || WORD_FIRST_LIST;
33
35
  if (listFormat.levels.length == 0) {
34
- listFormat.levels = listFormat.wordKnownLevels.get(listFormat.wordList) || [];
36
+ listFormat.levels =
37
+ (listFormat.wordList && listFormat.wordKnownLevels.get(listFormat.wordList)) || [];
35
38
  }
36
39
  if (wordListStyle && group && typeof listFormat.wordLevel === 'number') {
37
- var wordLevel = listFormat.wordLevel;
40
+ var wordLevel = listFormat.wordLevel, wordList = listFormat.wordList;
38
41
  // Retrieve the Fake bullet on the element and also the list type
39
- var fakeBullet = getFakeBulletText(element);
40
- var listType = getFakeBulletTagName(fakeBullet);
42
+ var listMetadata = metadata.get(lNumber + ":" + level);
43
+ var listType = ((_a = listMetadata === null || listMetadata === void 0 ? void 0 : listMetadata['mso-level-number-format']) === null || _a === void 0 ? void 0 : _a.toLowerCase()) != BULLET_METADATA
44
+ ? 'OL'
45
+ : 'UL';
41
46
  // Create the new level of the list item and parse the format
42
47
  var newLevel = createListLevel(listType);
43
48
  parseFormat(element, context.formatParsers.listLevel, newLevel.format, context);
@@ -53,99 +58,92 @@ export function processWordList(styles, group, element, context) {
53
58
  listFormat.levels[wordLevel - 1] = newLevel;
54
59
  }
55
60
  listFormat.listParent = group;
56
- processAsListItem(listFormat, context, element, group, fakeBullet);
61
+ processAsListItem(listFormat, context, element, group, listMetadata);
57
62
  if (listFormat.levels.length > 0 &&
58
- listFormat.wordKnownLevels.get(listFormat.wordList) != listFormat.levels) {
59
- listFormat.wordKnownLevels.set(listFormat.wordList, __spreadArray([], __read(listFormat.levels), false));
63
+ listFormat.wordKnownLevels.get(wordList) != listFormat.levels) {
64
+ listFormat.wordKnownLevels.set(wordList, __spreadArray([], __read(listFormat.levels), false));
60
65
  }
61
66
  return true;
62
67
  }
63
68
  return false;
64
69
  }
65
- function processAsListItem(listFormat, context, element, group, fakeBullet) {
70
+ function processAsListItem(listFormat, context, element, group, listMetadata) {
71
+ var listLevel = listFormat.levels[listFormat.levels.length - 1];
72
+ var listType = listLevel.listType;
73
+ var bullet = getBulletFromMetadata(listMetadata, listType);
74
+ if (bullet) {
75
+ updateListMetadata(listFormat.levels[listFormat.levels.length - 1], function (metadata) {
76
+ return Object.assign({}, metadata, {
77
+ unorderedStyleType: listType == 'UL' ? bullet : undefined,
78
+ orderedStyleType: listType == 'OL' ? bullet : undefined,
79
+ });
80
+ });
81
+ }
66
82
  var listItem = createListItem(listFormat.levels, context.segmentFormat);
67
- var lastLevel = listItem.levels[listItem.levels.length - 1];
68
83
  parseFormat(element, context.formatParsers.segmentOnBlock, context.segmentFormat, context);
69
84
  parseFormat(element, context.formatParsers.listItemElement, listItem.format, context);
70
- if ((lastLevel === null || lastLevel === void 0 ? void 0 : lastLevel.listType) == 'OL') {
71
- parseFormat(element, [startNumberOverrideParser(fakeBullet)], listItem.levels[listItem.levels.length - 1].format, context);
85
+ if (listType == 'OL') {
86
+ parseFormat(element, [startNumberOverrideParser(listMetadata)], listItem.levels[listItem.levels.length - 1].format, context);
72
87
  }
73
88
  context.elementProcessors.child(listItem, element, context);
74
89
  addBlock(group, listItem);
75
90
  }
76
- function startNumberOverrideParser(fakeBullet) {
91
+ function getBulletFromMetadata(listMetadata, listType) {
92
+ var templateType = (listMetadata === null || listMetadata === void 0 ? void 0 : listMetadata['mso-level-number-format']) || 'decimal';
93
+ var templateFinal;
94
+ if (listMetadata === null || listMetadata === void 0 ? void 0 : listMetadata['mso-level-text']) {
95
+ var templateValue = '';
96
+ switch (templateType) {
97
+ case 'alpha-upper':
98
+ templateValue = 'UpperAlpha';
99
+ break;
100
+ case 'alpha-lower':
101
+ templateValue = 'LowerAlpha';
102
+ break;
103
+ case 'roman-lower':
104
+ templateValue = 'LowerRoman';
105
+ break;
106
+ case 'roman-upper':
107
+ templateValue = 'UpperRoman';
108
+ break;
109
+ default:
110
+ templateValue = 'Number';
111
+ break;
112
+ }
113
+ var template = (listMetadata['mso-level-text'] || '')
114
+ .replace('\\', '')
115
+ .replace('"', '')
116
+ .replace(TEMPLATE_VALUE_REGEX, '${' + templateValue + '}');
117
+ templateFinal = '"' + template + ' "';
118
+ }
119
+ else {
120
+ switch (templateType) {
121
+ case 'alpha-lower':
122
+ templateFinal = 'lower-alpha';
123
+ break;
124
+ case 'roman-lower':
125
+ templateFinal = 'lower-roman';
126
+ break;
127
+ case 'roman-upper':
128
+ templateFinal = 'upper-roman';
129
+ break;
130
+ default:
131
+ templateFinal = 'decimal';
132
+ break;
133
+ }
134
+ }
135
+ return getListStyleTypeFromString(listType, templateFinal);
136
+ }
137
+ function startNumberOverrideParser(listMetadata) {
77
138
  return function (format, _, context) {
78
- var _a = context.listFormat, wordKnownLevels = _a.wordKnownLevels, wordLevel = _a.wordLevel, wordList = _a.wordList;
139
+ var _a = context.listFormat, wordKnownLevels = _a.wordKnownLevels, wordLevel = _a.wordLevel, wordList = _a.wordList, levels = _a.levels;
79
140
  if (typeof wordLevel === 'number' && wordList) {
80
- var start = parseInt(fakeBullet);
81
- if (start != undefined && !isNaN(start) && !(wordKnownLevels === null || wordKnownLevels === void 0 ? void 0 : wordKnownLevels.has(wordList))) {
141
+ var start = parseInt((listMetadata === null || listMetadata === void 0 ? void 0 : listMetadata['mso-level-start-at']) || '1');
142
+ var knownLevel = (wordKnownLevels === null || wordKnownLevels === void 0 ? void 0 : wordKnownLevels.get(wordList)) || [];
143
+ if (start != undefined && !isNaN(start) && knownLevel.length != levels.length) {
82
144
  format.startNumberOverride = start;
83
145
  }
84
146
  }
85
147
  };
86
148
  }
87
- /**
88
- * Check whether the string is a fake bullet from word Desktop
89
- */
90
- function isFakeBullet(fakeBullet) {
91
- return ['o', '·', '§', '-'].indexOf(fakeBullet) >= 0;
92
- }
93
- /** Given a fake bullet text, returns the type of list that should be used for it */
94
- function getFakeBulletTagName(fakeBullet) {
95
- return isFakeBullet(fakeBullet) ? 'UL' : 'OL';
96
- }
97
- /**
98
- * Finds the fake bullet text out of the specified node and returns it. For images, it will return
99
- * a bullet string. If not found, it returns null...
100
- */
101
- function getFakeBulletText(node, levels) {
102
- var _a, _b;
103
- // Word uses the following format for their bullets:
104
- // &lt;p style="mso-list:l1 level1 lfo2"&gt;
105
- // &lt;span style="..."&gt;
106
- // &lt;span style="mso-list:Ignore"&gt;1.&lt;span style="..."&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/span&gt;&lt;/span&gt;
107
- // &lt;/span&gt;
108
- // Content here...
109
- // &lt;/p&gt;
110
- //
111
- // Basically, we need to locate the mso-list:Ignore SPAN, which holds either one text or image node. That
112
- // text or image node will be the fake bullet we are looking for
113
- var result = '';
114
- levels = levels || LOOKUP_DEPTH;
115
- var child = node.firstChild;
116
- while (!result && child) {
117
- // Check if this is the node that holds the fake bullets (mso-list: Ignore)
118
- if (isIgnoreNode(child)) {
119
- // Yes... this is the node that holds either the text or image data
120
- result = (_b = (_a = child.textContent) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : '';
121
- // This is the case for image case
122
- if (result.length == 0) {
123
- result = 'o';
124
- }
125
- }
126
- else if (isNodeOfType(child, 'ELEMENT_NODE') && levels > 1) {
127
- // If this is an element and we are not in the last level, try to get the fake bullet
128
- // out of the child
129
- result = getFakeBulletText(child, levels - 1);
130
- }
131
- child = child.nextSibling;
132
- }
133
- return result;
134
- }
135
- /**
136
- * Checks if the specified node is marked as a mso-list: Ignore. These
137
- * nodes need to be ignored when a list item is converted into standard
138
- * HTML lists
139
- */
140
- function isIgnoreNode(node) {
141
- if (isNodeOfType(node, 'ELEMENT_NODE')) {
142
- var listAttribute = getStyles(node)[MSO_LIST];
143
- if (listAttribute &&
144
- listAttribute.length > 0 &&
145
- listAttribute.trim().toLowerCase() == MSO_LIST_IGNORE) {
146
- return true;
147
- }
148
- }
149
- return false;
150
- }
151
149
  //# sourceMappingURL=processWordLists.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"processWordLists.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-plugins/lib/paste/WordDesktop/processWordLists.ts"],"names":[],"mappings":"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","sourcesContent":["import { getStyles } from '../utils/getStyles';\nimport {\n addBlock,\n createListItem,\n createListLevel,\n isNodeOfType,\n parseFormat,\n} from 'roosterjs-content-model-dom';\nimport type {\n ContentModelBlockGroup,\n ContentModelListItemLevelFormat,\n ContentModelListLevel,\n DomToModelContext,\n DomToModelListFormat,\n FormatParser,\n} from 'roosterjs-content-model-types';\n\n/** Word list metadata style name */\nconst MSO_LIST = 'mso-list';\nconst MSO_LIST_IGNORE = 'ignore';\nconst LOOKUP_DEPTH = 5;\nconst WORD_FIRST_LIST = 'l0';\n\ninterface WordDesktopListFormat extends DomToModelListFormat {\n wordLevel?: number | '';\n wordList?: string;\n wordKnownLevels?: Map<string, ContentModelListLevel[]>;\n}\n\n/**\n * @internal\n * @param styles\n * @param group\n * @param element\n * @param context\n * @returns\n */\nexport function processWordList(\n styles: Record<string, string>,\n group: ContentModelBlockGroup,\n element: HTMLElement,\n context: DomToModelContext\n) {\n const listFormat = context.listFormat as WordDesktopListFormat;\n if (!listFormat.wordKnownLevels) {\n listFormat.wordKnownLevels = new Map<string, ContentModelListLevel[]>();\n }\n const wordListStyle = styles[MSO_LIST] || '';\n\n // If the element contains Ignore style, do not process it,\n // Usually this element contains the fake bullet used in Word Desktop.\n if (wordListStyle.toLowerCase() === MSO_LIST_IGNORE) {\n return true;\n }\n\n const listProps = wordListStyle.split(' ');\n // Try get the list metadata from word, which follows this format: l1 level1 lfo2\n // If we are able to get the level property means we can process this element to be a list\n listFormat.wordLevel = listProps[1] && parseInt(listProps[1].substr('level'.length));\n\n listFormat.wordList = listProps[0] || WORD_FIRST_LIST;\n if (listFormat.levels.length == 0) {\n listFormat.levels = listFormat.wordKnownLevels.get(listFormat.wordList) || [];\n }\n\n if (wordListStyle && group && typeof listFormat.wordLevel === 'number') {\n const { wordLevel } = listFormat;\n // Retrieve the Fake bullet on the element and also the list type\n const fakeBullet = getFakeBulletText(element);\n const listType = getFakeBulletTagName(fakeBullet);\n\n // Create the new level of the list item and parse the format\n const newLevel: ContentModelListLevel = createListLevel(listType);\n parseFormat(element, context.formatParsers.listLevel, newLevel.format, context);\n\n // If the list format is in a different level, update the array so we get the new item\n // To be in the same level as the provided level metadata.\n if (wordLevel > listFormat.levels.length) {\n while (wordLevel != listFormat.levels.length) {\n listFormat.levels.push(newLevel);\n }\n } else {\n listFormat.levels.splice(wordLevel, listFormat.levels.length - 1);\n listFormat.levels[wordLevel - 1] = newLevel;\n }\n\n listFormat.listParent = group;\n\n processAsListItem(listFormat, context, element, group, fakeBullet);\n\n if (\n listFormat.levels.length > 0 &&\n listFormat.wordKnownLevels.get(listFormat.wordList) != listFormat.levels\n ) {\n listFormat.wordKnownLevels.set(listFormat.wordList, [...listFormat.levels]);\n }\n return true;\n }\n\n return false;\n}\n\nfunction processAsListItem(\n listFormat: WordDesktopListFormat,\n context: DomToModelContext,\n element: HTMLElement,\n group: ContentModelBlockGroup,\n fakeBullet: string\n) {\n const listItem = createListItem(listFormat.levels, context.segmentFormat);\n const lastLevel = listItem.levels[listItem.levels.length - 1];\n\n parseFormat(element, context.formatParsers.segmentOnBlock, context.segmentFormat, context);\n parseFormat(element, context.formatParsers.listItemElement, listItem.format, context);\n\n if (lastLevel?.listType == 'OL') {\n parseFormat(\n element,\n [startNumberOverrideParser(fakeBullet)],\n listItem.levels[listItem.levels.length - 1].format,\n context\n );\n }\n\n context.elementProcessors.child(listItem, element, context);\n addBlock(group, listItem);\n}\n\nfunction startNumberOverrideParser(\n fakeBullet: string\n): FormatParser<ContentModelListItemLevelFormat> | null {\n return (format, _, context) => {\n const {\n wordKnownLevels,\n wordLevel,\n wordList,\n } = context.listFormat as WordDesktopListFormat;\n if (typeof wordLevel === 'number' && wordList) {\n const start = parseInt(fakeBullet);\n if (start != undefined && !isNaN(start) && !wordKnownLevels?.has(wordList)) {\n format.startNumberOverride = start;\n }\n }\n };\n}\n\n/**\n * Check whether the string is a fake bullet from word Desktop\n */\nfunction isFakeBullet(fakeBullet: string): boolean {\n return ['o', '·', '§', '-'].indexOf(fakeBullet) >= 0;\n}\n\n/** Given a fake bullet text, returns the type of list that should be used for it */\nfunction getFakeBulletTagName(fakeBullet: string): 'UL' | 'OL' {\n return isFakeBullet(fakeBullet) ? 'UL' : 'OL';\n}\n\n/**\n * Finds the fake bullet text out of the specified node and returns it. For images, it will return\n * a bullet string. If not found, it returns null...\n */\nfunction getFakeBulletText(node: Node, levels?: number): string {\n // Word uses the following format for their bullets:\n // &lt;p style=\"mso-list:l1 level1 lfo2\"&gt;\n // &lt;span style=\"...\"&gt;\n // &lt;span style=\"mso-list:Ignore\"&gt;1.&lt;span style=\"...\"&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/span&gt;&lt;/span&gt;\n // &lt;/span&gt;\n // Content here...\n // &lt;/p&gt;\n //\n // Basically, we need to locate the mso-list:Ignore SPAN, which holds either one text or image node. That\n // text or image node will be the fake bullet we are looking for\n let result: string = '';\n levels = levels || LOOKUP_DEPTH;\n let child: Node | null = node.firstChild;\n while (!result && child) {\n // Check if this is the node that holds the fake bullets (mso-list: Ignore)\n if (isIgnoreNode(child)) {\n // Yes... this is the node that holds either the text or image data\n result = child.textContent?.trim() ?? '';\n\n // This is the case for image case\n if (result.length == 0) {\n result = 'o';\n }\n } else if (isNodeOfType(child, 'ELEMENT_NODE') && levels > 1) {\n // If this is an element and we are not in the last level, try to get the fake bullet\n // out of the child\n result = getFakeBulletText(child, levels - 1);\n }\n\n child = child.nextSibling;\n }\n\n return result;\n}\n/**\n * Checks if the specified node is marked as a mso-list: Ignore. These\n * nodes need to be ignored when a list item is converted into standard\n * HTML lists\n */\nfunction isIgnoreNode(node: Node): boolean {\n if (isNodeOfType(node, 'ELEMENT_NODE')) {\n const listAttribute = getStyles(node as HTMLElement)[MSO_LIST];\n if (\n listAttribute &&\n listAttribute.length > 0 &&\n listAttribute.trim().toLowerCase() == MSO_LIST_IGNORE\n ) {\n return true;\n }\n }\n\n return false;\n}\n"]}
1
+ {"version":3,"file":"processWordLists.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-plugins/lib/paste/WordDesktop/processWordLists.ts"],"names":[],"mappings":"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","sourcesContent":["import { getListStyleTypeFromString, updateListMetadata } from 'roosterjs-content-model-core';\nimport type { WordMetadata } from './WordMetadata';\nimport {\n addBlock,\n createListItem,\n createListLevel,\n parseFormat,\n} from 'roosterjs-content-model-dom';\nimport type {\n ContentModelBlockGroup,\n ContentModelListItemLevelFormat,\n ContentModelListLevel,\n DomToModelContext,\n DomToModelListFormat,\n FormatParser,\n} from 'roosterjs-content-model-types';\n\n/** Word list metadata style name */\nconst MSO_LIST = 'mso-list';\nconst MSO_LIST_IGNORE = 'ignore';\nconst WORD_FIRST_LIST = 'l0';\n\nconst TEMPLATE_VALUE_REGEX = /%[0-9a-zA-Z]+/g;\n\ninterface WordDesktopListFormat extends DomToModelListFormat {\n wordLevel?: number | '';\n wordList?: string;\n wordKnownLevels?: Map<string, ContentModelListLevel[]>;\n}\n\nconst BULLET_METADATA = 'bullet';\n/**\n * @internal\n * @param styles\n * @param group\n * @param element\n * @param context\n * @returns\n */\nexport function processWordList(\n styles: Record<string, string>,\n group: ContentModelBlockGroup,\n element: HTMLElement,\n context: DomToModelContext,\n metadata: Map<string, WordMetadata>\n) {\n const listFormat = context.listFormat as WordDesktopListFormat;\n if (!listFormat.wordKnownLevels) {\n listFormat.wordKnownLevels = new Map<string, ContentModelListLevel[]>();\n }\n const wordListStyle = styles[MSO_LIST] || '';\n\n // If the element contains Ignore style, do not process it,\n // Usually this element contains the fake bullet used in Word Desktop.\n if (wordListStyle.toLowerCase() === MSO_LIST_IGNORE) {\n return true;\n }\n\n const [lNumber, level] = wordListStyle.split(' ');\n // Try get the list metadata from word, which follows this format: l1 level1 lfo2\n // If we are able to get the level property means we can process this element to be a list\n listFormat.wordLevel = level && parseInt(level.substr('level'.length));\n\n listFormat.wordList = lNumber || WORD_FIRST_LIST;\n if (listFormat.levels.length == 0) {\n listFormat.levels =\n (listFormat.wordList && listFormat.wordKnownLevels.get(listFormat.wordList)) || [];\n }\n\n if (wordListStyle && group && typeof listFormat.wordLevel === 'number') {\n const { wordLevel, wordList } = listFormat;\n // Retrieve the Fake bullet on the element and also the list type\n const listMetadata = metadata.get(`${lNumber}:${level}`);\n const listType =\n listMetadata?.['mso-level-number-format']?.toLowerCase() != BULLET_METADATA\n ? 'OL'\n : 'UL';\n\n // Create the new level of the list item and parse the format\n const newLevel: ContentModelListLevel = createListLevel(listType);\n parseFormat(element, context.formatParsers.listLevel, newLevel.format, context);\n\n // If the list format is in a different level, update the array so we get the new item\n // To be in the same level as the provided level metadata.\n if (wordLevel > listFormat.levels.length) {\n while (wordLevel != listFormat.levels.length) {\n listFormat.levels.push(newLevel);\n }\n } else {\n listFormat.levels.splice(wordLevel, listFormat.levels.length - 1);\n listFormat.levels[wordLevel - 1] = newLevel;\n }\n\n listFormat.listParent = group;\n\n processAsListItem(listFormat, context, element, group, listMetadata);\n\n if (\n listFormat.levels.length > 0 &&\n listFormat.wordKnownLevels.get(wordList) != listFormat.levels\n ) {\n listFormat.wordKnownLevels.set(wordList, [...listFormat.levels]);\n }\n return true;\n }\n\n return false;\n}\n\nfunction processAsListItem(\n listFormat: WordDesktopListFormat,\n context: DomToModelContext,\n element: HTMLElement,\n group: ContentModelBlockGroup,\n listMetadata: WordMetadata | undefined\n) {\n const listLevel = listFormat.levels[listFormat.levels.length - 1];\n const { listType } = listLevel;\n const bullet = getBulletFromMetadata(listMetadata, listType);\n if (bullet) {\n updateListMetadata(listFormat.levels[listFormat.levels.length - 1], metadata =>\n Object.assign({}, metadata, {\n unorderedStyleType: listType == 'UL' ? bullet : undefined,\n orderedStyleType: listType == 'OL' ? bullet : undefined,\n })\n );\n }\n\n const listItem = createListItem(listFormat.levels, context.segmentFormat);\n\n parseFormat(element, context.formatParsers.segmentOnBlock, context.segmentFormat, context);\n parseFormat(element, context.formatParsers.listItemElement, listItem.format, context);\n\n if (listType == 'OL') {\n parseFormat(\n element,\n [startNumberOverrideParser(listMetadata)],\n listItem.levels[listItem.levels.length - 1].format,\n context\n );\n }\n\n context.elementProcessors.child(listItem, element, context);\n addBlock(group, listItem);\n}\n\nfunction getBulletFromMetadata(listMetadata: WordMetadata | undefined, listType: 'OL' | 'UL') {\n const templateType = listMetadata?.['mso-level-number-format'] || 'decimal';\n let templateFinal: string;\n\n if (listMetadata?.['mso-level-text']) {\n let templateValue: string = '';\n switch (templateType) {\n case 'alpha-upper':\n templateValue = 'UpperAlpha';\n break;\n case 'alpha-lower':\n templateValue = 'LowerAlpha';\n break;\n case 'roman-lower':\n templateValue = 'LowerRoman';\n break;\n case 'roman-upper':\n templateValue = 'UpperRoman';\n break;\n default:\n templateValue = 'Number';\n break;\n }\n const template = (listMetadata['mso-level-text'] || '')\n .replace('\\\\', '')\n .replace('\"', '')\n .replace(TEMPLATE_VALUE_REGEX, '${' + templateValue + '}');\n\n templateFinal = '\"' + template + ' \"';\n } else {\n switch (templateType) {\n case 'alpha-lower':\n templateFinal = 'lower-alpha';\n break;\n case 'roman-lower':\n templateFinal = 'lower-roman';\n break;\n case 'roman-upper':\n templateFinal = 'upper-roman';\n break;\n default:\n templateFinal = 'decimal';\n break;\n }\n }\n\n return getListStyleTypeFromString(listType, templateFinal);\n}\n\nfunction startNumberOverrideParser(\n listMetadata: WordMetadata | undefined\n): FormatParser<ContentModelListItemLevelFormat> | null {\n return (format, _, context) => {\n const {\n wordKnownLevels,\n wordLevel,\n wordList,\n levels,\n } = context.listFormat as WordDesktopListFormat;\n if (typeof wordLevel === 'number' && wordList) {\n const start = parseInt(listMetadata?.['mso-level-start-at'] || '1');\n const knownLevel = wordKnownLevels?.get(wordList) || [];\n\n if (start != undefined && !isNaN(start) && knownLevel.length != levels.length) {\n format.startNumberOverride = start;\n }\n }\n };\n}\n"]}
@@ -1,13 +1,4 @@
1
- var WORD_ONLINE_TABLE_TEMP_ELEMENT_CLASSES = [
2
- 'TableInsertRowGapBlank',
3
- 'TableColumnResizeHandle',
4
- 'TableCellTopBorderHandle',
5
- 'TableCellLeftBorderHandle',
6
- 'TableHoverColumnHandle',
7
- 'TableHoverRowHandle',
8
- ];
9
- var WAC_IDENTIFY_SELECTOR = 'ul[class^="BulletListStyle"]>.OutlineElement,ol[class^="NumberListStyle"]>.OutlineElement,span.WACImageContainer,' +
10
- WORD_ONLINE_TABLE_TEMP_ELEMENT_CLASSES.map(function (c) { return "table div[class^=\"" + c + "\"]"; }).join(',');
1
+ import { WAC_IDENTIFY_SELECTOR } from '../WacComponents/constants';
11
2
  /**
12
3
  * @internal
13
4
  * Check whether the fragment provided contain Wac Elements
@@ -1 +1 @@
1
- {"version":3,"file":"documentContainWacElements.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-plugins/lib/paste/pasteSourceValidations/documentContainWacElements.ts"],"names":[],"mappings":"AAEA,IAAM,sCAAsC,GAAG;IAC3C,wBAAwB;IACxB,yBAAyB;IACzB,0BAA0B;IAC1B,2BAA2B;IAC3B,wBAAwB;IACxB,qBAAqB;CACxB,CAAC;AAEF,IAAM,qBAAqB,GACvB,mHAAmH;IACnH,sCAAsC,CAAC,GAAG,CAAC,UAAA,CAAC,IAAI,OAAA,wBAAqB,CAAC,QAAI,EAA1B,CAA0B,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE1F;;;;;GAKG;AACH,MAAM,CAAC,IAAM,0BAA0B,GAAsB,UAAA,KAAK;IACtD,IAAA,QAAQ,GAAK,KAAK,SAAV,CAAW;IAC3B,OAAO,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC;AAC3D,CAAC,CAAC","sourcesContent":["import type { GetSourceFunction } from './getPasteSource';\n\nconst WORD_ONLINE_TABLE_TEMP_ELEMENT_CLASSES = [\n 'TableInsertRowGapBlank',\n 'TableColumnResizeHandle',\n 'TableCellTopBorderHandle',\n 'TableCellLeftBorderHandle',\n 'TableHoverColumnHandle',\n 'TableHoverRowHandle',\n];\n\nconst WAC_IDENTIFY_SELECTOR =\n 'ul[class^=\"BulletListStyle\"]>.OutlineElement,ol[class^=\"NumberListStyle\"]>.OutlineElement,span.WACImageContainer,' +\n WORD_ONLINE_TABLE_TEMP_ELEMENT_CLASSES.map(c => `table div[class^=\"${c}\"]`).join(',');\n\n/**\n * @internal\n * Check whether the fragment provided contain Wac Elements\n * @param props Properties related to the PasteEvent\n * @returns\n */\nexport const documentContainWacElements: GetSourceFunction = props => {\n const { fragment } = props;\n return !!fragment.querySelector(WAC_IDENTIFY_SELECTOR);\n};\n"]}
1
+ {"version":3,"file":"documentContainWacElements.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-plugins/lib/paste/pasteSourceValidations/documentContainWacElements.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAGnE;;;;;GAKG;AACH,MAAM,CAAC,IAAM,0BAA0B,GAAsB,UAAA,KAAK;IACtD,IAAA,QAAQ,GAAK,KAAK,SAAV,CAAW;IAC3B,OAAO,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC;AAC3D,CAAC,CAAC","sourcesContent":["import { WAC_IDENTIFY_SELECTOR } from '../WacComponents/constants';\nimport type { GetSourceFunction } from './getPasteSource';\n\n/**\n * @internal\n * Check whether the fragment provided contain Wac Elements\n * @param props Properties related to the PasteEvent\n * @returns\n */\nexport const documentContainWacElements: GetSourceFunction = props => {\n const { fragment } = props;\n return !!fragment.querySelector(WAC_IDENTIFY_SELECTOR);\n};\n"]}
@@ -1,4 +1,5 @@
1
- import type { BeforePasteEvent, ClipboardData } from 'roosterjs-editor-types';
1
+ import type { ClipboardData } from 'roosterjs-content-model-types';
2
+ import type { BeforePasteEvent } from 'roosterjs-editor-types';
2
3
  /**
3
4
  * @internal
4
5
  */
@@ -1 +1 @@
1
- {"version":3,"file":"getPasteSource.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-plugins/lib/paste/pasteSourceValidations/getPasteSource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAgC1E,IAAM,kBAAkB,GAAG,IAAI,GAAG,CAA0C;IACxE,CAAC,aAAa,EAAE,qBAAqB,CAAC;IACtC,CAAC,cAAc,EAAE,sBAAsB,CAAC;IACxC,CAAC,aAAa,EAAE,qBAAqB,CAAC;IACtC,CAAC,mBAAmB,EAAE,2BAA2B,CAAC;IAClD,CAAC,eAAe,EAAE,0BAA0B,CAAC;IAC7C,CAAC,cAAc,EAAE,qBAAqB,CAAC;IACvC,CAAC,aAAa,EAAE,0BAA0B,CAAC;CAC9C,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC1B,KAAuB,EACvB,wBAAiC;IAEzB,IAAA,cAAc,GAA8B,KAAK,eAAnC,EAAE,aAAa,GAAe,KAAK,cAApB,EAAE,QAAQ,GAAK,KAAK,SAAV,CAAW;IAE1D,IAAI,MAAM,GAAgC,IAAI,CAAC;IAC/C,IAAM,KAAK,GAAyB;QAChC,cAAc,gBAAA;QACd,QAAQ,UAAA;QACR,wBAAwB,0BAAA;QACxB,aAAa,eAAA;KAChB,CAAC;IAEF,kBAAkB,CAAC,OAAO,CAAC,UAAC,IAAI,EAAE,GAAG;QACjC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE;YACxB,MAAM,GAAG,GAAG,CAAC;SAChB;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,aAAN,MAAM,cAAN,MAAM,GAAI,SAAS,CAAC;AAC/B,CAAC","sourcesContent":["import { documentContainWacElements } from './documentContainWacElements';\nimport { isExcelDesktopDocument } from './isExcelDesktopDocument';\nimport { isExcelOnlineDocument } from './isExcelOnlineDocument';\nimport { isGoogleSheetDocument } from './isGoogleSheetDocument';\nimport { isPowerPointDesktopDocument } from './isPowerPointDesktopDocument';\nimport { isWordDesktopDocument } from './isWordDesktopDocument';\nimport { shouldConvertToSingleImage } from './shouldConvertToSingleImage';\nimport type { BeforePasteEvent, ClipboardData } from 'roosterjs-editor-types';\n\n/**\n * @internal\n */\nexport type GetSourceInputParams = {\n htmlAttributes: Record<string, string>;\n fragment: DocumentFragment;\n shouldConvertSingleImage: boolean;\n clipboardData: ClipboardData;\n};\n\n/**\n * @internal\n * Represent the types of sources to handle in the Paste Plugin\n */\nexport type KnownPasteSourceType =\n | 'wordDesktop'\n | 'excelDesktop'\n | 'excelOnline'\n | 'powerPointDesktop'\n | 'googleSheets'\n | 'wacComponents'\n | 'default'\n | 'singleImage';\n\n/**\n * @internal\n */\nexport type GetSourceFunction = (props: GetSourceInputParams) => boolean;\n\nconst getSourceFunctions = new Map<KnownPasteSourceType, GetSourceFunction>([\n ['wordDesktop', isWordDesktopDocument],\n ['excelDesktop', isExcelDesktopDocument],\n ['excelOnline', isExcelOnlineDocument],\n ['powerPointDesktop', isPowerPointDesktopDocument],\n ['wacComponents', documentContainWacElements],\n ['googleSheets', isGoogleSheetDocument],\n ['singleImage', shouldConvertToSingleImage],\n]);\n\n/**\n * @internal\n * This function tries to get the source of the Pasted content\n * @param event the before paste event\n * @param shouldConvertSingleImage Whether convert single image is enabled.\n * @returns The Type of pasted content, if no type found will return {KnownSourceType.Default}\n */\nexport function getPasteSource(\n event: BeforePasteEvent,\n shouldConvertSingleImage: boolean\n): KnownPasteSourceType {\n const { htmlAttributes, clipboardData, fragment } = event;\n\n let result: KnownPasteSourceType | null = null;\n const param: GetSourceInputParams = {\n htmlAttributes,\n fragment,\n shouldConvertSingleImage,\n clipboardData,\n };\n\n getSourceFunctions.forEach((func, key) => {\n if (!result && func(param)) {\n result = key;\n }\n });\n\n return result ?? 'default';\n}\n"]}
1
+ {"version":3,"file":"getPasteSource.js","sourceRoot":"","sources":["../../../../../packages-content-model/roosterjs-content-model-plugins/lib/paste/pasteSourceValidations/getPasteSource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAiC1E,IAAM,kBAAkB,GAAG,IAAI,GAAG,CAA0C;IACxE,CAAC,aAAa,EAAE,qBAAqB,CAAC;IACtC,CAAC,cAAc,EAAE,sBAAsB,CAAC;IACxC,CAAC,aAAa,EAAE,qBAAqB,CAAC;IACtC,CAAC,mBAAmB,EAAE,2BAA2B,CAAC;IAClD,CAAC,eAAe,EAAE,0BAA0B,CAAC;IAC7C,CAAC,cAAc,EAAE,qBAAqB,CAAC;IACvC,CAAC,aAAa,EAAE,0BAA0B,CAAC;CAC9C,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC1B,KAAuB,EACvB,wBAAiC;IAEzB,IAAA,cAAc,GAA8B,KAAK,eAAnC,EAAE,aAAa,GAAe,KAAK,cAApB,EAAE,QAAQ,GAAK,KAAK,SAAV,CAAW;IAE1D,IAAI,MAAM,GAAgC,IAAI,CAAC;IAC/C,IAAM,KAAK,GAAyB;QAChC,cAAc,gBAAA;QACd,QAAQ,UAAA;QACR,wBAAwB,0BAAA;QACxB,aAAa,eAAA;KAChB,CAAC;IAEF,kBAAkB,CAAC,OAAO,CAAC,UAAC,IAAI,EAAE,GAAG;QACjC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE;YACxB,MAAM,GAAG,GAAG,CAAC;SAChB;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,aAAN,MAAM,cAAN,MAAM,GAAI,SAAS,CAAC;AAC/B,CAAC","sourcesContent":["import { documentContainWacElements } from './documentContainWacElements';\nimport { isExcelDesktopDocument } from './isExcelDesktopDocument';\nimport { isExcelOnlineDocument } from './isExcelOnlineDocument';\nimport { isGoogleSheetDocument } from './isGoogleSheetDocument';\nimport { isPowerPointDesktopDocument } from './isPowerPointDesktopDocument';\nimport { isWordDesktopDocument } from './isWordDesktopDocument';\nimport { shouldConvertToSingleImage } from './shouldConvertToSingleImage';\nimport type { ClipboardData } from 'roosterjs-content-model-types';\nimport type { BeforePasteEvent } from 'roosterjs-editor-types';\n\n/**\n * @internal\n */\nexport type GetSourceInputParams = {\n htmlAttributes: Record<string, string>;\n fragment: DocumentFragment;\n shouldConvertSingleImage: boolean;\n clipboardData: ClipboardData;\n};\n\n/**\n * @internal\n * Represent the types of sources to handle in the Paste Plugin\n */\nexport type KnownPasteSourceType =\n | 'wordDesktop'\n | 'excelDesktop'\n | 'excelOnline'\n | 'powerPointDesktop'\n | 'googleSheets'\n | 'wacComponents'\n | 'default'\n | 'singleImage';\n\n/**\n * @internal\n */\nexport type GetSourceFunction = (props: GetSourceInputParams) => boolean;\n\nconst getSourceFunctions = new Map<KnownPasteSourceType, GetSourceFunction>([\n ['wordDesktop', isWordDesktopDocument],\n ['excelDesktop', isExcelDesktopDocument],\n ['excelOnline', isExcelOnlineDocument],\n ['powerPointDesktop', isPowerPointDesktopDocument],\n ['wacComponents', documentContainWacElements],\n ['googleSheets', isGoogleSheetDocument],\n ['singleImage', shouldConvertToSingleImage],\n]);\n\n/**\n * @internal\n * This function tries to get the source of the Pasted content\n * @param event the before paste event\n * @param shouldConvertSingleImage Whether convert single image is enabled.\n * @returns The Type of pasted content, if no type found will return {KnownSourceType.Default}\n */\nexport function getPasteSource(\n event: BeforePasteEvent,\n shouldConvertSingleImage: boolean\n): KnownPasteSourceType {\n const { htmlAttributes, clipboardData, fragment } = event;\n\n let result: KnownPasteSourceType | null = null;\n const param: GetSourceInputParams = {\n htmlAttributes,\n fragment,\n shouldConvertSingleImage,\n clipboardData,\n };\n\n getSourceFunctions.forEach((func, key) => {\n if (!result && func(param)) {\n result = key;\n }\n });\n\n return result ?? 'default';\n}\n"]}
package/package.json CHANGED
@@ -5,12 +5,12 @@
5
5
  "tslib": "^2.3.1",
6
6
  "roosterjs-editor-types": "^8.59.0",
7
7
  "roosterjs-editor-dom": "^8.59.0",
8
- "roosterjs-content-model-core": "^0.21.2",
9
- "roosterjs-content-model-editor": "^0.21.2",
10
- "roosterjs-content-model-dom": "^0.21.2",
11
- "roosterjs-content-model-types": "^0.21.2"
8
+ "roosterjs-content-model-core": "^0.22.0",
9
+ "roosterjs-content-model-editor": "^0.22.0",
10
+ "roosterjs-content-model-dom": "^0.22.0",
11
+ "roosterjs-content-model-types": "^0.22.0"
12
12
  },
13
- "version": "0.21.3",
13
+ "version": "0.22.0",
14
14
  "main": "./lib/index.js",
15
15
  "typings": "./lib/index.d.ts",
16
16
  "module": "./lib-mjs/index.js",