roosterjs-content-model-plugins 9.19.0 → 9.20.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 (34) hide show
  1. package/lib/paste/Excel/processPastedContentFromExcel.d.ts +14 -6
  2. package/lib/paste/Excel/processPastedContentFromExcel.js +47 -31
  3. package/lib/paste/Excel/processPastedContentFromExcel.js.map +1 -1
  4. package/lib/paste/PastePlugin.js +2 -1
  5. package/lib/paste/PastePlugin.js.map +1 -1
  6. package/lib/paste/pasteSourceValidations/getPasteSource.d.ts +1 -1
  7. package/lib/paste/pasteSourceValidations/getPasteSource.js +2 -0
  8. package/lib/paste/pasteSourceValidations/getPasteSource.js.map +1 -1
  9. package/lib/paste/pasteSourceValidations/isExcelNonNativeEvent.d.ts +7 -0
  10. package/lib/paste/pasteSourceValidations/isExcelNonNativeEvent.js +18 -0
  11. package/lib/paste/pasteSourceValidations/isExcelNonNativeEvent.js.map +1 -0
  12. package/lib-amd/paste/Excel/processPastedContentFromExcel.d.ts +14 -6
  13. package/lib-amd/paste/Excel/processPastedContentFromExcel.js +47 -31
  14. package/lib-amd/paste/Excel/processPastedContentFromExcel.js.map +1 -1
  15. package/lib-amd/paste/PastePlugin.js +2 -1
  16. package/lib-amd/paste/PastePlugin.js.map +1 -1
  17. package/lib-amd/paste/pasteSourceValidations/getPasteSource.d.ts +1 -1
  18. package/lib-amd/paste/pasteSourceValidations/getPasteSource.js +2 -1
  19. package/lib-amd/paste/pasteSourceValidations/getPasteSource.js.map +1 -1
  20. package/lib-amd/paste/pasteSourceValidations/isExcelNonNativeEvent.d.ts +7 -0
  21. package/lib-amd/paste/pasteSourceValidations/isExcelNonNativeEvent.js +20 -0
  22. package/lib-amd/paste/pasteSourceValidations/isExcelNonNativeEvent.js.map +1 -0
  23. package/lib-mjs/paste/Excel/processPastedContentFromExcel.d.ts +14 -6
  24. package/lib-mjs/paste/Excel/processPastedContentFromExcel.js +44 -29
  25. package/lib-mjs/paste/Excel/processPastedContentFromExcel.js.map +1 -1
  26. package/lib-mjs/paste/PastePlugin.js +2 -1
  27. package/lib-mjs/paste/PastePlugin.js.map +1 -1
  28. package/lib-mjs/paste/pasteSourceValidations/getPasteSource.d.ts +1 -1
  29. package/lib-mjs/paste/pasteSourceValidations/getPasteSource.js +2 -0
  30. package/lib-mjs/paste/pasteSourceValidations/getPasteSource.js.map +1 -1
  31. package/lib-mjs/paste/pasteSourceValidations/isExcelNonNativeEvent.d.ts +7 -0
  32. package/lib-mjs/paste/pasteSourceValidations/isExcelNonNativeEvent.js +14 -0
  33. package/lib-mjs/paste/pasteSourceValidations/isExcelNonNativeEvent.js.map +1 -0
  34. package/package.json +5 -5
@@ -3,13 +3,11 @@ import type { BeforePasteEvent, ClipboardData, DOMCreator, ElementProcessor } fr
3
3
  * @internal
4
4
  * Convert pasted content from Excel, add borders when source doc doesn't have a border
5
5
  * @param event The BeforePaste event
6
+ * @param domCreator The DOM creator
7
+ * @param allowExcelNoBorderTable Allow table copied from Excel without border
8
+ * @param isNativeEvent Whether the event is native event
6
9
  */
7
- export declare function processPastedContentFromExcel(event: BeforePasteEvent, domCreator: DOMCreator, allowExcelNoBorderTable?: boolean): void;
8
- /**
9
- * @internal
10
- * Exported only for unit test
11
- */
12
- export declare const childProcessor: ElementProcessor<ParentNode>;
10
+ export declare function processPastedContentFromExcel(event: BeforePasteEvent, domCreator: DOMCreator, allowExcelNoBorderTable: boolean, isNativeEvent: boolean): void;
13
11
  /**
14
12
  * @internal
15
13
  * Exported only for unit test
@@ -20,3 +18,13 @@ export declare function validateExcelFragment(fragment: DocumentFragment, domCre
20
18
  * @param html Source html
21
19
  */
22
20
  export declare function excelHandler(html: string, htmlBefore: string): string;
21
+ /**
22
+ * @internal
23
+ * Exported only for unit test
24
+ */
25
+ export declare function setupExcelTableHandlers(event: BeforePasteEvent, allowExcelNoBorderTable: boolean | undefined, isNativeEvent: boolean): void;
26
+ /**
27
+ * @internal
28
+ * Exported only for unit test
29
+ */
30
+ export declare const childProcessor: ElementProcessor<ParentNode>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.excelHandler = exports.validateExcelFragment = exports.childProcessor = exports.processPastedContentFromExcel = void 0;
3
+ exports.childProcessor = exports.setupExcelTableHandlers = exports.excelHandler = exports.validateExcelFragment = exports.processPastedContentFromExcel = void 0;
4
4
  var tslib_1 = require("tslib");
5
5
  var addParser_1 = require("../utils/addParser");
6
6
  var roosterjs_content_model_dom_1 = require("roosterjs-content-model-dom");
@@ -9,16 +9,22 @@ var LAST_TD_END_REGEX = /<\/\s*td\s*>((?!<\/\s*tr\s*>)[\s\S])*$/i;
9
9
  var LAST_TR_END_REGEX = /<\/\s*tr\s*>((?!<\/\s*table\s*>)[\s\S])*$/i;
10
10
  var LAST_TR_REGEX = /<tr[^>]*>[^<]*/i;
11
11
  var LAST_TABLE_REGEX = /<table[^>]*>[^<]*/i;
12
- var DEFAULT_BORDER_STYLE = 'solid 1px #d4d4d4';
13
12
  var TABLE_SELECTOR = 'table';
13
+ var DEFAULT_BORDER_STYLE = 'solid 1px #d4d4d4';
14
14
  /**
15
15
  * @internal
16
16
  * Convert pasted content from Excel, add borders when source doc doesn't have a border
17
17
  * @param event The BeforePaste event
18
+ * @param domCreator The DOM creator
19
+ * @param allowExcelNoBorderTable Allow table copied from Excel without border
20
+ * @param isNativeEvent Whether the event is native event
18
21
  */
19
- function processPastedContentFromExcel(event, domCreator, allowExcelNoBorderTable) {
22
+ function processPastedContentFromExcel(event, domCreator, allowExcelNoBorderTable, isNativeEvent) {
20
23
  var fragment = event.fragment, htmlBefore = event.htmlBefore, htmlAfter = event.htmlAfter, clipboardData = event.clipboardData;
21
- validateExcelFragment(fragment, domCreator, htmlBefore, clipboardData, htmlAfter);
24
+ // For non native event we already validated that the content contains a table
25
+ if (isNativeEvent) {
26
+ validateExcelFragment(fragment, domCreator, htmlBefore, clipboardData, htmlAfter);
27
+ }
22
28
  // For Excel Online
23
29
  var firstChild = fragment.firstChild;
24
30
  if ((0, roosterjs_content_model_dom_1.isNodeOfType)(firstChild, 'ELEMENT_NODE') &&
@@ -38,35 +44,9 @@ function processPastedContentFromExcel(event, domCreator, allowExcelNoBorderTabl
38
44
  event.fragment.replaceChildren(firstChild.lastChild);
39
45
  }
40
46
  }
41
- (0, addParser_1.addParser)(event.domToModelOption, 'tableCell', function (format, element) {
42
- if (!allowExcelNoBorderTable && element.style.borderStyle === 'none') {
43
- format.borderBottom = DEFAULT_BORDER_STYLE;
44
- format.borderLeft = DEFAULT_BORDER_STYLE;
45
- format.borderRight = DEFAULT_BORDER_STYLE;
46
- format.borderTop = DEFAULT_BORDER_STYLE;
47
- }
48
- });
49
- (0, setProcessor_1.setProcessor)(event.domToModelOption, 'child', exports.childProcessor);
47
+ setupExcelTableHandlers(event, allowExcelNoBorderTable, isNativeEvent /* handleForNativeEvent */);
50
48
  }
51
49
  exports.processPastedContentFromExcel = processPastedContentFromExcel;
52
- /**
53
- * @internal
54
- * Exported only for unit test
55
- */
56
- var childProcessor = function (group, element, context) {
57
- var segmentFormat = (0, tslib_1.__assign)({}, context.segmentFormat);
58
- if (group.blockGroupType === 'TableCell' &&
59
- group.format.textColor &&
60
- !context.segmentFormat.textColor) {
61
- context.segmentFormat.textColor = group.format.textColor;
62
- }
63
- context.defaultElementProcessors.child(group, element, context);
64
- if (group.blockGroupType === 'TableCell' && group.format.textColor) {
65
- context.segmentFormat = segmentFormat;
66
- delete group.format.textColor;
67
- }
68
- };
69
- exports.childProcessor = childProcessor;
70
50
  /**
71
51
  * @internal
72
52
  * Exported only for unit test
@@ -122,4 +102,40 @@ function excelHandler(html, htmlBefore) {
122
102
  }
123
103
  }
124
104
  exports.excelHandler = excelHandler;
105
+ /**
106
+ * @internal
107
+ * Exported only for unit test
108
+ */
109
+ function setupExcelTableHandlers(event, allowExcelNoBorderTable, isNativeEvent) {
110
+ (0, addParser_1.addParser)(event.domToModelOption, 'tableCell', function (format, element) {
111
+ if (!allowExcelNoBorderTable &&
112
+ (element.style.borderStyle === 'none' ||
113
+ (!isNativeEvent && element.style.borderStyle == ''))) {
114
+ format.borderBottom = DEFAULT_BORDER_STYLE;
115
+ format.borderLeft = DEFAULT_BORDER_STYLE;
116
+ format.borderRight = DEFAULT_BORDER_STYLE;
117
+ format.borderTop = DEFAULT_BORDER_STYLE;
118
+ }
119
+ });
120
+ (0, setProcessor_1.setProcessor)(event.domToModelOption, 'child', exports.childProcessor);
121
+ }
122
+ exports.setupExcelTableHandlers = setupExcelTableHandlers;
123
+ /**
124
+ * @internal
125
+ * Exported only for unit test
126
+ */
127
+ var childProcessor = function (group, element, context) {
128
+ var segmentFormat = (0, tslib_1.__assign)({}, context.segmentFormat);
129
+ if (group.blockGroupType === 'TableCell' &&
130
+ group.format.textColor &&
131
+ !context.segmentFormat.textColor) {
132
+ context.segmentFormat.textColor = group.format.textColor;
133
+ }
134
+ context.defaultElementProcessors.child(group, element, context);
135
+ if (group.blockGroupType === 'TableCell' && group.format.textColor) {
136
+ context.segmentFormat = segmentFormat;
137
+ delete group.format.textColor;
138
+ }
139
+ };
140
+ exports.childProcessor = childProcessor;
125
141
  //# sourceMappingURL=processPastedContentFromExcel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"processPastedContentFromExcel.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/paste/Excel/processPastedContentFromExcel.ts"],"names":[],"mappings":";;;;AAAA,gDAA+C;AAC/C,2EAA2E;AAC3E,sDAAqD;AAQrD,IAAM,iBAAiB,GAAG,yCAAyC,CAAC;AACpE,IAAM,iBAAiB,GAAG,4CAA4C,CAAC;AACvE,IAAM,aAAa,GAAG,iBAAiB,CAAC;AACxC,IAAM,gBAAgB,GAAG,oBAAoB,CAAC;AAC9C,IAAM,oBAAoB,GAAG,mBAAmB,CAAC;AACjD,IAAM,cAAc,GAAG,OAAO,CAAC;AAE/B;;;;GAIG;AAEH,SAAgB,6BAA6B,CACzC,KAAuB,EACvB,UAAsB,EACtB,uBAAiC;IAEzB,IAAA,QAAQ,GAA2C,KAAK,SAAhD,EAAE,UAAU,GAA+B,KAAK,WAApC,EAAE,SAAS,GAAoB,KAAK,UAAzB,EAAE,aAAa,GAAK,KAAK,cAAV,CAAW;IAEjE,qBAAqB,CAAC,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC;IAElF,mBAAmB;IACnB,IAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC;IACvC,IACI,IAAA,0CAAY,EAAC,UAAU,EAAE,cAAc,CAAC;QACxC,UAAU,CAAC,OAAO,IAAI,KAAK;QAC3B,UAAU,CAAC,UAAU,EACvB;QACE,IAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,UAAC,KAAW;YACnE,4FAA4F;YAC5F,IAAM,OAAO,GAAG,IAAA,0CAAY,EAAC,KAAK,EAAE,cAAc,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC;YAErE,OAAO,OAAO,IAAI,MAAM;gBACpB,CAAC,CAAC,IAAI;gBACN,CAAC,CAAC,OAAO,IAAI,OAAO;oBACpB,CAAC,CAAC,KAAK,IAAI,UAAU,CAAC,SAAS;oBAC/B,CAAC,CAAC,KAAK,CAAC;QAChB,CAAC,CAAC,CAAC;QAEH,yBAAyB;QACzB,IAAI,UAAU,IAAI,UAAU,CAAC,SAAS,EAAE;YACpC,KAAK,CAAC,QAAQ,CAAC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;SACxD;KACJ;IAED,IAAA,qBAAS,EAAC,KAAK,CAAC,gBAAgB,EAAE,WAAW,EAAE,UAAC,MAAM,EAAE,OAAO;QAC3D,IAAI,CAAC,uBAAuB,IAAI,OAAO,CAAC,KAAK,CAAC,WAAW,KAAK,MAAM,EAAE;YAClE,MAAM,CAAC,YAAY,GAAG,oBAAoB,CAAC;YAC3C,MAAM,CAAC,UAAU,GAAG,oBAAoB,CAAC;YACzC,MAAM,CAAC,WAAW,GAAG,oBAAoB,CAAC;YAC1C,MAAM,CAAC,SAAS,GAAG,oBAAoB,CAAC;SAC3C;IACL,CAAC,CAAC,CAAC;IAEH,IAAA,2BAAY,EAAC,KAAK,CAAC,gBAAgB,EAAE,OAAO,EAAE,sBAAc,CAAC,CAAC;AAClE,CAAC;AA3CD,sEA2CC;AAED;;;GAGG;AACI,IAAM,cAAc,GAAiC,UAAC,KAAK,EAAE,OAAO,EAAE,OAAO;IAChF,IAAM,aAAa,6BAAQ,OAAO,CAAC,aAAa,CAAE,CAAC;IACnD,IACI,KAAK,CAAC,cAAc,KAAK,WAAW;QACpC,KAAK,CAAC,MAAM,CAAC,SAAS;QACtB,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,EAClC;QACE,OAAO,CAAC,aAAa,CAAC,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC;KAC5D;IAED,OAAO,CAAC,wBAAwB,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAEhE,IAAI,KAAK,CAAC,cAAc,KAAK,WAAW,IAAI,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE;QAChE,OAAO,CAAC,aAAa,GAAG,aAAa,CAAC;QACtC,OAAO,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC;KACjC;AACL,CAAC,CAAC;AAhBW,QAAA,cAAc,kBAgBzB;AAEF;;;GAGG;AACH,SAAgB,qBAAqB,CACjC,QAA0B,EAC1B,UAAsB,EACtB,UAAkB,EAClB,aAA4B,EAC5B,SAAiB;IAEjB,2GAA2G;IAC3G,EAAE;IACF,WAAW;IACX,UAAU;IACV,uBAAuB;IACvB,eAAe;IACf,qBAAqB;IACrB,WAAW;IACX,EAAE;IACF,wFAAwF;IACxF,yHAAyH;IACzH,+GAA+G;IAC/G,kEAAkE;IAClE,IAAM,MAAM,GACR,CAAC,QAAQ,CAAC,aAAa,CAAC,cAAc,CAAC;QACvC,UAAU,CAAC,SAAS,CAAC,UAAU,GAAG,aAAa,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC;IACtE,IAAI,MAAM,IAAI,MAAM,CAAC,aAAa,CAAC,cAAc,CAAC,EAAE;QAChD,IAAA,4CAAc,EAAC,QAAQ,EAAE,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,IAAI,CAAC,CAAC;KAC1C;SAAM;QACH,gGAAgG;QAChG,IAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAE3F,IAAI,IAAI,IAAI,aAAa,CAAC,IAAI,IAAI,IAAI,EAAE;YACpC,IAAM,GAAG,GAAG,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACvC,IAAA,4CAAc,EAAC,QAAQ,EAAE,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAE,IAAI,CAAC,CAAC;SACvC;KACJ;AACL,CAAC;AAlCD,sDAkCC;AAED;;;GAGG;AACH,SAAgB,YAAY,CAAC,IAAY,EAAE,UAAkB;IACzD,IAAI;QACA,IAAI,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE;YAC/B,IAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;YAChD,IAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YACzC,IAAI,GAAG,EAAE,GAAG,IAAI,GAAG,OAAO,CAAC;SAC9B;QACD,IAAI,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE;YAC/B,IAAM,UAAU,GAAG,UAAU,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;YACtD,IAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACrD,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,UAAU,CAAC;SACpC;KACJ;YAAS;QACN,OAAO,IAAI,CAAC;KACf;AACL,CAAC;AAfD,oCAeC","sourcesContent":["import { addParser } from '../utils/addParser';\nimport { isNodeOfType, moveChildNodes } from 'roosterjs-content-model-dom';\nimport { setProcessor } from '../utils/setProcessor';\nimport type {\n BeforePasteEvent,\n ClipboardData,\n DOMCreator,\n ElementProcessor,\n} from 'roosterjs-content-model-types';\n\nconst LAST_TD_END_REGEX = /<\\/\\s*td\\s*>((?!<\\/\\s*tr\\s*>)[\\s\\S])*$/i;\nconst LAST_TR_END_REGEX = /<\\/\\s*tr\\s*>((?!<\\/\\s*table\\s*>)[\\s\\S])*$/i;\nconst LAST_TR_REGEX = /<tr[^>]*>[^<]*/i;\nconst LAST_TABLE_REGEX = /<table[^>]*>[^<]*/i;\nconst DEFAULT_BORDER_STYLE = 'solid 1px #d4d4d4';\nconst TABLE_SELECTOR = 'table';\n\n/**\n * @internal\n * Convert pasted content from Excel, add borders when source doc doesn't have a border\n * @param event The BeforePaste event\n */\n\nexport function processPastedContentFromExcel(\n event: BeforePasteEvent,\n domCreator: DOMCreator,\n allowExcelNoBorderTable?: boolean\n) {\n const { fragment, htmlBefore, htmlAfter, clipboardData } = event;\n\n validateExcelFragment(fragment, domCreator, htmlBefore, clipboardData, htmlAfter);\n\n // For Excel Online\n const firstChild = fragment.firstChild;\n if (\n isNodeOfType(firstChild, 'ELEMENT_NODE') &&\n firstChild.tagName == 'div' &&\n firstChild.firstChild\n ) {\n const tableFound = Array.from(firstChild.childNodes).every((child: Node) => {\n // Tables pasted from Excel Online should be of the format: 0 to N META tags and 1 TABLE tag\n const tagName = isNodeOfType(child, 'ELEMENT_NODE') && child.tagName;\n\n return tagName == 'META'\n ? true\n : tagName == 'TABLE'\n ? child == firstChild.lastChild\n : false;\n });\n\n // Extract Table from Div\n if (tableFound && firstChild.lastChild) {\n event.fragment.replaceChildren(firstChild.lastChild);\n }\n }\n\n addParser(event.domToModelOption, 'tableCell', (format, element) => {\n if (!allowExcelNoBorderTable && element.style.borderStyle === 'none') {\n format.borderBottom = DEFAULT_BORDER_STYLE;\n format.borderLeft = DEFAULT_BORDER_STYLE;\n format.borderRight = DEFAULT_BORDER_STYLE;\n format.borderTop = DEFAULT_BORDER_STYLE;\n }\n });\n\n setProcessor(event.domToModelOption, 'child', childProcessor);\n}\n\n/**\n * @internal\n * Exported only for unit test\n */\nexport const childProcessor: ElementProcessor<ParentNode> = (group, element, context) => {\n const segmentFormat = { ...context.segmentFormat };\n if (\n group.blockGroupType === 'TableCell' &&\n group.format.textColor &&\n !context.segmentFormat.textColor\n ) {\n context.segmentFormat.textColor = group.format.textColor;\n }\n\n context.defaultElementProcessors.child(group, element, context);\n\n if (group.blockGroupType === 'TableCell' && group.format.textColor) {\n context.segmentFormat = segmentFormat;\n delete group.format.textColor;\n }\n};\n\n/**\n * @internal\n * Exported only for unit test\n */\nexport function validateExcelFragment(\n fragment: DocumentFragment,\n domCreator: DOMCreator,\n htmlBefore: string,\n clipboardData: ClipboardData,\n htmlAfter: string\n) {\n // Clipboard content of Excel may contain the <StartFragment> and EndFragment comment tags inside the table\n //\n // @example\n // <table>\n // <!--StartFragment-->\n // <tr>...</tr>\n // <!--EndFragment-->\n // </table>\n //\n // This causes that the fragment is not properly created and the table is not extracted.\n // The content that is before the StartFragment is htmlBefore and the content that is after the EndFragment is htmlAfter.\n // So attempt to create a new document fragment with the content of htmlBefore + clipboardData.html + htmlAfter\n // If a table is found, replace the fragment with the new fragment\n const result =\n !fragment.querySelector(TABLE_SELECTOR) &&\n domCreator.htmlToDOM(htmlBefore + clipboardData.html + htmlAfter);\n if (result && result.querySelector(TABLE_SELECTOR)) {\n moveChildNodes(fragment, result?.body);\n } else {\n // If the table is still not found, try to extract the table from the clipboard data using Regex\n const html = clipboardData.html ? excelHandler(clipboardData.html, htmlBefore) : undefined;\n\n if (html && clipboardData.html != html) {\n const doc = domCreator.htmlToDOM(html);\n moveChildNodes(fragment, doc?.body);\n }\n }\n}\n\n/**\n * @internal Export for test only\n * @param html Source html\n */\nexport function excelHandler(html: string, htmlBefore: string): string {\n try {\n if (html.match(LAST_TD_END_REGEX)) {\n const trMatch = htmlBefore.match(LAST_TR_REGEX);\n const tr = trMatch ? trMatch[0] : '<TR>';\n html = tr + html + '</TR>';\n }\n if (html.match(LAST_TR_END_REGEX)) {\n const tableMatch = htmlBefore.match(LAST_TABLE_REGEX);\n const table = tableMatch ? tableMatch[0] : '<TABLE>';\n html = table + html + '</TABLE>';\n }\n } finally {\n return html;\n }\n}\n"]}
1
+ {"version":3,"file":"processPastedContentFromExcel.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/paste/Excel/processPastedContentFromExcel.ts"],"names":[],"mappings":"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","sourcesContent":["import { addParser } from '../utils/addParser';\nimport { isNodeOfType, moveChildNodes } from 'roosterjs-content-model-dom';\nimport { setProcessor } from '../utils/setProcessor';\nimport type {\n BeforePasteEvent,\n ClipboardData,\n DOMCreator,\n ElementProcessor,\n} from 'roosterjs-content-model-types';\n\nconst LAST_TD_END_REGEX = /<\\/\\s*td\\s*>((?!<\\/\\s*tr\\s*>)[\\s\\S])*$/i;\nconst LAST_TR_END_REGEX = /<\\/\\s*tr\\s*>((?!<\\/\\s*table\\s*>)[\\s\\S])*$/i;\nconst LAST_TR_REGEX = /<tr[^>]*>[^<]*/i;\nconst LAST_TABLE_REGEX = /<table[^>]*>[^<]*/i;\nconst TABLE_SELECTOR = 'table';\nconst DEFAULT_BORDER_STYLE = 'solid 1px #d4d4d4';\n\n/**\n * @internal\n * Convert pasted content from Excel, add borders when source doc doesn't have a border\n * @param event The BeforePaste event\n * @param domCreator The DOM creator\n * @param allowExcelNoBorderTable Allow table copied from Excel without border\n * @param isNativeEvent Whether the event is native event\n */\nexport function processPastedContentFromExcel(\n event: BeforePasteEvent,\n domCreator: DOMCreator,\n allowExcelNoBorderTable: boolean,\n isNativeEvent: boolean\n) {\n const { fragment, htmlBefore, htmlAfter, clipboardData } = event;\n\n // For non native event we already validated that the content contains a table\n if (isNativeEvent) {\n validateExcelFragment(fragment, domCreator, htmlBefore, clipboardData, htmlAfter);\n }\n\n // For Excel Online\n const firstChild = fragment.firstChild;\n if (\n isNodeOfType(firstChild, 'ELEMENT_NODE') &&\n firstChild.tagName == 'div' &&\n firstChild.firstChild\n ) {\n const tableFound = Array.from(firstChild.childNodes).every((child: Node) => {\n // Tables pasted from Excel Online should be of the format: 0 to N META tags and 1 TABLE tag\n const tagName = isNodeOfType(child, 'ELEMENT_NODE') && child.tagName;\n\n return tagName == 'META'\n ? true\n : tagName == 'TABLE'\n ? child == firstChild.lastChild\n : false;\n });\n\n // Extract Table from Div\n if (tableFound && firstChild.lastChild) {\n event.fragment.replaceChildren(firstChild.lastChild);\n }\n }\n\n setupExcelTableHandlers(\n event,\n allowExcelNoBorderTable,\n isNativeEvent /* handleForNativeEvent */\n );\n}\n\n/**\n * @internal\n * Exported only for unit test\n */\nexport function validateExcelFragment(\n fragment: DocumentFragment,\n domCreator: DOMCreator,\n htmlBefore: string,\n clipboardData: ClipboardData,\n htmlAfter: string\n) {\n // Clipboard content of Excel may contain the <StartFragment> and EndFragment comment tags inside the table\n //\n // @example\n // <table>\n // <!--StartFragment-->\n // <tr>...</tr>\n // <!--EndFragment-->\n // </table>\n //\n // This causes that the fragment is not properly created and the table is not extracted.\n // The content that is before the StartFragment is htmlBefore and the content that is after the EndFragment is htmlAfter.\n // So attempt to create a new document fragment with the content of htmlBefore + clipboardData.html + htmlAfter\n // If a table is found, replace the fragment with the new fragment\n const result =\n !fragment.querySelector(TABLE_SELECTOR) &&\n domCreator.htmlToDOM(htmlBefore + clipboardData.html + htmlAfter);\n if (result && result.querySelector(TABLE_SELECTOR)) {\n moveChildNodes(fragment, result?.body);\n } else {\n // If the table is still not found, try to extract the table from the clipboard data using Regex\n const html = clipboardData.html ? excelHandler(clipboardData.html, htmlBefore) : undefined;\n\n if (html && clipboardData.html != html) {\n const doc = domCreator.htmlToDOM(html);\n moveChildNodes(fragment, doc?.body);\n }\n }\n}\n\n/**\n * @internal Export for test only\n * @param html Source html\n */\nexport function excelHandler(html: string, htmlBefore: string): string {\n try {\n if (html.match(LAST_TD_END_REGEX)) {\n const trMatch = htmlBefore.match(LAST_TR_REGEX);\n const tr = trMatch ? trMatch[0] : '<TR>';\n html = tr + html + '</TR>';\n }\n if (html.match(LAST_TR_END_REGEX)) {\n const tableMatch = htmlBefore.match(LAST_TABLE_REGEX);\n const table = tableMatch ? tableMatch[0] : '<TABLE>';\n html = table + html + '</TABLE>';\n }\n } finally {\n return html;\n }\n}\n\n/**\n * @internal\n * Exported only for unit test\n */\nexport function setupExcelTableHandlers(\n event: BeforePasteEvent,\n allowExcelNoBorderTable: boolean | undefined,\n isNativeEvent: boolean\n) {\n addParser(event.domToModelOption, 'tableCell', (format, element) => {\n if (\n !allowExcelNoBorderTable &&\n (element.style.borderStyle === 'none' ||\n (!isNativeEvent && element.style.borderStyle == ''))\n ) {\n format.borderBottom = DEFAULT_BORDER_STYLE;\n format.borderLeft = DEFAULT_BORDER_STYLE;\n format.borderRight = DEFAULT_BORDER_STYLE;\n format.borderTop = DEFAULT_BORDER_STYLE;\n }\n });\n\n setProcessor(event.domToModelOption, 'child', childProcessor);\n}\n\n/**\n * @internal\n * Exported only for unit test\n */\nexport const childProcessor: ElementProcessor<ParentNode> = (group, element, context) => {\n const segmentFormat = { ...context.segmentFormat };\n if (\n group.blockGroupType === 'TableCell' &&\n group.format.textColor &&\n !context.segmentFormat.textColor\n ) {\n context.segmentFormat.textColor = group.format.textColor;\n }\n\n context.defaultElementProcessors.child(group, element, context);\n\n if (group.blockGroupType === 'TableCell' && group.format.textColor) {\n context.segmentFormat = segmentFormat;\n delete group.format.textColor;\n }\n};\n"]}
@@ -85,9 +85,10 @@ var PastePlugin = /** @class */ (function () {
85
85
  break;
86
86
  case 'excelOnline':
87
87
  case 'excelDesktop':
88
+ case 'excelNonNativeEvent':
88
89
  if (pasteType === 'normal' || pasteType === 'mergeFormat') {
89
90
  // Handle HTML copied from Excel
90
- (0, processPastedContentFromExcel_1.processPastedContentFromExcel)(event, this.editor.getDOMCreator(), this.allowExcelNoBorderTable);
91
+ (0, processPastedContentFromExcel_1.processPastedContentFromExcel)(event, this.editor.getDOMCreator(), !!this.allowExcelNoBorderTable, pasteSource != 'excelNonNativeEvent' /* isNativeEvent */);
91
92
  }
92
93
  break;
93
94
  case 'googleSheets':
@@ -1 +1 @@
1
- {"version":3,"file":"PastePlugin.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/paste/PastePlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { addParser } from './utils/addParser';\nimport { BorderKeys, getObjectKeys } from 'roosterjs-content-model-dom';\nimport { chainSanitizerCallback } from './utils/chainSanitizerCallback';\nimport { DefaultSanitizers } from './DefaultSanitizers';\nimport { deprecatedBorderColorParser } from './utils/deprecatedColorParser';\nimport { getPasteSource } from './pasteSourceValidations/getPasteSource';\nimport { parseLink } from './utils/linkParser';\nimport { PastePropertyNames } from './pasteSourceValidations/constants';\nimport { processPastedContentFromExcel } from './Excel/processPastedContentFromExcel';\nimport { processPastedContentFromPowerPoint } from './PowerPoint/processPastedContentFromPowerPoint';\nimport { processPastedContentFromWordDesktop } from './WordDesktop/processPastedContentFromWordDesktop';\nimport { processPastedContentWacComponents } from './WacComponents/processPastedContentWacComponents';\nimport type {\n BeforePasteEvent,\n BorderFormat,\n ContentModelBlockFormat,\n ContentModelTableCellFormat,\n DomToModelOptionForSanitizing,\n EditorPlugin,\n FormatParser,\n IEditor,\n PluginEvent,\n} from 'roosterjs-content-model-types';\n\n/**\n * Paste plugin, handles BeforePaste event and reformat some special content, including:\n * 1. Content copied from Word\n * 2. Content copied from Excel\n * 3. Content copied from Word Online or OneNote Online\n * 4. Content copied from Power Point\n */\nexport class PastePlugin implements EditorPlugin {\n private editor: IEditor | null = null;\n\n /**\n * Construct a new instance of Paste class\n * @param unknownTagReplacement Replace solution of unknown tags, default behavior is to replace with SPAN\n * @param allowExcelNoBorderTable Allow table copied from Excel without border\n */\n constructor(\n private allowExcelNoBorderTable?: boolean,\n private domToModelForSanitizing: Pick<\n DomToModelOptionForSanitizing,\n | 'additionalAllowedTags'\n | 'additionalDisallowedTags'\n | 'styleSanitizers'\n | 'attributeSanitizers'\n > = {\n styleSanitizers: DefaultSanitizers,\n additionalAllowedTags: [],\n additionalDisallowedTags: [],\n attributeSanitizers: {},\n }\n ) {}\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'Paste';\n }\n\n /**\n * The first method that editor will call to a plugin when editor is initializing.\n * It will pass in the editor instance, plugin should take this chance to save the\n * editor reference so that it can call to any editor method or format API later.\n * @param editor The editor object\n */\n initialize(editor: IEditor) {\n this.editor = editor;\n }\n\n /**\n * The last method that editor will call to a plugin before it is disposed.\n * Plugin can take this chance to clear the reference to editor. After this method is\n * called, plugin should not call to any editor method since it will result in error.\n */\n dispose() {\n this.editor = null;\n }\n\n /**\n * Core method for a plugin. Once an event happens in editor, editor will call this\n * method of each plugin to handle the event as long as the event is not handled\n * exclusively by another plugin.\n * @param event The event to handle:\n */\n onPluginEvent(event: PluginEvent) {\n if (!this.editor || event.eventType != 'beforePaste') {\n return;\n }\n\n if (!event.domToModelOption) {\n return;\n }\n\n const pasteSource = getPasteSource(event, false);\n const pasteType = event.pasteType;\n\n switch (pasteSource) {\n case 'wordDesktop':\n processPastedContentFromWordDesktop(event, this.editor.getDOMCreator());\n break;\n case 'wacComponents':\n processPastedContentWacComponents(event);\n break;\n case 'excelOnline':\n case 'excelDesktop':\n if (pasteType === 'normal' || pasteType === 'mergeFormat') {\n // Handle HTML copied from Excel\n processPastedContentFromExcel(\n event,\n this.editor.getDOMCreator(),\n this.allowExcelNoBorderTable\n );\n }\n break;\n case 'googleSheets':\n event.domToModelOption.additionalAllowedTags.push(\n PastePropertyNames.GOOGLE_SHEET_NODE_NAME as Lowercase<string>\n );\n break;\n case 'powerPointDesktop':\n processPastedContentFromPowerPoint(event, this.editor.getDOMCreator());\n break;\n }\n\n addParser(event.domToModelOption, 'link', parseLink);\n addParser(event.domToModelOption, 'tableCell', deprecatedBorderColorParser);\n addParser(event.domToModelOption, 'tableCell', tableBorderParser);\n addParser(event.domToModelOption, 'table', deprecatedBorderColorParser);\n\n if (pasteType === 'mergeFormat') {\n addParser(event.domToModelOption, 'block', blockElementParser);\n addParser(event.domToModelOption, 'listLevel', blockElementParser);\n }\n\n this.setEventSanitizers(event);\n }\n\n private setEventSanitizers(event: BeforePasteEvent) {\n if (this.domToModelForSanitizing) {\n const {\n styleSanitizers,\n attributeSanitizers,\n additionalAllowedTags,\n additionalDisallowedTags,\n } = this.domToModelForSanitizing;\n getObjectKeys(styleSanitizers).forEach(key =>\n chainSanitizerCallback(\n event.domToModelOption.styleSanitizers,\n key,\n styleSanitizers[key]\n )\n );\n getObjectKeys(attributeSanitizers).forEach(key =>\n chainSanitizerCallback(\n event.domToModelOption.attributeSanitizers,\n key,\n attributeSanitizers[key]\n )\n );\n event.domToModelOption.additionalAllowedTags.push(...additionalAllowedTags);\n event.domToModelOption.additionalDisallowedTags.push(...additionalDisallowedTags);\n }\n }\n}\n\n/**\n * For block elements that have background color style, remove the background color when user selects the merge current format\n * paste option\n */\nconst blockElementParser: FormatParser<ContentModelBlockFormat> = (\n format: ContentModelBlockFormat,\n element: HTMLElement\n) => {\n if (element.style.backgroundColor) {\n delete format.backgroundColor;\n }\n};\n\nconst ElementBorderKeys = new Map<\n keyof BorderFormat,\n {\n c: keyof CSSStyleDeclaration;\n s: keyof CSSStyleDeclaration;\n w: keyof CSSStyleDeclaration;\n }\n>([\n ['borderTop', { w: 'borderTopWidth', s: 'borderTopStyle', c: 'borderTopColor' }],\n ['borderRight', { w: 'borderRightWidth', s: 'borderRightStyle', c: 'borderRightColor' }],\n ['borderBottom', { w: 'borderBottomWidth', s: 'borderBottomStyle', c: 'borderBottomColor' }],\n ['borderLeft', { w: 'borderLeftWidth', s: 'borderLeftStyle', c: 'borderLeftColor' }],\n]);\n\nfunction tableBorderParser(format: ContentModelTableCellFormat, element: HTMLElement): void {\n BorderKeys.forEach(key => {\n if (!format[key]) {\n const styleSet = ElementBorderKeys.get(key);\n if (\n styleSet &&\n element.style[styleSet.w] &&\n element.style[styleSet.s] &&\n !element.style[styleSet.c]\n ) {\n format[key] = `${element.style[styleSet.w]} ${element.style[styleSet.s]}`;\n }\n }\n });\n}\n"]}
1
+ {"version":3,"file":"PastePlugin.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/paste/PastePlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { addParser } from './utils/addParser';\nimport { BorderKeys, getObjectKeys } from 'roosterjs-content-model-dom';\nimport { chainSanitizerCallback } from './utils/chainSanitizerCallback';\nimport { DefaultSanitizers } from './DefaultSanitizers';\nimport { deprecatedBorderColorParser } from './utils/deprecatedColorParser';\nimport { getPasteSource } from './pasteSourceValidations/getPasteSource';\nimport { parseLink } from './utils/linkParser';\nimport { PastePropertyNames } from './pasteSourceValidations/constants';\nimport { processPastedContentFromExcel } from './Excel/processPastedContentFromExcel';\nimport { processPastedContentFromPowerPoint } from './PowerPoint/processPastedContentFromPowerPoint';\nimport { processPastedContentFromWordDesktop } from './WordDesktop/processPastedContentFromWordDesktop';\nimport { processPastedContentWacComponents } from './WacComponents/processPastedContentWacComponents';\nimport type {\n BeforePasteEvent,\n BorderFormat,\n ContentModelBlockFormat,\n ContentModelTableCellFormat,\n DomToModelOptionForSanitizing,\n EditorPlugin,\n FormatParser,\n IEditor,\n PluginEvent,\n} from 'roosterjs-content-model-types';\n\n/**\n * Paste plugin, handles BeforePaste event and reformat some special content, including:\n * 1. Content copied from Word\n * 2. Content copied from Excel\n * 3. Content copied from Word Online or OneNote Online\n * 4. Content copied from Power Point\n */\nexport class PastePlugin implements EditorPlugin {\n private editor: IEditor | null = null;\n\n /**\n * Construct a new instance of Paste class\n * @param unknownTagReplacement Replace solution of unknown tags, default behavior is to replace with SPAN\n * @param allowExcelNoBorderTable Allow table copied from Excel without border\n */\n constructor(\n private allowExcelNoBorderTable?: boolean,\n private domToModelForSanitizing: Pick<\n DomToModelOptionForSanitizing,\n | 'additionalAllowedTags'\n | 'additionalDisallowedTags'\n | 'styleSanitizers'\n | 'attributeSanitizers'\n > = {\n styleSanitizers: DefaultSanitizers,\n additionalAllowedTags: [],\n additionalDisallowedTags: [],\n attributeSanitizers: {},\n }\n ) {}\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'Paste';\n }\n\n /**\n * The first method that editor will call to a plugin when editor is initializing.\n * It will pass in the editor instance, plugin should take this chance to save the\n * editor reference so that it can call to any editor method or format API later.\n * @param editor The editor object\n */\n initialize(editor: IEditor) {\n this.editor = editor;\n }\n\n /**\n * The last method that editor will call to a plugin before it is disposed.\n * Plugin can take this chance to clear the reference to editor. After this method is\n * called, plugin should not call to any editor method since it will result in error.\n */\n dispose() {\n this.editor = null;\n }\n\n /**\n * Core method for a plugin. Once an event happens in editor, editor will call this\n * method of each plugin to handle the event as long as the event is not handled\n * exclusively by another plugin.\n * @param event The event to handle:\n */\n onPluginEvent(event: PluginEvent) {\n if (!this.editor || event.eventType != 'beforePaste') {\n return;\n }\n\n if (!event.domToModelOption) {\n return;\n }\n\n const pasteSource = getPasteSource(event, false);\n const pasteType = event.pasteType;\n\n switch (pasteSource) {\n case 'wordDesktop':\n processPastedContentFromWordDesktop(event, this.editor.getDOMCreator());\n break;\n case 'wacComponents':\n processPastedContentWacComponents(event);\n break;\n case 'excelOnline':\n case 'excelDesktop':\n case 'excelNonNativeEvent':\n if (pasteType === 'normal' || pasteType === 'mergeFormat') {\n // Handle HTML copied from Excel\n processPastedContentFromExcel(\n event,\n this.editor.getDOMCreator(),\n !!this.allowExcelNoBorderTable,\n pasteSource != 'excelNonNativeEvent' /* isNativeEvent */\n );\n }\n break;\n case 'googleSheets':\n event.domToModelOption.additionalAllowedTags.push(\n PastePropertyNames.GOOGLE_SHEET_NODE_NAME as Lowercase<string>\n );\n break;\n case 'powerPointDesktop':\n processPastedContentFromPowerPoint(event, this.editor.getDOMCreator());\n break;\n }\n\n addParser(event.domToModelOption, 'link', parseLink);\n addParser(event.domToModelOption, 'tableCell', deprecatedBorderColorParser);\n addParser(event.domToModelOption, 'tableCell', tableBorderParser);\n addParser(event.domToModelOption, 'table', deprecatedBorderColorParser);\n\n if (pasteType === 'mergeFormat') {\n addParser(event.domToModelOption, 'block', blockElementParser);\n addParser(event.domToModelOption, 'listLevel', blockElementParser);\n }\n\n this.setEventSanitizers(event);\n }\n\n private setEventSanitizers(event: BeforePasteEvent) {\n if (this.domToModelForSanitizing) {\n const {\n styleSanitizers,\n attributeSanitizers,\n additionalAllowedTags,\n additionalDisallowedTags,\n } = this.domToModelForSanitizing;\n getObjectKeys(styleSanitizers).forEach(key =>\n chainSanitizerCallback(\n event.domToModelOption.styleSanitizers,\n key,\n styleSanitizers[key]\n )\n );\n getObjectKeys(attributeSanitizers).forEach(key =>\n chainSanitizerCallback(\n event.domToModelOption.attributeSanitizers,\n key,\n attributeSanitizers[key]\n )\n );\n event.domToModelOption.additionalAllowedTags.push(...additionalAllowedTags);\n event.domToModelOption.additionalDisallowedTags.push(...additionalDisallowedTags);\n }\n }\n}\n\n/**\n * For block elements that have background color style, remove the background color when user selects the merge current format\n * paste option\n */\nconst blockElementParser: FormatParser<ContentModelBlockFormat> = (\n format: ContentModelBlockFormat,\n element: HTMLElement\n) => {\n if (element.style.backgroundColor) {\n delete format.backgroundColor;\n }\n};\n\nconst ElementBorderKeys = new Map<\n keyof BorderFormat,\n {\n c: keyof CSSStyleDeclaration;\n s: keyof CSSStyleDeclaration;\n w: keyof CSSStyleDeclaration;\n }\n>([\n ['borderTop', { w: 'borderTopWidth', s: 'borderTopStyle', c: 'borderTopColor' }],\n ['borderRight', { w: 'borderRightWidth', s: 'borderRightStyle', c: 'borderRightColor' }],\n ['borderBottom', { w: 'borderBottomWidth', s: 'borderBottomStyle', c: 'borderBottomColor' }],\n ['borderLeft', { w: 'borderLeftWidth', s: 'borderLeftStyle', c: 'borderLeftColor' }],\n]);\n\nfunction tableBorderParser(format: ContentModelTableCellFormat, element: HTMLElement): void {\n BorderKeys.forEach(key => {\n if (!format[key]) {\n const styleSet = ElementBorderKeys.get(key);\n if (\n styleSet &&\n element.style[styleSet.w] &&\n element.style[styleSet.s] &&\n !element.style[styleSet.c]\n ) {\n format[key] = `${element.style[styleSet.w]} ${element.style[styleSet.s]}`;\n }\n }\n });\n}\n"]}
@@ -12,7 +12,7 @@ export declare type GetSourceInputParams = {
12
12
  * @internal
13
13
  * Represent the types of sources to handle in the Paste Plugin
14
14
  */
15
- export declare type KnownPasteSourceType = 'wordDesktop' | 'excelDesktop' | 'excelOnline' | 'powerPointDesktop' | 'googleSheets' | 'wacComponents' | 'default' | 'singleImage';
15
+ export declare type KnownPasteSourceType = 'wordDesktop' | 'excelDesktop' | 'excelOnline' | 'powerPointDesktop' | 'googleSheets' | 'wacComponents' | 'default' | 'singleImage' | 'excelNonNativeEvent';
16
16
  /**
17
17
  * @internal
18
18
  */
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getPasteSource = void 0;
4
4
  var documentContainWacElements_1 = require("./documentContainWacElements");
5
5
  var isExcelDesktopDocument_1 = require("./isExcelDesktopDocument");
6
+ var isExcelNonNativeEvent_1 = require("./isExcelNonNativeEvent");
6
7
  var isExcelOnlineDocument_1 = require("./isExcelOnlineDocument");
7
8
  var isGoogleSheetDocument_1 = require("./isGoogleSheetDocument");
8
9
  var isPowerPointDesktopDocument_1 = require("./isPowerPointDesktopDocument");
@@ -16,6 +17,7 @@ var getSourceFunctions = new Map([
16
17
  ['wacComponents', documentContainWacElements_1.documentContainWacElements],
17
18
  ['googleSheets', isGoogleSheetDocument_1.isGoogleSheetDocument],
18
19
  ['singleImage', shouldConvertToSingleImage_1.shouldConvertToSingleImage],
20
+ ['excelNonNativeEvent', isExcelNonNativeEvent_1.isExcelNotNativeEvent],
19
21
  ]);
20
22
  /**
21
23
  * @internal
@@ -1 +1 @@
1
- {"version":3,"file":"getPasteSource.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/paste/pasteSourceValidations/getPasteSource.ts"],"names":[],"mappings":";;;AAAA,2EAA0E;AAC1E,mEAAkE;AAClE,iEAAgE;AAChE,iEAAgE;AAChE,6EAA4E;AAC5E,iEAAgE;AAChE,2EAA0E;AAgC1E,IAAM,kBAAkB,GAAG,IAAI,GAAG,CAA0C;IACxE,CAAC,aAAa,EAAE,6CAAqB,CAAC;IACtC,CAAC,cAAc,EAAE,+CAAsB,CAAC;IACxC,CAAC,aAAa,EAAE,6CAAqB,CAAC;IACtC,CAAC,mBAAmB,EAAE,yDAA2B,CAAC;IAClD,CAAC,eAAe,EAAE,uDAA0B,CAAC;IAC7C,CAAC,cAAc,EAAE,6CAAqB,CAAC;IACvC,CAAC,aAAa,EAAE,uDAA0B,CAAC;CAC9C,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,SAAgB,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;AArBD,wCAqBC","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-content-model-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/roosterjs-content-model-plugins/lib/paste/pasteSourceValidations/getPasteSource.ts"],"names":[],"mappings":";;;AAAA,2EAA0E;AAC1E,mEAAkE;AAClE,iEAAgE;AAChE,iEAAgE;AAChE,iEAAgE;AAChE,6EAA4E;AAC5E,iEAAgE;AAChE,2EAA0E;AAiC1E,IAAM,kBAAkB,GAAG,IAAI,GAAG,CAA0C;IACxE,CAAC,aAAa,EAAE,6CAAqB,CAAC;IACtC,CAAC,cAAc,EAAE,+CAAsB,CAAC;IACxC,CAAC,aAAa,EAAE,6CAAqB,CAAC;IACtC,CAAC,mBAAmB,EAAE,yDAA2B,CAAC;IAClD,CAAC,eAAe,EAAE,uDAA0B,CAAC;IAC7C,CAAC,cAAc,EAAE,6CAAqB,CAAC;IACvC,CAAC,aAAa,EAAE,uDAA0B,CAAC;IAC3C,CAAC,qBAAqB,EAAE,6CAAqB,CAAC;CACjD,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,SAAgB,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;AArBD,wCAqBC","sourcesContent":["import { documentContainWacElements } from './documentContainWacElements';\nimport { isExcelDesktopDocument } from './isExcelDesktopDocument';\nimport { isExcelNotNativeEvent } from './isExcelNonNativeEvent';\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-content-model-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 | 'excelNonNativeEvent';\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 ['excelNonNativeEvent', isExcelNotNativeEvent],\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"]}
@@ -0,0 +1,7 @@
1
+ import type { GetSourceFunction } from './getPasteSource';
2
+ /**
3
+ * @internal
4
+ * When the clipboard content is retrieved programatically, the clipboard html does not contain the usual
5
+ * attributes we use to determine if the content is from Excel. This function is used to handle that case.
6
+ */
7
+ export declare const isExcelNotNativeEvent: GetSourceFunction;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isExcelNotNativeEvent = void 0;
4
+ var ShadowWorkbookClipboardType = 'web data/shadow-workbook';
5
+ /**
6
+ * @internal
7
+ * When the clipboard content is retrieved programatically, the clipboard html does not contain the usual
8
+ * attributes we use to determine if the content is from Excel. This function is used to handle that case.
9
+ */
10
+ var isExcelNotNativeEvent = function (props) {
11
+ var _a;
12
+ var clipboardData = props.clipboardData;
13
+ return (clipboardData.types.includes(ShadowWorkbookClipboardType) &&
14
+ ((_a = clipboardData.htmlFirstLevelChildTags) === null || _a === void 0 ? void 0 : _a.length) == 1 &&
15
+ clipboardData.htmlFirstLevelChildTags[0] == 'TABLE');
16
+ };
17
+ exports.isExcelNotNativeEvent = isExcelNotNativeEvent;
18
+ //# sourceMappingURL=isExcelNonNativeEvent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isExcelNonNativeEvent.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/paste/pasteSourceValidations/isExcelNonNativeEvent.ts"],"names":[],"mappings":";;;AAEA,IAAM,2BAA2B,GAAG,0BAA0B,CAAC;AAE/D;;;;GAIG;AACI,IAAM,qBAAqB,GAAsB,UAAC,KAA2B;;IACxE,IAAA,aAAa,GAAK,KAAK,cAAV,CAAW;IAEhC,OAAO,CACH,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,2BAA2B,CAAC;QACzD,CAAA,MAAA,aAAa,CAAC,uBAAuB,0CAAE,MAAM,KAAI,CAAC;QAClD,aAAa,CAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI,OAAO,CACtD,CAAC;AACN,CAAC,CAAC;AARW,QAAA,qBAAqB,yBAQhC","sourcesContent":["import type { GetSourceFunction, GetSourceInputParams } from './getPasteSource';\n\nconst ShadowWorkbookClipboardType = 'web data/shadow-workbook';\n\n/**\n * @internal\n * When the clipboard content is retrieved programatically, the clipboard html does not contain the usual\n * attributes we use to determine if the content is from Excel. This function is used to handle that case.\n */\nexport const isExcelNotNativeEvent: GetSourceFunction = (props: GetSourceInputParams) => {\n const { clipboardData } = props;\n\n return (\n clipboardData.types.includes(ShadowWorkbookClipboardType) &&\n clipboardData.htmlFirstLevelChildTags?.length == 1 &&\n clipboardData.htmlFirstLevelChildTags[0] == 'TABLE'\n );\n};\n"]}
@@ -3,13 +3,11 @@ import type { BeforePasteEvent, ClipboardData, DOMCreator, ElementProcessor } fr
3
3
  * @internal
4
4
  * Convert pasted content from Excel, add borders when source doc doesn't have a border
5
5
  * @param event The BeforePaste event
6
+ * @param domCreator The DOM creator
7
+ * @param allowExcelNoBorderTable Allow table copied from Excel without border
8
+ * @param isNativeEvent Whether the event is native event
6
9
  */
7
- export declare function processPastedContentFromExcel(event: BeforePasteEvent, domCreator: DOMCreator, allowExcelNoBorderTable?: boolean): void;
8
- /**
9
- * @internal
10
- * Exported only for unit test
11
- */
12
- export declare const childProcessor: ElementProcessor<ParentNode>;
10
+ export declare function processPastedContentFromExcel(event: BeforePasteEvent, domCreator: DOMCreator, allowExcelNoBorderTable: boolean, isNativeEvent: boolean): void;
13
11
  /**
14
12
  * @internal
15
13
  * Exported only for unit test
@@ -20,3 +18,13 @@ export declare function validateExcelFragment(fragment: DocumentFragment, domCre
20
18
  * @param html Source html
21
19
  */
22
20
  export declare function excelHandler(html: string, htmlBefore: string): string;
21
+ /**
22
+ * @internal
23
+ * Exported only for unit test
24
+ */
25
+ export declare function setupExcelTableHandlers(event: BeforePasteEvent, allowExcelNoBorderTable: boolean | undefined, isNativeEvent: boolean): void;
26
+ /**
27
+ * @internal
28
+ * Exported only for unit test
29
+ */
30
+ export declare const childProcessor: ElementProcessor<ParentNode>;
@@ -1,21 +1,27 @@
1
1
  define(["require", "exports", "tslib", "../utils/addParser", "roosterjs-content-model-dom", "../utils/setProcessor"], function (require, exports, tslib_1, addParser_1, roosterjs_content_model_dom_1, setProcessor_1) {
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.excelHandler = exports.validateExcelFragment = exports.childProcessor = exports.processPastedContentFromExcel = void 0;
4
+ exports.childProcessor = exports.setupExcelTableHandlers = exports.excelHandler = exports.validateExcelFragment = exports.processPastedContentFromExcel = void 0;
5
5
  var LAST_TD_END_REGEX = /<\/\s*td\s*>((?!<\/\s*tr\s*>)[\s\S])*$/i;
6
6
  var LAST_TR_END_REGEX = /<\/\s*tr\s*>((?!<\/\s*table\s*>)[\s\S])*$/i;
7
7
  var LAST_TR_REGEX = /<tr[^>]*>[^<]*/i;
8
8
  var LAST_TABLE_REGEX = /<table[^>]*>[^<]*/i;
9
- var DEFAULT_BORDER_STYLE = 'solid 1px #d4d4d4';
10
9
  var TABLE_SELECTOR = 'table';
10
+ var DEFAULT_BORDER_STYLE = 'solid 1px #d4d4d4';
11
11
  /**
12
12
  * @internal
13
13
  * Convert pasted content from Excel, add borders when source doc doesn't have a border
14
14
  * @param event The BeforePaste event
15
+ * @param domCreator The DOM creator
16
+ * @param allowExcelNoBorderTable Allow table copied from Excel without border
17
+ * @param isNativeEvent Whether the event is native event
15
18
  */
16
- function processPastedContentFromExcel(event, domCreator, allowExcelNoBorderTable) {
19
+ function processPastedContentFromExcel(event, domCreator, allowExcelNoBorderTable, isNativeEvent) {
17
20
  var fragment = event.fragment, htmlBefore = event.htmlBefore, htmlAfter = event.htmlAfter, clipboardData = event.clipboardData;
18
- validateExcelFragment(fragment, domCreator, htmlBefore, clipboardData, htmlAfter);
21
+ // For non native event we already validated that the content contains a table
22
+ if (isNativeEvent) {
23
+ validateExcelFragment(fragment, domCreator, htmlBefore, clipboardData, htmlAfter);
24
+ }
19
25
  // For Excel Online
20
26
  var firstChild = fragment.firstChild;
21
27
  if ((0, roosterjs_content_model_dom_1.isNodeOfType)(firstChild, 'ELEMENT_NODE') &&
@@ -35,35 +41,9 @@ define(["require", "exports", "tslib", "../utils/addParser", "roosterjs-content-
35
41
  event.fragment.replaceChildren(firstChild.lastChild);
36
42
  }
37
43
  }
38
- (0, addParser_1.addParser)(event.domToModelOption, 'tableCell', function (format, element) {
39
- if (!allowExcelNoBorderTable && element.style.borderStyle === 'none') {
40
- format.borderBottom = DEFAULT_BORDER_STYLE;
41
- format.borderLeft = DEFAULT_BORDER_STYLE;
42
- format.borderRight = DEFAULT_BORDER_STYLE;
43
- format.borderTop = DEFAULT_BORDER_STYLE;
44
- }
45
- });
46
- (0, setProcessor_1.setProcessor)(event.domToModelOption, 'child', exports.childProcessor);
44
+ setupExcelTableHandlers(event, allowExcelNoBorderTable, isNativeEvent /* handleForNativeEvent */);
47
45
  }
48
46
  exports.processPastedContentFromExcel = processPastedContentFromExcel;
49
- /**
50
- * @internal
51
- * Exported only for unit test
52
- */
53
- var childProcessor = function (group, element, context) {
54
- var segmentFormat = (0, tslib_1.__assign)({}, context.segmentFormat);
55
- if (group.blockGroupType === 'TableCell' &&
56
- group.format.textColor &&
57
- !context.segmentFormat.textColor) {
58
- context.segmentFormat.textColor = group.format.textColor;
59
- }
60
- context.defaultElementProcessors.child(group, element, context);
61
- if (group.blockGroupType === 'TableCell' && group.format.textColor) {
62
- context.segmentFormat = segmentFormat;
63
- delete group.format.textColor;
64
- }
65
- };
66
- exports.childProcessor = childProcessor;
67
47
  /**
68
48
  * @internal
69
49
  * Exported only for unit test
@@ -119,5 +99,41 @@ define(["require", "exports", "tslib", "../utils/addParser", "roosterjs-content-
119
99
  }
120
100
  }
121
101
  exports.excelHandler = excelHandler;
102
+ /**
103
+ * @internal
104
+ * Exported only for unit test
105
+ */
106
+ function setupExcelTableHandlers(event, allowExcelNoBorderTable, isNativeEvent) {
107
+ (0, addParser_1.addParser)(event.domToModelOption, 'tableCell', function (format, element) {
108
+ if (!allowExcelNoBorderTable &&
109
+ (element.style.borderStyle === 'none' ||
110
+ (!isNativeEvent && element.style.borderStyle == ''))) {
111
+ format.borderBottom = DEFAULT_BORDER_STYLE;
112
+ format.borderLeft = DEFAULT_BORDER_STYLE;
113
+ format.borderRight = DEFAULT_BORDER_STYLE;
114
+ format.borderTop = DEFAULT_BORDER_STYLE;
115
+ }
116
+ });
117
+ (0, setProcessor_1.setProcessor)(event.domToModelOption, 'child', exports.childProcessor);
118
+ }
119
+ exports.setupExcelTableHandlers = setupExcelTableHandlers;
120
+ /**
121
+ * @internal
122
+ * Exported only for unit test
123
+ */
124
+ var childProcessor = function (group, element, context) {
125
+ var segmentFormat = (0, tslib_1.__assign)({}, context.segmentFormat);
126
+ if (group.blockGroupType === 'TableCell' &&
127
+ group.format.textColor &&
128
+ !context.segmentFormat.textColor) {
129
+ context.segmentFormat.textColor = group.format.textColor;
130
+ }
131
+ context.defaultElementProcessors.child(group, element, context);
132
+ if (group.blockGroupType === 'TableCell' && group.format.textColor) {
133
+ context.segmentFormat = segmentFormat;
134
+ delete group.format.textColor;
135
+ }
136
+ };
137
+ exports.childProcessor = childProcessor;
122
138
  });
123
139
  //# sourceMappingURL=processPastedContentFromExcel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"processPastedContentFromExcel.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/paste/Excel/processPastedContentFromExcel.ts"],"names":[],"mappings":"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","sourcesContent":["import { addParser } from '../utils/addParser';\nimport { isNodeOfType, moveChildNodes } from 'roosterjs-content-model-dom';\nimport { setProcessor } from '../utils/setProcessor';\nimport type {\n BeforePasteEvent,\n ClipboardData,\n DOMCreator,\n ElementProcessor,\n} from 'roosterjs-content-model-types';\n\nconst LAST_TD_END_REGEX = /<\\/\\s*td\\s*>((?!<\\/\\s*tr\\s*>)[\\s\\S])*$/i;\nconst LAST_TR_END_REGEX = /<\\/\\s*tr\\s*>((?!<\\/\\s*table\\s*>)[\\s\\S])*$/i;\nconst LAST_TR_REGEX = /<tr[^>]*>[^<]*/i;\nconst LAST_TABLE_REGEX = /<table[^>]*>[^<]*/i;\nconst DEFAULT_BORDER_STYLE = 'solid 1px #d4d4d4';\nconst TABLE_SELECTOR = 'table';\n\n/**\n * @internal\n * Convert pasted content from Excel, add borders when source doc doesn't have a border\n * @param event The BeforePaste event\n */\n\nexport function processPastedContentFromExcel(\n event: BeforePasteEvent,\n domCreator: DOMCreator,\n allowExcelNoBorderTable?: boolean\n) {\n const { fragment, htmlBefore, htmlAfter, clipboardData } = event;\n\n validateExcelFragment(fragment, domCreator, htmlBefore, clipboardData, htmlAfter);\n\n // For Excel Online\n const firstChild = fragment.firstChild;\n if (\n isNodeOfType(firstChild, 'ELEMENT_NODE') &&\n firstChild.tagName == 'div' &&\n firstChild.firstChild\n ) {\n const tableFound = Array.from(firstChild.childNodes).every((child: Node) => {\n // Tables pasted from Excel Online should be of the format: 0 to N META tags and 1 TABLE tag\n const tagName = isNodeOfType(child, 'ELEMENT_NODE') && child.tagName;\n\n return tagName == 'META'\n ? true\n : tagName == 'TABLE'\n ? child == firstChild.lastChild\n : false;\n });\n\n // Extract Table from Div\n if (tableFound && firstChild.lastChild) {\n event.fragment.replaceChildren(firstChild.lastChild);\n }\n }\n\n addParser(event.domToModelOption, 'tableCell', (format, element) => {\n if (!allowExcelNoBorderTable && element.style.borderStyle === 'none') {\n format.borderBottom = DEFAULT_BORDER_STYLE;\n format.borderLeft = DEFAULT_BORDER_STYLE;\n format.borderRight = DEFAULT_BORDER_STYLE;\n format.borderTop = DEFAULT_BORDER_STYLE;\n }\n });\n\n setProcessor(event.domToModelOption, 'child', childProcessor);\n}\n\n/**\n * @internal\n * Exported only for unit test\n */\nexport const childProcessor: ElementProcessor<ParentNode> = (group, element, context) => {\n const segmentFormat = { ...context.segmentFormat };\n if (\n group.blockGroupType === 'TableCell' &&\n group.format.textColor &&\n !context.segmentFormat.textColor\n ) {\n context.segmentFormat.textColor = group.format.textColor;\n }\n\n context.defaultElementProcessors.child(group, element, context);\n\n if (group.blockGroupType === 'TableCell' && group.format.textColor) {\n context.segmentFormat = segmentFormat;\n delete group.format.textColor;\n }\n};\n\n/**\n * @internal\n * Exported only for unit test\n */\nexport function validateExcelFragment(\n fragment: DocumentFragment,\n domCreator: DOMCreator,\n htmlBefore: string,\n clipboardData: ClipboardData,\n htmlAfter: string\n) {\n // Clipboard content of Excel may contain the <StartFragment> and EndFragment comment tags inside the table\n //\n // @example\n // <table>\n // <!--StartFragment-->\n // <tr>...</tr>\n // <!--EndFragment-->\n // </table>\n //\n // This causes that the fragment is not properly created and the table is not extracted.\n // The content that is before the StartFragment is htmlBefore and the content that is after the EndFragment is htmlAfter.\n // So attempt to create a new document fragment with the content of htmlBefore + clipboardData.html + htmlAfter\n // If a table is found, replace the fragment with the new fragment\n const result =\n !fragment.querySelector(TABLE_SELECTOR) &&\n domCreator.htmlToDOM(htmlBefore + clipboardData.html + htmlAfter);\n if (result && result.querySelector(TABLE_SELECTOR)) {\n moveChildNodes(fragment, result?.body);\n } else {\n // If the table is still not found, try to extract the table from the clipboard data using Regex\n const html = clipboardData.html ? excelHandler(clipboardData.html, htmlBefore) : undefined;\n\n if (html && clipboardData.html != html) {\n const doc = domCreator.htmlToDOM(html);\n moveChildNodes(fragment, doc?.body);\n }\n }\n}\n\n/**\n * @internal Export for test only\n * @param html Source html\n */\nexport function excelHandler(html: string, htmlBefore: string): string {\n try {\n if (html.match(LAST_TD_END_REGEX)) {\n const trMatch = htmlBefore.match(LAST_TR_REGEX);\n const tr = trMatch ? trMatch[0] : '<TR>';\n html = tr + html + '</TR>';\n }\n if (html.match(LAST_TR_END_REGEX)) {\n const tableMatch = htmlBefore.match(LAST_TABLE_REGEX);\n const table = tableMatch ? tableMatch[0] : '<TABLE>';\n html = table + html + '</TABLE>';\n }\n } finally {\n return html;\n }\n}\n"]}
1
+ {"version":3,"file":"processPastedContentFromExcel.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/paste/Excel/processPastedContentFromExcel.ts"],"names":[],"mappings":"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","sourcesContent":["import { addParser } from '../utils/addParser';\nimport { isNodeOfType, moveChildNodes } from 'roosterjs-content-model-dom';\nimport { setProcessor } from '../utils/setProcessor';\nimport type {\n BeforePasteEvent,\n ClipboardData,\n DOMCreator,\n ElementProcessor,\n} from 'roosterjs-content-model-types';\n\nconst LAST_TD_END_REGEX = /<\\/\\s*td\\s*>((?!<\\/\\s*tr\\s*>)[\\s\\S])*$/i;\nconst LAST_TR_END_REGEX = /<\\/\\s*tr\\s*>((?!<\\/\\s*table\\s*>)[\\s\\S])*$/i;\nconst LAST_TR_REGEX = /<tr[^>]*>[^<]*/i;\nconst LAST_TABLE_REGEX = /<table[^>]*>[^<]*/i;\nconst TABLE_SELECTOR = 'table';\nconst DEFAULT_BORDER_STYLE = 'solid 1px #d4d4d4';\n\n/**\n * @internal\n * Convert pasted content from Excel, add borders when source doc doesn't have a border\n * @param event The BeforePaste event\n * @param domCreator The DOM creator\n * @param allowExcelNoBorderTable Allow table copied from Excel without border\n * @param isNativeEvent Whether the event is native event\n */\nexport function processPastedContentFromExcel(\n event: BeforePasteEvent,\n domCreator: DOMCreator,\n allowExcelNoBorderTable: boolean,\n isNativeEvent: boolean\n) {\n const { fragment, htmlBefore, htmlAfter, clipboardData } = event;\n\n // For non native event we already validated that the content contains a table\n if (isNativeEvent) {\n validateExcelFragment(fragment, domCreator, htmlBefore, clipboardData, htmlAfter);\n }\n\n // For Excel Online\n const firstChild = fragment.firstChild;\n if (\n isNodeOfType(firstChild, 'ELEMENT_NODE') &&\n firstChild.tagName == 'div' &&\n firstChild.firstChild\n ) {\n const tableFound = Array.from(firstChild.childNodes).every((child: Node) => {\n // Tables pasted from Excel Online should be of the format: 0 to N META tags and 1 TABLE tag\n const tagName = isNodeOfType(child, 'ELEMENT_NODE') && child.tagName;\n\n return tagName == 'META'\n ? true\n : tagName == 'TABLE'\n ? child == firstChild.lastChild\n : false;\n });\n\n // Extract Table from Div\n if (tableFound && firstChild.lastChild) {\n event.fragment.replaceChildren(firstChild.lastChild);\n }\n }\n\n setupExcelTableHandlers(\n event,\n allowExcelNoBorderTable,\n isNativeEvent /* handleForNativeEvent */\n );\n}\n\n/**\n * @internal\n * Exported only for unit test\n */\nexport function validateExcelFragment(\n fragment: DocumentFragment,\n domCreator: DOMCreator,\n htmlBefore: string,\n clipboardData: ClipboardData,\n htmlAfter: string\n) {\n // Clipboard content of Excel may contain the <StartFragment> and EndFragment comment tags inside the table\n //\n // @example\n // <table>\n // <!--StartFragment-->\n // <tr>...</tr>\n // <!--EndFragment-->\n // </table>\n //\n // This causes that the fragment is not properly created and the table is not extracted.\n // The content that is before the StartFragment is htmlBefore and the content that is after the EndFragment is htmlAfter.\n // So attempt to create a new document fragment with the content of htmlBefore + clipboardData.html + htmlAfter\n // If a table is found, replace the fragment with the new fragment\n const result =\n !fragment.querySelector(TABLE_SELECTOR) &&\n domCreator.htmlToDOM(htmlBefore + clipboardData.html + htmlAfter);\n if (result && result.querySelector(TABLE_SELECTOR)) {\n moveChildNodes(fragment, result?.body);\n } else {\n // If the table is still not found, try to extract the table from the clipboard data using Regex\n const html = clipboardData.html ? excelHandler(clipboardData.html, htmlBefore) : undefined;\n\n if (html && clipboardData.html != html) {\n const doc = domCreator.htmlToDOM(html);\n moveChildNodes(fragment, doc?.body);\n }\n }\n}\n\n/**\n * @internal Export for test only\n * @param html Source html\n */\nexport function excelHandler(html: string, htmlBefore: string): string {\n try {\n if (html.match(LAST_TD_END_REGEX)) {\n const trMatch = htmlBefore.match(LAST_TR_REGEX);\n const tr = trMatch ? trMatch[0] : '<TR>';\n html = tr + html + '</TR>';\n }\n if (html.match(LAST_TR_END_REGEX)) {\n const tableMatch = htmlBefore.match(LAST_TABLE_REGEX);\n const table = tableMatch ? tableMatch[0] : '<TABLE>';\n html = table + html + '</TABLE>';\n }\n } finally {\n return html;\n }\n}\n\n/**\n * @internal\n * Exported only for unit test\n */\nexport function setupExcelTableHandlers(\n event: BeforePasteEvent,\n allowExcelNoBorderTable: boolean | undefined,\n isNativeEvent: boolean\n) {\n addParser(event.domToModelOption, 'tableCell', (format, element) => {\n if (\n !allowExcelNoBorderTable &&\n (element.style.borderStyle === 'none' ||\n (!isNativeEvent && element.style.borderStyle == ''))\n ) {\n format.borderBottom = DEFAULT_BORDER_STYLE;\n format.borderLeft = DEFAULT_BORDER_STYLE;\n format.borderRight = DEFAULT_BORDER_STYLE;\n format.borderTop = DEFAULT_BORDER_STYLE;\n }\n });\n\n setProcessor(event.domToModelOption, 'child', childProcessor);\n}\n\n/**\n * @internal\n * Exported only for unit test\n */\nexport const childProcessor: ElementProcessor<ParentNode> = (group, element, context) => {\n const segmentFormat = { ...context.segmentFormat };\n if (\n group.blockGroupType === 'TableCell' &&\n group.format.textColor &&\n !context.segmentFormat.textColor\n ) {\n context.segmentFormat.textColor = group.format.textColor;\n }\n\n context.defaultElementProcessors.child(group, element, context);\n\n if (group.blockGroupType === 'TableCell' && group.format.textColor) {\n context.segmentFormat = segmentFormat;\n delete group.format.textColor;\n }\n};\n"]}
@@ -73,9 +73,10 @@ define(["require", "exports", "tslib", "./utils/addParser", "roosterjs-content-m
73
73
  break;
74
74
  case 'excelOnline':
75
75
  case 'excelDesktop':
76
+ case 'excelNonNativeEvent':
76
77
  if (pasteType === 'normal' || pasteType === 'mergeFormat') {
77
78
  // Handle HTML copied from Excel
78
- (0, processPastedContentFromExcel_1.processPastedContentFromExcel)(event, this.editor.getDOMCreator(), this.allowExcelNoBorderTable);
79
+ (0, processPastedContentFromExcel_1.processPastedContentFromExcel)(event, this.editor.getDOMCreator(), !!this.allowExcelNoBorderTable, pasteSource != 'excelNonNativeEvent' /* isNativeEvent */);
79
80
  }
80
81
  break;
81
82
  case 'googleSheets':
@@ -1 +1 @@
1
- {"version":3,"file":"PastePlugin.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/paste/PastePlugin.ts"],"names":[],"mappings":";;;;IAwBA;;;;;;OAMG;IACH;QAGI;;;;WAIG;QACH,qBACY,uBAAiC,EACjC,uBAWP;YAXO,wCAAA,EAAA;gBAOJ,eAAe,EAAE,qCAAiB;gBAClC,qBAAqB,EAAE,EAAE;gBACzB,wBAAwB,EAAE,EAAE;gBAC5B,mBAAmB,EAAE,EAAE;aAC1B;YAZO,4BAAuB,GAAvB,uBAAuB,CAAU;YACjC,4BAAuB,GAAvB,uBAAuB,CAW9B;YApBG,WAAM,GAAmB,IAAI,CAAC;QAqBnC,CAAC;QAEJ;;WAEG;QACH,6BAAO,GAAP;YACI,OAAO,OAAO,CAAC;QACnB,CAAC;QAED;;;;;WAKG;QACH,gCAAU,GAAV,UAAW,MAAe;YACtB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACzB,CAAC;QAED;;;;WAIG;QACH,6BAAO,GAAP;YACI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACvB,CAAC;QAED;;;;;WAKG;QACH,mCAAa,GAAb,UAAc,KAAkB;YAC5B,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,SAAS,IAAI,aAAa,EAAE;gBAClD,OAAO;aACV;YAED,IAAI,CAAC,KAAK,CAAC,gBAAgB,EAAE;gBACzB,OAAO;aACV;YAED,IAAM,WAAW,GAAG,IAAA,+BAAc,EAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YACjD,IAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;YAElC,QAAQ,WAAW,EAAE;gBACjB,KAAK,aAAa;oBACd,IAAA,yEAAmC,EAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;oBACxE,MAAM;gBACV,KAAK,eAAe;oBAChB,IAAA,qEAAiC,EAAC,KAAK,CAAC,CAAC;oBACzC,MAAM;gBACV,KAAK,aAAa,CAAC;gBACnB,KAAK,cAAc;oBACf,IAAI,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,aAAa,EAAE;wBACvD,gCAAgC;wBAChC,IAAA,6DAA6B,EACzB,KAAK,EACL,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,EAC3B,IAAI,CAAC,uBAAuB,CAC/B,CAAC;qBACL;oBACD,MAAM;gBACV,KAAK,cAAc;oBACf,KAAK,CAAC,gBAAgB,CAAC,qBAAqB,CAAC,IAAI,CAC7C,8BAAkB,CAAC,sBAA2C,CACjE,CAAC;oBACF,MAAM;gBACV,KAAK,mBAAmB;oBACpB,IAAA,uEAAkC,EAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;oBACvE,MAAM;aACb;YAED,IAAA,qBAAS,EAAC,KAAK,CAAC,gBAAgB,EAAE,MAAM,EAAE,sBAAS,CAAC,CAAC;YACrD,IAAA,qBAAS,EAAC,KAAK,CAAC,gBAAgB,EAAE,WAAW,EAAE,mDAA2B,CAAC,CAAC;YAC5E,IAAA,qBAAS,EAAC,KAAK,CAAC,gBAAgB,EAAE,WAAW,EAAE,iBAAiB,CAAC,CAAC;YAClE,IAAA,qBAAS,EAAC,KAAK,CAAC,gBAAgB,EAAE,OAAO,EAAE,mDAA2B,CAAC,CAAC;YAExE,IAAI,SAAS,KAAK,aAAa,EAAE;gBAC7B,IAAA,qBAAS,EAAC,KAAK,CAAC,gBAAgB,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC;gBAC/D,IAAA,qBAAS,EAAC,KAAK,CAAC,gBAAgB,EAAE,WAAW,EAAE,kBAAkB,CAAC,CAAC;aACtE;YAED,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;QAEO,wCAAkB,GAA1B,UAA2B,KAAuB;;YAC9C,IAAI,IAAI,CAAC,uBAAuB,EAAE;gBACxB,IAAA,KAKF,IAAI,CAAC,uBAAuB,EAJ5B,iBAAe,qBAAA,EACf,qBAAmB,yBAAA,EACnB,qBAAqB,2BAAA,EACrB,wBAAwB,8BACI,CAAC;gBACjC,IAAA,2CAAa,EAAC,iBAAe,CAAC,CAAC,OAAO,CAAC,UAAA,GAAG;oBACtC,OAAA,IAAA,+CAAsB,EAClB,KAAK,CAAC,gBAAgB,CAAC,eAAe,EACtC,GAAG,EACH,iBAAe,CAAC,GAAG,CAAC,CACvB;gBAJD,CAIC,CACJ,CAAC;gBACF,IAAA,2CAAa,EAAC,qBAAmB,CAAC,CAAC,OAAO,CAAC,UAAA,GAAG;oBAC1C,OAAA,IAAA,+CAAsB,EAClB,KAAK,CAAC,gBAAgB,CAAC,mBAAmB,EAC1C,GAAG,EACH,qBAAmB,CAAC,GAAG,CAAC,CAC3B;gBAJD,CAIC,CACJ,CAAC;gBACF,CAAA,KAAA,KAAK,CAAC,gBAAgB,CAAC,qBAAqB,CAAA,CAAC,IAAI,8DAAI,qBAAqB,WAAE;gBAC5E,CAAA,KAAA,KAAK,CAAC,gBAAgB,CAAC,wBAAwB,CAAA,CAAC,IAAI,8DAAI,wBAAwB,WAAE;aACrF;QACL,CAAC;QACL,kBAAC;IAAD,CAAC,AAvID,IAuIC;IAvIY,kCAAW;IAyIxB;;;OAGG;IACH,IAAM,kBAAkB,GAA0C,UAC9D,MAA+B,EAC/B,OAAoB;QAEpB,IAAI,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE;YAC/B,OAAO,MAAM,CAAC,eAAe,CAAC;SACjC;IACL,CAAC,CAAC;IAEF,IAAM,iBAAiB,GAAG,IAAI,GAAG,CAO/B;QACE,CAAC,WAAW,EAAE,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC;QAChF,CAAC,aAAa,EAAE,EAAE,CAAC,EAAE,kBAAkB,EAAE,CAAC,EAAE,kBAAkB,EAAE,CAAC,EAAE,kBAAkB,EAAE,CAAC;QACxF,CAAC,cAAc,EAAE,EAAE,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE,mBAAmB,EAAE,CAAC;QAC5F,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,iBAAiB,EAAE,CAAC,EAAE,iBAAiB,EAAE,CAAC,EAAE,iBAAiB,EAAE,CAAC;KACvF,CAAC,CAAC;IAEH,SAAS,iBAAiB,CAAC,MAAmC,EAAE,OAAoB;QAChF,wCAAU,CAAC,OAAO,CAAC,UAAA,GAAG;YAClB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;gBACd,IAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBAC5C,IACI,QAAQ;oBACR,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;oBACzB,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;oBACzB,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAC5B;oBACE,MAAM,CAAC,GAAG,CAAC,GAAM,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAI,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAG,CAAC;iBAC7E;aACJ;QACL,CAAC,CAAC,CAAC;IACP,CAAC","sourcesContent":["import { addParser } from './utils/addParser';\nimport { BorderKeys, getObjectKeys } from 'roosterjs-content-model-dom';\nimport { chainSanitizerCallback } from './utils/chainSanitizerCallback';\nimport { DefaultSanitizers } from './DefaultSanitizers';\nimport { deprecatedBorderColorParser } from './utils/deprecatedColorParser';\nimport { getPasteSource } from './pasteSourceValidations/getPasteSource';\nimport { parseLink } from './utils/linkParser';\nimport { PastePropertyNames } from './pasteSourceValidations/constants';\nimport { processPastedContentFromExcel } from './Excel/processPastedContentFromExcel';\nimport { processPastedContentFromPowerPoint } from './PowerPoint/processPastedContentFromPowerPoint';\nimport { processPastedContentFromWordDesktop } from './WordDesktop/processPastedContentFromWordDesktop';\nimport { processPastedContentWacComponents } from './WacComponents/processPastedContentWacComponents';\nimport type {\n BeforePasteEvent,\n BorderFormat,\n ContentModelBlockFormat,\n ContentModelTableCellFormat,\n DomToModelOptionForSanitizing,\n EditorPlugin,\n FormatParser,\n IEditor,\n PluginEvent,\n} from 'roosterjs-content-model-types';\n\n/**\n * Paste plugin, handles BeforePaste event and reformat some special content, including:\n * 1. Content copied from Word\n * 2. Content copied from Excel\n * 3. Content copied from Word Online or OneNote Online\n * 4. Content copied from Power Point\n */\nexport class PastePlugin implements EditorPlugin {\n private editor: IEditor | null = null;\n\n /**\n * Construct a new instance of Paste class\n * @param unknownTagReplacement Replace solution of unknown tags, default behavior is to replace with SPAN\n * @param allowExcelNoBorderTable Allow table copied from Excel without border\n */\n constructor(\n private allowExcelNoBorderTable?: boolean,\n private domToModelForSanitizing: Pick<\n DomToModelOptionForSanitizing,\n | 'additionalAllowedTags'\n | 'additionalDisallowedTags'\n | 'styleSanitizers'\n | 'attributeSanitizers'\n > = {\n styleSanitizers: DefaultSanitizers,\n additionalAllowedTags: [],\n additionalDisallowedTags: [],\n attributeSanitizers: {},\n }\n ) {}\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'Paste';\n }\n\n /**\n * The first method that editor will call to a plugin when editor is initializing.\n * It will pass in the editor instance, plugin should take this chance to save the\n * editor reference so that it can call to any editor method or format API later.\n * @param editor The editor object\n */\n initialize(editor: IEditor) {\n this.editor = editor;\n }\n\n /**\n * The last method that editor will call to a plugin before it is disposed.\n * Plugin can take this chance to clear the reference to editor. After this method is\n * called, plugin should not call to any editor method since it will result in error.\n */\n dispose() {\n this.editor = null;\n }\n\n /**\n * Core method for a plugin. Once an event happens in editor, editor will call this\n * method of each plugin to handle the event as long as the event is not handled\n * exclusively by another plugin.\n * @param event The event to handle:\n */\n onPluginEvent(event: PluginEvent) {\n if (!this.editor || event.eventType != 'beforePaste') {\n return;\n }\n\n if (!event.domToModelOption) {\n return;\n }\n\n const pasteSource = getPasteSource(event, false);\n const pasteType = event.pasteType;\n\n switch (pasteSource) {\n case 'wordDesktop':\n processPastedContentFromWordDesktop(event, this.editor.getDOMCreator());\n break;\n case 'wacComponents':\n processPastedContentWacComponents(event);\n break;\n case 'excelOnline':\n case 'excelDesktop':\n if (pasteType === 'normal' || pasteType === 'mergeFormat') {\n // Handle HTML copied from Excel\n processPastedContentFromExcel(\n event,\n this.editor.getDOMCreator(),\n this.allowExcelNoBorderTable\n );\n }\n break;\n case 'googleSheets':\n event.domToModelOption.additionalAllowedTags.push(\n PastePropertyNames.GOOGLE_SHEET_NODE_NAME as Lowercase<string>\n );\n break;\n case 'powerPointDesktop':\n processPastedContentFromPowerPoint(event, this.editor.getDOMCreator());\n break;\n }\n\n addParser(event.domToModelOption, 'link', parseLink);\n addParser(event.domToModelOption, 'tableCell', deprecatedBorderColorParser);\n addParser(event.domToModelOption, 'tableCell', tableBorderParser);\n addParser(event.domToModelOption, 'table', deprecatedBorderColorParser);\n\n if (pasteType === 'mergeFormat') {\n addParser(event.domToModelOption, 'block', blockElementParser);\n addParser(event.domToModelOption, 'listLevel', blockElementParser);\n }\n\n this.setEventSanitizers(event);\n }\n\n private setEventSanitizers(event: BeforePasteEvent) {\n if (this.domToModelForSanitizing) {\n const {\n styleSanitizers,\n attributeSanitizers,\n additionalAllowedTags,\n additionalDisallowedTags,\n } = this.domToModelForSanitizing;\n getObjectKeys(styleSanitizers).forEach(key =>\n chainSanitizerCallback(\n event.domToModelOption.styleSanitizers,\n key,\n styleSanitizers[key]\n )\n );\n getObjectKeys(attributeSanitizers).forEach(key =>\n chainSanitizerCallback(\n event.domToModelOption.attributeSanitizers,\n key,\n attributeSanitizers[key]\n )\n );\n event.domToModelOption.additionalAllowedTags.push(...additionalAllowedTags);\n event.domToModelOption.additionalDisallowedTags.push(...additionalDisallowedTags);\n }\n }\n}\n\n/**\n * For block elements that have background color style, remove the background color when user selects the merge current format\n * paste option\n */\nconst blockElementParser: FormatParser<ContentModelBlockFormat> = (\n format: ContentModelBlockFormat,\n element: HTMLElement\n) => {\n if (element.style.backgroundColor) {\n delete format.backgroundColor;\n }\n};\n\nconst ElementBorderKeys = new Map<\n keyof BorderFormat,\n {\n c: keyof CSSStyleDeclaration;\n s: keyof CSSStyleDeclaration;\n w: keyof CSSStyleDeclaration;\n }\n>([\n ['borderTop', { w: 'borderTopWidth', s: 'borderTopStyle', c: 'borderTopColor' }],\n ['borderRight', { w: 'borderRightWidth', s: 'borderRightStyle', c: 'borderRightColor' }],\n ['borderBottom', { w: 'borderBottomWidth', s: 'borderBottomStyle', c: 'borderBottomColor' }],\n ['borderLeft', { w: 'borderLeftWidth', s: 'borderLeftStyle', c: 'borderLeftColor' }],\n]);\n\nfunction tableBorderParser(format: ContentModelTableCellFormat, element: HTMLElement): void {\n BorderKeys.forEach(key => {\n if (!format[key]) {\n const styleSet = ElementBorderKeys.get(key);\n if (\n styleSet &&\n element.style[styleSet.w] &&\n element.style[styleSet.s] &&\n !element.style[styleSet.c]\n ) {\n format[key] = `${element.style[styleSet.w]} ${element.style[styleSet.s]}`;\n }\n }\n });\n}\n"]}
1
+ {"version":3,"file":"PastePlugin.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/paste/PastePlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { addParser } from './utils/addParser';\nimport { BorderKeys, getObjectKeys } from 'roosterjs-content-model-dom';\nimport { chainSanitizerCallback } from './utils/chainSanitizerCallback';\nimport { DefaultSanitizers } from './DefaultSanitizers';\nimport { deprecatedBorderColorParser } from './utils/deprecatedColorParser';\nimport { getPasteSource } from './pasteSourceValidations/getPasteSource';\nimport { parseLink } from './utils/linkParser';\nimport { PastePropertyNames } from './pasteSourceValidations/constants';\nimport { processPastedContentFromExcel } from './Excel/processPastedContentFromExcel';\nimport { processPastedContentFromPowerPoint } from './PowerPoint/processPastedContentFromPowerPoint';\nimport { processPastedContentFromWordDesktop } from './WordDesktop/processPastedContentFromWordDesktop';\nimport { processPastedContentWacComponents } from './WacComponents/processPastedContentWacComponents';\nimport type {\n BeforePasteEvent,\n BorderFormat,\n ContentModelBlockFormat,\n ContentModelTableCellFormat,\n DomToModelOptionForSanitizing,\n EditorPlugin,\n FormatParser,\n IEditor,\n PluginEvent,\n} from 'roosterjs-content-model-types';\n\n/**\n * Paste plugin, handles BeforePaste event and reformat some special content, including:\n * 1. Content copied from Word\n * 2. Content copied from Excel\n * 3. Content copied from Word Online or OneNote Online\n * 4. Content copied from Power Point\n */\nexport class PastePlugin implements EditorPlugin {\n private editor: IEditor | null = null;\n\n /**\n * Construct a new instance of Paste class\n * @param unknownTagReplacement Replace solution of unknown tags, default behavior is to replace with SPAN\n * @param allowExcelNoBorderTable Allow table copied from Excel without border\n */\n constructor(\n private allowExcelNoBorderTable?: boolean,\n private domToModelForSanitizing: Pick<\n DomToModelOptionForSanitizing,\n | 'additionalAllowedTags'\n | 'additionalDisallowedTags'\n | 'styleSanitizers'\n | 'attributeSanitizers'\n > = {\n styleSanitizers: DefaultSanitizers,\n additionalAllowedTags: [],\n additionalDisallowedTags: [],\n attributeSanitizers: {},\n }\n ) {}\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'Paste';\n }\n\n /**\n * The first method that editor will call to a plugin when editor is initializing.\n * It will pass in the editor instance, plugin should take this chance to save the\n * editor reference so that it can call to any editor method or format API later.\n * @param editor The editor object\n */\n initialize(editor: IEditor) {\n this.editor = editor;\n }\n\n /**\n * The last method that editor will call to a plugin before it is disposed.\n * Plugin can take this chance to clear the reference to editor. After this method is\n * called, plugin should not call to any editor method since it will result in error.\n */\n dispose() {\n this.editor = null;\n }\n\n /**\n * Core method for a plugin. Once an event happens in editor, editor will call this\n * method of each plugin to handle the event as long as the event is not handled\n * exclusively by another plugin.\n * @param event The event to handle:\n */\n onPluginEvent(event: PluginEvent) {\n if (!this.editor || event.eventType != 'beforePaste') {\n return;\n }\n\n if (!event.domToModelOption) {\n return;\n }\n\n const pasteSource = getPasteSource(event, false);\n const pasteType = event.pasteType;\n\n switch (pasteSource) {\n case 'wordDesktop':\n processPastedContentFromWordDesktop(event, this.editor.getDOMCreator());\n break;\n case 'wacComponents':\n processPastedContentWacComponents(event);\n break;\n case 'excelOnline':\n case 'excelDesktop':\n case 'excelNonNativeEvent':\n if (pasteType === 'normal' || pasteType === 'mergeFormat') {\n // Handle HTML copied from Excel\n processPastedContentFromExcel(\n event,\n this.editor.getDOMCreator(),\n !!this.allowExcelNoBorderTable,\n pasteSource != 'excelNonNativeEvent' /* isNativeEvent */\n );\n }\n break;\n case 'googleSheets':\n event.domToModelOption.additionalAllowedTags.push(\n PastePropertyNames.GOOGLE_SHEET_NODE_NAME as Lowercase<string>\n );\n break;\n case 'powerPointDesktop':\n processPastedContentFromPowerPoint(event, this.editor.getDOMCreator());\n break;\n }\n\n addParser(event.domToModelOption, 'link', parseLink);\n addParser(event.domToModelOption, 'tableCell', deprecatedBorderColorParser);\n addParser(event.domToModelOption, 'tableCell', tableBorderParser);\n addParser(event.domToModelOption, 'table', deprecatedBorderColorParser);\n\n if (pasteType === 'mergeFormat') {\n addParser(event.domToModelOption, 'block', blockElementParser);\n addParser(event.domToModelOption, 'listLevel', blockElementParser);\n }\n\n this.setEventSanitizers(event);\n }\n\n private setEventSanitizers(event: BeforePasteEvent) {\n if (this.domToModelForSanitizing) {\n const {\n styleSanitizers,\n attributeSanitizers,\n additionalAllowedTags,\n additionalDisallowedTags,\n } = this.domToModelForSanitizing;\n getObjectKeys(styleSanitizers).forEach(key =>\n chainSanitizerCallback(\n event.domToModelOption.styleSanitizers,\n key,\n styleSanitizers[key]\n )\n );\n getObjectKeys(attributeSanitizers).forEach(key =>\n chainSanitizerCallback(\n event.domToModelOption.attributeSanitizers,\n key,\n attributeSanitizers[key]\n )\n );\n event.domToModelOption.additionalAllowedTags.push(...additionalAllowedTags);\n event.domToModelOption.additionalDisallowedTags.push(...additionalDisallowedTags);\n }\n }\n}\n\n/**\n * For block elements that have background color style, remove the background color when user selects the merge current format\n * paste option\n */\nconst blockElementParser: FormatParser<ContentModelBlockFormat> = (\n format: ContentModelBlockFormat,\n element: HTMLElement\n) => {\n if (element.style.backgroundColor) {\n delete format.backgroundColor;\n }\n};\n\nconst ElementBorderKeys = new Map<\n keyof BorderFormat,\n {\n c: keyof CSSStyleDeclaration;\n s: keyof CSSStyleDeclaration;\n w: keyof CSSStyleDeclaration;\n }\n>([\n ['borderTop', { w: 'borderTopWidth', s: 'borderTopStyle', c: 'borderTopColor' }],\n ['borderRight', { w: 'borderRightWidth', s: 'borderRightStyle', c: 'borderRightColor' }],\n ['borderBottom', { w: 'borderBottomWidth', s: 'borderBottomStyle', c: 'borderBottomColor' }],\n ['borderLeft', { w: 'borderLeftWidth', s: 'borderLeftStyle', c: 'borderLeftColor' }],\n]);\n\nfunction tableBorderParser(format: ContentModelTableCellFormat, element: HTMLElement): void {\n BorderKeys.forEach(key => {\n if (!format[key]) {\n const styleSet = ElementBorderKeys.get(key);\n if (\n styleSet &&\n element.style[styleSet.w] &&\n element.style[styleSet.s] &&\n !element.style[styleSet.c]\n ) {\n format[key] = `${element.style[styleSet.w]} ${element.style[styleSet.s]}`;\n }\n }\n });\n}\n"]}
@@ -12,7 +12,7 @@ export declare type GetSourceInputParams = {
12
12
  * @internal
13
13
  * Represent the types of sources to handle in the Paste Plugin
14
14
  */
15
- export declare type KnownPasteSourceType = 'wordDesktop' | 'excelDesktop' | 'excelOnline' | 'powerPointDesktop' | 'googleSheets' | 'wacComponents' | 'default' | 'singleImage';
15
+ export declare type KnownPasteSourceType = 'wordDesktop' | 'excelDesktop' | 'excelOnline' | 'powerPointDesktop' | 'googleSheets' | 'wacComponents' | 'default' | 'singleImage' | 'excelNonNativeEvent';
16
16
  /**
17
17
  * @internal
18
18
  */
@@ -1,4 +1,4 @@
1
- define(["require", "exports", "./documentContainWacElements", "./isExcelDesktopDocument", "./isExcelOnlineDocument", "./isGoogleSheetDocument", "./isPowerPointDesktopDocument", "./isWordDesktopDocument", "./shouldConvertToSingleImage"], function (require, exports, documentContainWacElements_1, isExcelDesktopDocument_1, isExcelOnlineDocument_1, isGoogleSheetDocument_1, isPowerPointDesktopDocument_1, isWordDesktopDocument_1, shouldConvertToSingleImage_1) {
1
+ define(["require", "exports", "./documentContainWacElements", "./isExcelDesktopDocument", "./isExcelNonNativeEvent", "./isExcelOnlineDocument", "./isGoogleSheetDocument", "./isPowerPointDesktopDocument", "./isWordDesktopDocument", "./shouldConvertToSingleImage"], function (require, exports, documentContainWacElements_1, isExcelDesktopDocument_1, isExcelNonNativeEvent_1, isExcelOnlineDocument_1, isGoogleSheetDocument_1, isPowerPointDesktopDocument_1, isWordDesktopDocument_1, shouldConvertToSingleImage_1) {
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.getPasteSource = void 0;
@@ -10,6 +10,7 @@ define(["require", "exports", "./documentContainWacElements", "./isExcelDesktopD
10
10
  ['wacComponents', documentContainWacElements_1.documentContainWacElements],
11
11
  ['googleSheets', isGoogleSheetDocument_1.isGoogleSheetDocument],
12
12
  ['singleImage', shouldConvertToSingleImage_1.shouldConvertToSingleImage],
13
+ ['excelNonNativeEvent', isExcelNonNativeEvent_1.isExcelNotNativeEvent],
13
14
  ]);
14
15
  /**
15
16
  * @internal
@@ -1 +1 @@
1
- {"version":3,"file":"getPasteSource.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/paste/pasteSourceValidations/getPasteSource.ts"],"names":[],"mappings":";;;;IAsCA,IAAM,kBAAkB,GAAG,IAAI,GAAG,CAA0C;QACxE,CAAC,aAAa,EAAE,6CAAqB,CAAC;QACtC,CAAC,cAAc,EAAE,+CAAsB,CAAC;QACxC,CAAC,aAAa,EAAE,6CAAqB,CAAC;QACtC,CAAC,mBAAmB,EAAE,yDAA2B,CAAC;QAClD,CAAC,eAAe,EAAE,uDAA0B,CAAC;QAC7C,CAAC,cAAc,EAAE,6CAAqB,CAAC;QACvC,CAAC,aAAa,EAAE,uDAA0B,CAAC;KAC9C,CAAC,CAAC;IAEH;;;;;;OAMG;IACH,SAAgB,cAAc,CAC1B,KAAuB,EACvB,wBAAiC;QAEzB,IAAA,cAAc,GAA8B,KAAK,eAAnC,EAAE,aAAa,GAAe,KAAK,cAApB,EAAE,QAAQ,GAAK,KAAK,SAAV,CAAW;QAE1D,IAAI,MAAM,GAAgC,IAAI,CAAC;QAC/C,IAAM,KAAK,GAAyB;YAChC,cAAc,gBAAA;YACd,QAAQ,UAAA;YACR,wBAAwB,0BAAA;YACxB,aAAa,eAAA;SAChB,CAAC;QAEF,kBAAkB,CAAC,OAAO,CAAC,UAAC,IAAI,EAAE,GAAG;YACjC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE;gBACxB,MAAM,GAAG,GAAG,CAAC;aAChB;QACL,CAAC,CAAC,CAAC;QAEH,OAAO,MAAM,aAAN,MAAM,cAAN,MAAM,GAAI,SAAS,CAAC;IAC/B,CAAC;IArBD,wCAqBC","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-content-model-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/roosterjs-content-model-plugins/lib/paste/pasteSourceValidations/getPasteSource.ts"],"names":[],"mappings":";;;;IAwCA,IAAM,kBAAkB,GAAG,IAAI,GAAG,CAA0C;QACxE,CAAC,aAAa,EAAE,6CAAqB,CAAC;QACtC,CAAC,cAAc,EAAE,+CAAsB,CAAC;QACxC,CAAC,aAAa,EAAE,6CAAqB,CAAC;QACtC,CAAC,mBAAmB,EAAE,yDAA2B,CAAC;QAClD,CAAC,eAAe,EAAE,uDAA0B,CAAC;QAC7C,CAAC,cAAc,EAAE,6CAAqB,CAAC;QACvC,CAAC,aAAa,EAAE,uDAA0B,CAAC;QAC3C,CAAC,qBAAqB,EAAE,6CAAqB,CAAC;KACjD,CAAC,CAAC;IAEH;;;;;;OAMG;IACH,SAAgB,cAAc,CAC1B,KAAuB,EACvB,wBAAiC;QAEzB,IAAA,cAAc,GAA8B,KAAK,eAAnC,EAAE,aAAa,GAAe,KAAK,cAApB,EAAE,QAAQ,GAAK,KAAK,SAAV,CAAW;QAE1D,IAAI,MAAM,GAAgC,IAAI,CAAC;QAC/C,IAAM,KAAK,GAAyB;YAChC,cAAc,gBAAA;YACd,QAAQ,UAAA;YACR,wBAAwB,0BAAA;YACxB,aAAa,eAAA;SAChB,CAAC;QAEF,kBAAkB,CAAC,OAAO,CAAC,UAAC,IAAI,EAAE,GAAG;YACjC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE;gBACxB,MAAM,GAAG,GAAG,CAAC;aAChB;QACL,CAAC,CAAC,CAAC;QAEH,OAAO,MAAM,aAAN,MAAM,cAAN,MAAM,GAAI,SAAS,CAAC;IAC/B,CAAC;IArBD,wCAqBC","sourcesContent":["import { documentContainWacElements } from './documentContainWacElements';\nimport { isExcelDesktopDocument } from './isExcelDesktopDocument';\nimport { isExcelNotNativeEvent } from './isExcelNonNativeEvent';\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-content-model-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 | 'excelNonNativeEvent';\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 ['excelNonNativeEvent', isExcelNotNativeEvent],\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"]}
@@ -0,0 +1,7 @@
1
+ import type { GetSourceFunction } from './getPasteSource';
2
+ /**
3
+ * @internal
4
+ * When the clipboard content is retrieved programatically, the clipboard html does not contain the usual
5
+ * attributes we use to determine if the content is from Excel. This function is used to handle that case.
6
+ */
7
+ export declare const isExcelNotNativeEvent: GetSourceFunction;
@@ -0,0 +1,20 @@
1
+ define(["require", "exports"], function (require, exports) {
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.isExcelNotNativeEvent = void 0;
5
+ var ShadowWorkbookClipboardType = 'web data/shadow-workbook';
6
+ /**
7
+ * @internal
8
+ * When the clipboard content is retrieved programatically, the clipboard html does not contain the usual
9
+ * attributes we use to determine if the content is from Excel. This function is used to handle that case.
10
+ */
11
+ var isExcelNotNativeEvent = function (props) {
12
+ var _a;
13
+ var clipboardData = props.clipboardData;
14
+ return (clipboardData.types.includes(ShadowWorkbookClipboardType) &&
15
+ ((_a = clipboardData.htmlFirstLevelChildTags) === null || _a === void 0 ? void 0 : _a.length) == 1 &&
16
+ clipboardData.htmlFirstLevelChildTags[0] == 'TABLE');
17
+ };
18
+ exports.isExcelNotNativeEvent = isExcelNotNativeEvent;
19
+ });
20
+ //# sourceMappingURL=isExcelNonNativeEvent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isExcelNonNativeEvent.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/paste/pasteSourceValidations/isExcelNonNativeEvent.ts"],"names":[],"mappings":";;;;IAEA,IAAM,2BAA2B,GAAG,0BAA0B,CAAC;IAE/D;;;;OAIG;IACI,IAAM,qBAAqB,GAAsB,UAAC,KAA2B;;QACxE,IAAA,aAAa,GAAK,KAAK,cAAV,CAAW;QAEhC,OAAO,CACH,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,2BAA2B,CAAC;YACzD,CAAA,MAAA,aAAa,CAAC,uBAAuB,0CAAE,MAAM,KAAI,CAAC;YAClD,aAAa,CAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI,OAAO,CACtD,CAAC;IACN,CAAC,CAAC;IARW,QAAA,qBAAqB,yBAQhC","sourcesContent":["import type { GetSourceFunction, GetSourceInputParams } from './getPasteSource';\n\nconst ShadowWorkbookClipboardType = 'web data/shadow-workbook';\n\n/**\n * @internal\n * When the clipboard content is retrieved programatically, the clipboard html does not contain the usual\n * attributes we use to determine if the content is from Excel. This function is used to handle that case.\n */\nexport const isExcelNotNativeEvent: GetSourceFunction = (props: GetSourceInputParams) => {\n const { clipboardData } = props;\n\n return (\n clipboardData.types.includes(ShadowWorkbookClipboardType) &&\n clipboardData.htmlFirstLevelChildTags?.length == 1 &&\n clipboardData.htmlFirstLevelChildTags[0] == 'TABLE'\n );\n};\n"]}
@@ -3,13 +3,11 @@ import type { BeforePasteEvent, ClipboardData, DOMCreator, ElementProcessor } fr
3
3
  * @internal
4
4
  * Convert pasted content from Excel, add borders when source doc doesn't have a border
5
5
  * @param event The BeforePaste event
6
+ * @param domCreator The DOM creator
7
+ * @param allowExcelNoBorderTable Allow table copied from Excel without border
8
+ * @param isNativeEvent Whether the event is native event
6
9
  */
7
- export declare function processPastedContentFromExcel(event: BeforePasteEvent, domCreator: DOMCreator, allowExcelNoBorderTable?: boolean): void;
8
- /**
9
- * @internal
10
- * Exported only for unit test
11
- */
12
- export declare const childProcessor: ElementProcessor<ParentNode>;
10
+ export declare function processPastedContentFromExcel(event: BeforePasteEvent, domCreator: DOMCreator, allowExcelNoBorderTable: boolean, isNativeEvent: boolean): void;
13
11
  /**
14
12
  * @internal
15
13
  * Exported only for unit test
@@ -20,3 +18,13 @@ export declare function validateExcelFragment(fragment: DocumentFragment, domCre
20
18
  * @param html Source html
21
19
  */
22
20
  export declare function excelHandler(html: string, htmlBefore: string): string;
21
+ /**
22
+ * @internal
23
+ * Exported only for unit test
24
+ */
25
+ export declare function setupExcelTableHandlers(event: BeforePasteEvent, allowExcelNoBorderTable: boolean | undefined, isNativeEvent: boolean): void;
26
+ /**
27
+ * @internal
28
+ * Exported only for unit test
29
+ */
30
+ export declare const childProcessor: ElementProcessor<ParentNode>;
@@ -6,16 +6,22 @@ var LAST_TD_END_REGEX = /<\/\s*td\s*>((?!<\/\s*tr\s*>)[\s\S])*$/i;
6
6
  var LAST_TR_END_REGEX = /<\/\s*tr\s*>((?!<\/\s*table\s*>)[\s\S])*$/i;
7
7
  var LAST_TR_REGEX = /<tr[^>]*>[^<]*/i;
8
8
  var LAST_TABLE_REGEX = /<table[^>]*>[^<]*/i;
9
- var DEFAULT_BORDER_STYLE = 'solid 1px #d4d4d4';
10
9
  var TABLE_SELECTOR = 'table';
10
+ var DEFAULT_BORDER_STYLE = 'solid 1px #d4d4d4';
11
11
  /**
12
12
  * @internal
13
13
  * Convert pasted content from Excel, add borders when source doc doesn't have a border
14
14
  * @param event The BeforePaste event
15
+ * @param domCreator The DOM creator
16
+ * @param allowExcelNoBorderTable Allow table copied from Excel without border
17
+ * @param isNativeEvent Whether the event is native event
15
18
  */
16
- export function processPastedContentFromExcel(event, domCreator, allowExcelNoBorderTable) {
19
+ export function processPastedContentFromExcel(event, domCreator, allowExcelNoBorderTable, isNativeEvent) {
17
20
  var fragment = event.fragment, htmlBefore = event.htmlBefore, htmlAfter = event.htmlAfter, clipboardData = event.clipboardData;
18
- validateExcelFragment(fragment, domCreator, htmlBefore, clipboardData, htmlAfter);
21
+ // For non native event we already validated that the content contains a table
22
+ if (isNativeEvent) {
23
+ validateExcelFragment(fragment, domCreator, htmlBefore, clipboardData, htmlAfter);
24
+ }
19
25
  // For Excel Online
20
26
  var firstChild = fragment.firstChild;
21
27
  if (isNodeOfType(firstChild, 'ELEMENT_NODE') &&
@@ -35,33 +41,8 @@ export function processPastedContentFromExcel(event, domCreator, allowExcelNoBor
35
41
  event.fragment.replaceChildren(firstChild.lastChild);
36
42
  }
37
43
  }
38
- addParser(event.domToModelOption, 'tableCell', function (format, element) {
39
- if (!allowExcelNoBorderTable && element.style.borderStyle === 'none') {
40
- format.borderBottom = DEFAULT_BORDER_STYLE;
41
- format.borderLeft = DEFAULT_BORDER_STYLE;
42
- format.borderRight = DEFAULT_BORDER_STYLE;
43
- format.borderTop = DEFAULT_BORDER_STYLE;
44
- }
45
- });
46
- setProcessor(event.domToModelOption, 'child', childProcessor);
44
+ setupExcelTableHandlers(event, allowExcelNoBorderTable, isNativeEvent /* handleForNativeEvent */);
47
45
  }
48
- /**
49
- * @internal
50
- * Exported only for unit test
51
- */
52
- export var childProcessor = function (group, element, context) {
53
- var segmentFormat = __assign({}, context.segmentFormat);
54
- if (group.blockGroupType === 'TableCell' &&
55
- group.format.textColor &&
56
- !context.segmentFormat.textColor) {
57
- context.segmentFormat.textColor = group.format.textColor;
58
- }
59
- context.defaultElementProcessors.child(group, element, context);
60
- if (group.blockGroupType === 'TableCell' && group.format.textColor) {
61
- context.segmentFormat = segmentFormat;
62
- delete group.format.textColor;
63
- }
64
- };
65
46
  /**
66
47
  * @internal
67
48
  * Exported only for unit test
@@ -115,4 +96,38 @@ export function excelHandler(html, htmlBefore) {
115
96
  return html;
116
97
  }
117
98
  }
99
+ /**
100
+ * @internal
101
+ * Exported only for unit test
102
+ */
103
+ export function setupExcelTableHandlers(event, allowExcelNoBorderTable, isNativeEvent) {
104
+ addParser(event.domToModelOption, 'tableCell', function (format, element) {
105
+ if (!allowExcelNoBorderTable &&
106
+ (element.style.borderStyle === 'none' ||
107
+ (!isNativeEvent && element.style.borderStyle == ''))) {
108
+ format.borderBottom = DEFAULT_BORDER_STYLE;
109
+ format.borderLeft = DEFAULT_BORDER_STYLE;
110
+ format.borderRight = DEFAULT_BORDER_STYLE;
111
+ format.borderTop = DEFAULT_BORDER_STYLE;
112
+ }
113
+ });
114
+ setProcessor(event.domToModelOption, 'child', childProcessor);
115
+ }
116
+ /**
117
+ * @internal
118
+ * Exported only for unit test
119
+ */
120
+ export var childProcessor = function (group, element, context) {
121
+ var segmentFormat = __assign({}, context.segmentFormat);
122
+ if (group.blockGroupType === 'TableCell' &&
123
+ group.format.textColor &&
124
+ !context.segmentFormat.textColor) {
125
+ context.segmentFormat.textColor = group.format.textColor;
126
+ }
127
+ context.defaultElementProcessors.child(group, element, context);
128
+ if (group.blockGroupType === 'TableCell' && group.format.textColor) {
129
+ context.segmentFormat = segmentFormat;
130
+ delete group.format.textColor;
131
+ }
132
+ };
118
133
  //# sourceMappingURL=processPastedContentFromExcel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"processPastedContentFromExcel.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/paste/Excel/processPastedContentFromExcel.ts"],"names":[],"mappings":"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","sourcesContent":["import { addParser } from '../utils/addParser';\nimport { isNodeOfType, moveChildNodes } from 'roosterjs-content-model-dom';\nimport { setProcessor } from '../utils/setProcessor';\nimport type {\n BeforePasteEvent,\n ClipboardData,\n DOMCreator,\n ElementProcessor,\n} from 'roosterjs-content-model-types';\n\nconst LAST_TD_END_REGEX = /<\\/\\s*td\\s*>((?!<\\/\\s*tr\\s*>)[\\s\\S])*$/i;\nconst LAST_TR_END_REGEX = /<\\/\\s*tr\\s*>((?!<\\/\\s*table\\s*>)[\\s\\S])*$/i;\nconst LAST_TR_REGEX = /<tr[^>]*>[^<]*/i;\nconst LAST_TABLE_REGEX = /<table[^>]*>[^<]*/i;\nconst DEFAULT_BORDER_STYLE = 'solid 1px #d4d4d4';\nconst TABLE_SELECTOR = 'table';\n\n/**\n * @internal\n * Convert pasted content from Excel, add borders when source doc doesn't have a border\n * @param event The BeforePaste event\n */\n\nexport function processPastedContentFromExcel(\n event: BeforePasteEvent,\n domCreator: DOMCreator,\n allowExcelNoBorderTable?: boolean\n) {\n const { fragment, htmlBefore, htmlAfter, clipboardData } = event;\n\n validateExcelFragment(fragment, domCreator, htmlBefore, clipboardData, htmlAfter);\n\n // For Excel Online\n const firstChild = fragment.firstChild;\n if (\n isNodeOfType(firstChild, 'ELEMENT_NODE') &&\n firstChild.tagName == 'div' &&\n firstChild.firstChild\n ) {\n const tableFound = Array.from(firstChild.childNodes).every((child: Node) => {\n // Tables pasted from Excel Online should be of the format: 0 to N META tags and 1 TABLE tag\n const tagName = isNodeOfType(child, 'ELEMENT_NODE') && child.tagName;\n\n return tagName == 'META'\n ? true\n : tagName == 'TABLE'\n ? child == firstChild.lastChild\n : false;\n });\n\n // Extract Table from Div\n if (tableFound && firstChild.lastChild) {\n event.fragment.replaceChildren(firstChild.lastChild);\n }\n }\n\n addParser(event.domToModelOption, 'tableCell', (format, element) => {\n if (!allowExcelNoBorderTable && element.style.borderStyle === 'none') {\n format.borderBottom = DEFAULT_BORDER_STYLE;\n format.borderLeft = DEFAULT_BORDER_STYLE;\n format.borderRight = DEFAULT_BORDER_STYLE;\n format.borderTop = DEFAULT_BORDER_STYLE;\n }\n });\n\n setProcessor(event.domToModelOption, 'child', childProcessor);\n}\n\n/**\n * @internal\n * Exported only for unit test\n */\nexport const childProcessor: ElementProcessor<ParentNode> = (group, element, context) => {\n const segmentFormat = { ...context.segmentFormat };\n if (\n group.blockGroupType === 'TableCell' &&\n group.format.textColor &&\n !context.segmentFormat.textColor\n ) {\n context.segmentFormat.textColor = group.format.textColor;\n }\n\n context.defaultElementProcessors.child(group, element, context);\n\n if (group.blockGroupType === 'TableCell' && group.format.textColor) {\n context.segmentFormat = segmentFormat;\n delete group.format.textColor;\n }\n};\n\n/**\n * @internal\n * Exported only for unit test\n */\nexport function validateExcelFragment(\n fragment: DocumentFragment,\n domCreator: DOMCreator,\n htmlBefore: string,\n clipboardData: ClipboardData,\n htmlAfter: string\n) {\n // Clipboard content of Excel may contain the <StartFragment> and EndFragment comment tags inside the table\n //\n // @example\n // <table>\n // <!--StartFragment-->\n // <tr>...</tr>\n // <!--EndFragment-->\n // </table>\n //\n // This causes that the fragment is not properly created and the table is not extracted.\n // The content that is before the StartFragment is htmlBefore and the content that is after the EndFragment is htmlAfter.\n // So attempt to create a new document fragment with the content of htmlBefore + clipboardData.html + htmlAfter\n // If a table is found, replace the fragment with the new fragment\n const result =\n !fragment.querySelector(TABLE_SELECTOR) &&\n domCreator.htmlToDOM(htmlBefore + clipboardData.html + htmlAfter);\n if (result && result.querySelector(TABLE_SELECTOR)) {\n moveChildNodes(fragment, result?.body);\n } else {\n // If the table is still not found, try to extract the table from the clipboard data using Regex\n const html = clipboardData.html ? excelHandler(clipboardData.html, htmlBefore) : undefined;\n\n if (html && clipboardData.html != html) {\n const doc = domCreator.htmlToDOM(html);\n moveChildNodes(fragment, doc?.body);\n }\n }\n}\n\n/**\n * @internal Export for test only\n * @param html Source html\n */\nexport function excelHandler(html: string, htmlBefore: string): string {\n try {\n if (html.match(LAST_TD_END_REGEX)) {\n const trMatch = htmlBefore.match(LAST_TR_REGEX);\n const tr = trMatch ? trMatch[0] : '<TR>';\n html = tr + html + '</TR>';\n }\n if (html.match(LAST_TR_END_REGEX)) {\n const tableMatch = htmlBefore.match(LAST_TABLE_REGEX);\n const table = tableMatch ? tableMatch[0] : '<TABLE>';\n html = table + html + '</TABLE>';\n }\n } finally {\n return html;\n }\n}\n"]}
1
+ {"version":3,"file":"processPastedContentFromExcel.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/paste/Excel/processPastedContentFromExcel.ts"],"names":[],"mappings":"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","sourcesContent":["import { addParser } from '../utils/addParser';\nimport { isNodeOfType, moveChildNodes } from 'roosterjs-content-model-dom';\nimport { setProcessor } from '../utils/setProcessor';\nimport type {\n BeforePasteEvent,\n ClipboardData,\n DOMCreator,\n ElementProcessor,\n} from 'roosterjs-content-model-types';\n\nconst LAST_TD_END_REGEX = /<\\/\\s*td\\s*>((?!<\\/\\s*tr\\s*>)[\\s\\S])*$/i;\nconst LAST_TR_END_REGEX = /<\\/\\s*tr\\s*>((?!<\\/\\s*table\\s*>)[\\s\\S])*$/i;\nconst LAST_TR_REGEX = /<tr[^>]*>[^<]*/i;\nconst LAST_TABLE_REGEX = /<table[^>]*>[^<]*/i;\nconst TABLE_SELECTOR = 'table';\nconst DEFAULT_BORDER_STYLE = 'solid 1px #d4d4d4';\n\n/**\n * @internal\n * Convert pasted content from Excel, add borders when source doc doesn't have a border\n * @param event The BeforePaste event\n * @param domCreator The DOM creator\n * @param allowExcelNoBorderTable Allow table copied from Excel without border\n * @param isNativeEvent Whether the event is native event\n */\nexport function processPastedContentFromExcel(\n event: BeforePasteEvent,\n domCreator: DOMCreator,\n allowExcelNoBorderTable: boolean,\n isNativeEvent: boolean\n) {\n const { fragment, htmlBefore, htmlAfter, clipboardData } = event;\n\n // For non native event we already validated that the content contains a table\n if (isNativeEvent) {\n validateExcelFragment(fragment, domCreator, htmlBefore, clipboardData, htmlAfter);\n }\n\n // For Excel Online\n const firstChild = fragment.firstChild;\n if (\n isNodeOfType(firstChild, 'ELEMENT_NODE') &&\n firstChild.tagName == 'div' &&\n firstChild.firstChild\n ) {\n const tableFound = Array.from(firstChild.childNodes).every((child: Node) => {\n // Tables pasted from Excel Online should be of the format: 0 to N META tags and 1 TABLE tag\n const tagName = isNodeOfType(child, 'ELEMENT_NODE') && child.tagName;\n\n return tagName == 'META'\n ? true\n : tagName == 'TABLE'\n ? child == firstChild.lastChild\n : false;\n });\n\n // Extract Table from Div\n if (tableFound && firstChild.lastChild) {\n event.fragment.replaceChildren(firstChild.lastChild);\n }\n }\n\n setupExcelTableHandlers(\n event,\n allowExcelNoBorderTable,\n isNativeEvent /* handleForNativeEvent */\n );\n}\n\n/**\n * @internal\n * Exported only for unit test\n */\nexport function validateExcelFragment(\n fragment: DocumentFragment,\n domCreator: DOMCreator,\n htmlBefore: string,\n clipboardData: ClipboardData,\n htmlAfter: string\n) {\n // Clipboard content of Excel may contain the <StartFragment> and EndFragment comment tags inside the table\n //\n // @example\n // <table>\n // <!--StartFragment-->\n // <tr>...</tr>\n // <!--EndFragment-->\n // </table>\n //\n // This causes that the fragment is not properly created and the table is not extracted.\n // The content that is before the StartFragment is htmlBefore and the content that is after the EndFragment is htmlAfter.\n // So attempt to create a new document fragment with the content of htmlBefore + clipboardData.html + htmlAfter\n // If a table is found, replace the fragment with the new fragment\n const result =\n !fragment.querySelector(TABLE_SELECTOR) &&\n domCreator.htmlToDOM(htmlBefore + clipboardData.html + htmlAfter);\n if (result && result.querySelector(TABLE_SELECTOR)) {\n moveChildNodes(fragment, result?.body);\n } else {\n // If the table is still not found, try to extract the table from the clipboard data using Regex\n const html = clipboardData.html ? excelHandler(clipboardData.html, htmlBefore) : undefined;\n\n if (html && clipboardData.html != html) {\n const doc = domCreator.htmlToDOM(html);\n moveChildNodes(fragment, doc?.body);\n }\n }\n}\n\n/**\n * @internal Export for test only\n * @param html Source html\n */\nexport function excelHandler(html: string, htmlBefore: string): string {\n try {\n if (html.match(LAST_TD_END_REGEX)) {\n const trMatch = htmlBefore.match(LAST_TR_REGEX);\n const tr = trMatch ? trMatch[0] : '<TR>';\n html = tr + html + '</TR>';\n }\n if (html.match(LAST_TR_END_REGEX)) {\n const tableMatch = htmlBefore.match(LAST_TABLE_REGEX);\n const table = tableMatch ? tableMatch[0] : '<TABLE>';\n html = table + html + '</TABLE>';\n }\n } finally {\n return html;\n }\n}\n\n/**\n * @internal\n * Exported only for unit test\n */\nexport function setupExcelTableHandlers(\n event: BeforePasteEvent,\n allowExcelNoBorderTable: boolean | undefined,\n isNativeEvent: boolean\n) {\n addParser(event.domToModelOption, 'tableCell', (format, element) => {\n if (\n !allowExcelNoBorderTable &&\n (element.style.borderStyle === 'none' ||\n (!isNativeEvent && element.style.borderStyle == ''))\n ) {\n format.borderBottom = DEFAULT_BORDER_STYLE;\n format.borderLeft = DEFAULT_BORDER_STYLE;\n format.borderRight = DEFAULT_BORDER_STYLE;\n format.borderTop = DEFAULT_BORDER_STYLE;\n }\n });\n\n setProcessor(event.domToModelOption, 'child', childProcessor);\n}\n\n/**\n * @internal\n * Exported only for unit test\n */\nexport const childProcessor: ElementProcessor<ParentNode> = (group, element, context) => {\n const segmentFormat = { ...context.segmentFormat };\n if (\n group.blockGroupType === 'TableCell' &&\n group.format.textColor &&\n !context.segmentFormat.textColor\n ) {\n context.segmentFormat.textColor = group.format.textColor;\n }\n\n context.defaultElementProcessors.child(group, element, context);\n\n if (group.blockGroupType === 'TableCell' && group.format.textColor) {\n context.segmentFormat = segmentFormat;\n delete group.format.textColor;\n }\n};\n"]}
@@ -82,9 +82,10 @@ var PastePlugin = /** @class */ (function () {
82
82
  break;
83
83
  case 'excelOnline':
84
84
  case 'excelDesktop':
85
+ case 'excelNonNativeEvent':
85
86
  if (pasteType === 'normal' || pasteType === 'mergeFormat') {
86
87
  // Handle HTML copied from Excel
87
- processPastedContentFromExcel(event, this.editor.getDOMCreator(), this.allowExcelNoBorderTable);
88
+ processPastedContentFromExcel(event, this.editor.getDOMCreator(), !!this.allowExcelNoBorderTable, pasteSource != 'excelNonNativeEvent' /* isNativeEvent */);
88
89
  }
89
90
  break;
90
91
  case 'googleSheets':
@@ -1 +1 @@
1
- {"version":3,"file":"PastePlugin.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/paste/PastePlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { addParser } from './utils/addParser';\nimport { BorderKeys, getObjectKeys } from 'roosterjs-content-model-dom';\nimport { chainSanitizerCallback } from './utils/chainSanitizerCallback';\nimport { DefaultSanitizers } from './DefaultSanitizers';\nimport { deprecatedBorderColorParser } from './utils/deprecatedColorParser';\nimport { getPasteSource } from './pasteSourceValidations/getPasteSource';\nimport { parseLink } from './utils/linkParser';\nimport { PastePropertyNames } from './pasteSourceValidations/constants';\nimport { processPastedContentFromExcel } from './Excel/processPastedContentFromExcel';\nimport { processPastedContentFromPowerPoint } from './PowerPoint/processPastedContentFromPowerPoint';\nimport { processPastedContentFromWordDesktop } from './WordDesktop/processPastedContentFromWordDesktop';\nimport { processPastedContentWacComponents } from './WacComponents/processPastedContentWacComponents';\nimport type {\n BeforePasteEvent,\n BorderFormat,\n ContentModelBlockFormat,\n ContentModelTableCellFormat,\n DomToModelOptionForSanitizing,\n EditorPlugin,\n FormatParser,\n IEditor,\n PluginEvent,\n} from 'roosterjs-content-model-types';\n\n/**\n * Paste plugin, handles BeforePaste event and reformat some special content, including:\n * 1. Content copied from Word\n * 2. Content copied from Excel\n * 3. Content copied from Word Online or OneNote Online\n * 4. Content copied from Power Point\n */\nexport class PastePlugin implements EditorPlugin {\n private editor: IEditor | null = null;\n\n /**\n * Construct a new instance of Paste class\n * @param unknownTagReplacement Replace solution of unknown tags, default behavior is to replace with SPAN\n * @param allowExcelNoBorderTable Allow table copied from Excel without border\n */\n constructor(\n private allowExcelNoBorderTable?: boolean,\n private domToModelForSanitizing: Pick<\n DomToModelOptionForSanitizing,\n | 'additionalAllowedTags'\n | 'additionalDisallowedTags'\n | 'styleSanitizers'\n | 'attributeSanitizers'\n > = {\n styleSanitizers: DefaultSanitizers,\n additionalAllowedTags: [],\n additionalDisallowedTags: [],\n attributeSanitizers: {},\n }\n ) {}\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'Paste';\n }\n\n /**\n * The first method that editor will call to a plugin when editor is initializing.\n * It will pass in the editor instance, plugin should take this chance to save the\n * editor reference so that it can call to any editor method or format API later.\n * @param editor The editor object\n */\n initialize(editor: IEditor) {\n this.editor = editor;\n }\n\n /**\n * The last method that editor will call to a plugin before it is disposed.\n * Plugin can take this chance to clear the reference to editor. After this method is\n * called, plugin should not call to any editor method since it will result in error.\n */\n dispose() {\n this.editor = null;\n }\n\n /**\n * Core method for a plugin. Once an event happens in editor, editor will call this\n * method of each plugin to handle the event as long as the event is not handled\n * exclusively by another plugin.\n * @param event The event to handle:\n */\n onPluginEvent(event: PluginEvent) {\n if (!this.editor || event.eventType != 'beforePaste') {\n return;\n }\n\n if (!event.domToModelOption) {\n return;\n }\n\n const pasteSource = getPasteSource(event, false);\n const pasteType = event.pasteType;\n\n switch (pasteSource) {\n case 'wordDesktop':\n processPastedContentFromWordDesktop(event, this.editor.getDOMCreator());\n break;\n case 'wacComponents':\n processPastedContentWacComponents(event);\n break;\n case 'excelOnline':\n case 'excelDesktop':\n if (pasteType === 'normal' || pasteType === 'mergeFormat') {\n // Handle HTML copied from Excel\n processPastedContentFromExcel(\n event,\n this.editor.getDOMCreator(),\n this.allowExcelNoBorderTable\n );\n }\n break;\n case 'googleSheets':\n event.domToModelOption.additionalAllowedTags.push(\n PastePropertyNames.GOOGLE_SHEET_NODE_NAME as Lowercase<string>\n );\n break;\n case 'powerPointDesktop':\n processPastedContentFromPowerPoint(event, this.editor.getDOMCreator());\n break;\n }\n\n addParser(event.domToModelOption, 'link', parseLink);\n addParser(event.domToModelOption, 'tableCell', deprecatedBorderColorParser);\n addParser(event.domToModelOption, 'tableCell', tableBorderParser);\n addParser(event.domToModelOption, 'table', deprecatedBorderColorParser);\n\n if (pasteType === 'mergeFormat') {\n addParser(event.domToModelOption, 'block', blockElementParser);\n addParser(event.domToModelOption, 'listLevel', blockElementParser);\n }\n\n this.setEventSanitizers(event);\n }\n\n private setEventSanitizers(event: BeforePasteEvent) {\n if (this.domToModelForSanitizing) {\n const {\n styleSanitizers,\n attributeSanitizers,\n additionalAllowedTags,\n additionalDisallowedTags,\n } = this.domToModelForSanitizing;\n getObjectKeys(styleSanitizers).forEach(key =>\n chainSanitizerCallback(\n event.domToModelOption.styleSanitizers,\n key,\n styleSanitizers[key]\n )\n );\n getObjectKeys(attributeSanitizers).forEach(key =>\n chainSanitizerCallback(\n event.domToModelOption.attributeSanitizers,\n key,\n attributeSanitizers[key]\n )\n );\n event.domToModelOption.additionalAllowedTags.push(...additionalAllowedTags);\n event.domToModelOption.additionalDisallowedTags.push(...additionalDisallowedTags);\n }\n }\n}\n\n/**\n * For block elements that have background color style, remove the background color when user selects the merge current format\n * paste option\n */\nconst blockElementParser: FormatParser<ContentModelBlockFormat> = (\n format: ContentModelBlockFormat,\n element: HTMLElement\n) => {\n if (element.style.backgroundColor) {\n delete format.backgroundColor;\n }\n};\n\nconst ElementBorderKeys = new Map<\n keyof BorderFormat,\n {\n c: keyof CSSStyleDeclaration;\n s: keyof CSSStyleDeclaration;\n w: keyof CSSStyleDeclaration;\n }\n>([\n ['borderTop', { w: 'borderTopWidth', s: 'borderTopStyle', c: 'borderTopColor' }],\n ['borderRight', { w: 'borderRightWidth', s: 'borderRightStyle', c: 'borderRightColor' }],\n ['borderBottom', { w: 'borderBottomWidth', s: 'borderBottomStyle', c: 'borderBottomColor' }],\n ['borderLeft', { w: 'borderLeftWidth', s: 'borderLeftStyle', c: 'borderLeftColor' }],\n]);\n\nfunction tableBorderParser(format: ContentModelTableCellFormat, element: HTMLElement): void {\n BorderKeys.forEach(key => {\n if (!format[key]) {\n const styleSet = ElementBorderKeys.get(key);\n if (\n styleSet &&\n element.style[styleSet.w] &&\n element.style[styleSet.s] &&\n !element.style[styleSet.c]\n ) {\n format[key] = `${element.style[styleSet.w]} ${element.style[styleSet.s]}`;\n }\n }\n });\n}\n"]}
1
+ {"version":3,"file":"PastePlugin.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/paste/PastePlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { addParser } from './utils/addParser';\nimport { BorderKeys, getObjectKeys } from 'roosterjs-content-model-dom';\nimport { chainSanitizerCallback } from './utils/chainSanitizerCallback';\nimport { DefaultSanitizers } from './DefaultSanitizers';\nimport { deprecatedBorderColorParser } from './utils/deprecatedColorParser';\nimport { getPasteSource } from './pasteSourceValidations/getPasteSource';\nimport { parseLink } from './utils/linkParser';\nimport { PastePropertyNames } from './pasteSourceValidations/constants';\nimport { processPastedContentFromExcel } from './Excel/processPastedContentFromExcel';\nimport { processPastedContentFromPowerPoint } from './PowerPoint/processPastedContentFromPowerPoint';\nimport { processPastedContentFromWordDesktop } from './WordDesktop/processPastedContentFromWordDesktop';\nimport { processPastedContentWacComponents } from './WacComponents/processPastedContentWacComponents';\nimport type {\n BeforePasteEvent,\n BorderFormat,\n ContentModelBlockFormat,\n ContentModelTableCellFormat,\n DomToModelOptionForSanitizing,\n EditorPlugin,\n FormatParser,\n IEditor,\n PluginEvent,\n} from 'roosterjs-content-model-types';\n\n/**\n * Paste plugin, handles BeforePaste event and reformat some special content, including:\n * 1. Content copied from Word\n * 2. Content copied from Excel\n * 3. Content copied from Word Online or OneNote Online\n * 4. Content copied from Power Point\n */\nexport class PastePlugin implements EditorPlugin {\n private editor: IEditor | null = null;\n\n /**\n * Construct a new instance of Paste class\n * @param unknownTagReplacement Replace solution of unknown tags, default behavior is to replace with SPAN\n * @param allowExcelNoBorderTable Allow table copied from Excel without border\n */\n constructor(\n private allowExcelNoBorderTable?: boolean,\n private domToModelForSanitizing: Pick<\n DomToModelOptionForSanitizing,\n | 'additionalAllowedTags'\n | 'additionalDisallowedTags'\n | 'styleSanitizers'\n | 'attributeSanitizers'\n > = {\n styleSanitizers: DefaultSanitizers,\n additionalAllowedTags: [],\n additionalDisallowedTags: [],\n attributeSanitizers: {},\n }\n ) {}\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'Paste';\n }\n\n /**\n * The first method that editor will call to a plugin when editor is initializing.\n * It will pass in the editor instance, plugin should take this chance to save the\n * editor reference so that it can call to any editor method or format API later.\n * @param editor The editor object\n */\n initialize(editor: IEditor) {\n this.editor = editor;\n }\n\n /**\n * The last method that editor will call to a plugin before it is disposed.\n * Plugin can take this chance to clear the reference to editor. After this method is\n * called, plugin should not call to any editor method since it will result in error.\n */\n dispose() {\n this.editor = null;\n }\n\n /**\n * Core method for a plugin. Once an event happens in editor, editor will call this\n * method of each plugin to handle the event as long as the event is not handled\n * exclusively by another plugin.\n * @param event The event to handle:\n */\n onPluginEvent(event: PluginEvent) {\n if (!this.editor || event.eventType != 'beforePaste') {\n return;\n }\n\n if (!event.domToModelOption) {\n return;\n }\n\n const pasteSource = getPasteSource(event, false);\n const pasteType = event.pasteType;\n\n switch (pasteSource) {\n case 'wordDesktop':\n processPastedContentFromWordDesktop(event, this.editor.getDOMCreator());\n break;\n case 'wacComponents':\n processPastedContentWacComponents(event);\n break;\n case 'excelOnline':\n case 'excelDesktop':\n case 'excelNonNativeEvent':\n if (pasteType === 'normal' || pasteType === 'mergeFormat') {\n // Handle HTML copied from Excel\n processPastedContentFromExcel(\n event,\n this.editor.getDOMCreator(),\n !!this.allowExcelNoBorderTable,\n pasteSource != 'excelNonNativeEvent' /* isNativeEvent */\n );\n }\n break;\n case 'googleSheets':\n event.domToModelOption.additionalAllowedTags.push(\n PastePropertyNames.GOOGLE_SHEET_NODE_NAME as Lowercase<string>\n );\n break;\n case 'powerPointDesktop':\n processPastedContentFromPowerPoint(event, this.editor.getDOMCreator());\n break;\n }\n\n addParser(event.domToModelOption, 'link', parseLink);\n addParser(event.domToModelOption, 'tableCell', deprecatedBorderColorParser);\n addParser(event.domToModelOption, 'tableCell', tableBorderParser);\n addParser(event.domToModelOption, 'table', deprecatedBorderColorParser);\n\n if (pasteType === 'mergeFormat') {\n addParser(event.domToModelOption, 'block', blockElementParser);\n addParser(event.domToModelOption, 'listLevel', blockElementParser);\n }\n\n this.setEventSanitizers(event);\n }\n\n private setEventSanitizers(event: BeforePasteEvent) {\n if (this.domToModelForSanitizing) {\n const {\n styleSanitizers,\n attributeSanitizers,\n additionalAllowedTags,\n additionalDisallowedTags,\n } = this.domToModelForSanitizing;\n getObjectKeys(styleSanitizers).forEach(key =>\n chainSanitizerCallback(\n event.domToModelOption.styleSanitizers,\n key,\n styleSanitizers[key]\n )\n );\n getObjectKeys(attributeSanitizers).forEach(key =>\n chainSanitizerCallback(\n event.domToModelOption.attributeSanitizers,\n key,\n attributeSanitizers[key]\n )\n );\n event.domToModelOption.additionalAllowedTags.push(...additionalAllowedTags);\n event.domToModelOption.additionalDisallowedTags.push(...additionalDisallowedTags);\n }\n }\n}\n\n/**\n * For block elements that have background color style, remove the background color when user selects the merge current format\n * paste option\n */\nconst blockElementParser: FormatParser<ContentModelBlockFormat> = (\n format: ContentModelBlockFormat,\n element: HTMLElement\n) => {\n if (element.style.backgroundColor) {\n delete format.backgroundColor;\n }\n};\n\nconst ElementBorderKeys = new Map<\n keyof BorderFormat,\n {\n c: keyof CSSStyleDeclaration;\n s: keyof CSSStyleDeclaration;\n w: keyof CSSStyleDeclaration;\n }\n>([\n ['borderTop', { w: 'borderTopWidth', s: 'borderTopStyle', c: 'borderTopColor' }],\n ['borderRight', { w: 'borderRightWidth', s: 'borderRightStyle', c: 'borderRightColor' }],\n ['borderBottom', { w: 'borderBottomWidth', s: 'borderBottomStyle', c: 'borderBottomColor' }],\n ['borderLeft', { w: 'borderLeftWidth', s: 'borderLeftStyle', c: 'borderLeftColor' }],\n]);\n\nfunction tableBorderParser(format: ContentModelTableCellFormat, element: HTMLElement): void {\n BorderKeys.forEach(key => {\n if (!format[key]) {\n const styleSet = ElementBorderKeys.get(key);\n if (\n styleSet &&\n element.style[styleSet.w] &&\n element.style[styleSet.s] &&\n !element.style[styleSet.c]\n ) {\n format[key] = `${element.style[styleSet.w]} ${element.style[styleSet.s]}`;\n }\n }\n });\n}\n"]}
@@ -12,7 +12,7 @@ export declare type GetSourceInputParams = {
12
12
  * @internal
13
13
  * Represent the types of sources to handle in the Paste Plugin
14
14
  */
15
- export declare type KnownPasteSourceType = 'wordDesktop' | 'excelDesktop' | 'excelOnline' | 'powerPointDesktop' | 'googleSheets' | 'wacComponents' | 'default' | 'singleImage';
15
+ export declare type KnownPasteSourceType = 'wordDesktop' | 'excelDesktop' | 'excelOnline' | 'powerPointDesktop' | 'googleSheets' | 'wacComponents' | 'default' | 'singleImage' | 'excelNonNativeEvent';
16
16
  /**
17
17
  * @internal
18
18
  */
@@ -1,5 +1,6 @@
1
1
  import { documentContainWacElements } from './documentContainWacElements';
2
2
  import { isExcelDesktopDocument } from './isExcelDesktopDocument';
3
+ import { isExcelNotNativeEvent } from './isExcelNonNativeEvent';
3
4
  import { isExcelOnlineDocument } from './isExcelOnlineDocument';
4
5
  import { isGoogleSheetDocument } from './isGoogleSheetDocument';
5
6
  import { isPowerPointDesktopDocument } from './isPowerPointDesktopDocument';
@@ -13,6 +14,7 @@ var getSourceFunctions = new Map([
13
14
  ['wacComponents', documentContainWacElements],
14
15
  ['googleSheets', isGoogleSheetDocument],
15
16
  ['singleImage', shouldConvertToSingleImage],
17
+ ['excelNonNativeEvent', isExcelNotNativeEvent],
16
18
  ]);
17
19
  /**
18
20
  * @internal
@@ -1 +1 @@
1
- {"version":3,"file":"getPasteSource.js","sourceRoot":"","sources":["../../../../../packages/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-content-model-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/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,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;IAC3C,CAAC,qBAAqB,EAAE,qBAAqB,CAAC;CACjD,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 { isExcelNotNativeEvent } from './isExcelNonNativeEvent';\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-content-model-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 | 'excelNonNativeEvent';\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 ['excelNonNativeEvent', isExcelNotNativeEvent],\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"]}
@@ -0,0 +1,7 @@
1
+ import type { GetSourceFunction } from './getPasteSource';
2
+ /**
3
+ * @internal
4
+ * When the clipboard content is retrieved programatically, the clipboard html does not contain the usual
5
+ * attributes we use to determine if the content is from Excel. This function is used to handle that case.
6
+ */
7
+ export declare const isExcelNotNativeEvent: GetSourceFunction;
@@ -0,0 +1,14 @@
1
+ var ShadowWorkbookClipboardType = 'web data/shadow-workbook';
2
+ /**
3
+ * @internal
4
+ * When the clipboard content is retrieved programatically, the clipboard html does not contain the usual
5
+ * attributes we use to determine if the content is from Excel. This function is used to handle that case.
6
+ */
7
+ export var isExcelNotNativeEvent = function (props) {
8
+ var _a;
9
+ var clipboardData = props.clipboardData;
10
+ return (clipboardData.types.includes(ShadowWorkbookClipboardType) &&
11
+ ((_a = clipboardData.htmlFirstLevelChildTags) === null || _a === void 0 ? void 0 : _a.length) == 1 &&
12
+ clipboardData.htmlFirstLevelChildTags[0] == 'TABLE');
13
+ };
14
+ //# sourceMappingURL=isExcelNonNativeEvent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isExcelNonNativeEvent.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/paste/pasteSourceValidations/isExcelNonNativeEvent.ts"],"names":[],"mappings":"AAEA,IAAM,2BAA2B,GAAG,0BAA0B,CAAC;AAE/D;;;;GAIG;AACH,MAAM,CAAC,IAAM,qBAAqB,GAAsB,UAAC,KAA2B;;IACxE,IAAA,aAAa,GAAK,KAAK,cAAV,CAAW;IAEhC,OAAO,CACH,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,2BAA2B,CAAC;QACzD,CAAA,MAAA,aAAa,CAAC,uBAAuB,0CAAE,MAAM,KAAI,CAAC;QAClD,aAAa,CAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI,OAAO,CACtD,CAAC;AACN,CAAC,CAAC","sourcesContent":["import type { GetSourceFunction, GetSourceInputParams } from './getPasteSource';\n\nconst ShadowWorkbookClipboardType = 'web data/shadow-workbook';\n\n/**\n * @internal\n * When the clipboard content is retrieved programatically, the clipboard html does not contain the usual\n * attributes we use to determine if the content is from Excel. This function is used to handle that case.\n */\nexport const isExcelNotNativeEvent: GetSourceFunction = (props: GetSourceInputParams) => {\n const { clipboardData } = props;\n\n return (\n clipboardData.types.includes(ShadowWorkbookClipboardType) &&\n clipboardData.htmlFirstLevelChildTags?.length == 1 &&\n clipboardData.htmlFirstLevelChildTags[0] == 'TABLE'\n );\n};\n"]}
package/package.json CHANGED
@@ -3,12 +3,12 @@
3
3
  "description": "Plugins for roosterjs",
4
4
  "dependencies": {
5
5
  "tslib": "^2.3.1",
6
- "roosterjs-content-model-core": "^9.19.0",
7
- "roosterjs-content-model-dom": "^9.19.0",
8
- "roosterjs-content-model-types": "^9.19.0",
9
- "roosterjs-content-model-api": "^9.19.0"
6
+ "roosterjs-content-model-core": "^9.20.0",
7
+ "roosterjs-content-model-dom": "^9.20.0",
8
+ "roosterjs-content-model-types": "^9.20.0",
9
+ "roosterjs-content-model-api": "^9.20.0"
10
10
  },
11
- "version": "9.19.0",
11
+ "version": "9.20.0",
12
12
  "main": "./lib/index.js",
13
13
  "typings": "./lib/index.d.ts",
14
14
  "module": "./lib-mjs/index.js",