roosterjs-content-model-plugins 9.22.0 → 9.23.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 (43) hide show
  1. package/lib/edit/keyboardDelete.js +28 -7
  2. package/lib/edit/keyboardDelete.js.map +1 -1
  3. package/lib/hiddenProperty/HiddenPropertyOptions.d.ts +11 -0
  4. package/lib/hiddenProperty/HiddenPropertyOptions.js +3 -0
  5. package/lib/hiddenProperty/HiddenPropertyOptions.js.map +1 -0
  6. package/lib/hiddenProperty/HiddenPropertyPlugin.d.ts +38 -0
  7. package/lib/hiddenProperty/HiddenPropertyPlugin.js +58 -0
  8. package/lib/hiddenProperty/HiddenPropertyPlugin.js.map +1 -0
  9. package/lib/hiddenProperty/fixupHiddenProperties.d.ts +9 -0
  10. package/lib/hiddenProperty/fixupHiddenProperties.js +38 -0
  11. package/lib/hiddenProperty/fixupHiddenProperties.js.map +1 -0
  12. package/lib/index.d.ts +2 -0
  13. package/lib/index.js +3 -1
  14. package/lib/index.js.map +1 -1
  15. package/lib-amd/edit/keyboardDelete.js +28 -7
  16. package/lib-amd/edit/keyboardDelete.js.map +1 -1
  17. package/lib-amd/hiddenProperty/HiddenPropertyOptions.d.ts +11 -0
  18. package/lib-amd/hiddenProperty/HiddenPropertyOptions.js +5 -0
  19. package/lib-amd/hiddenProperty/HiddenPropertyOptions.js.map +1 -0
  20. package/lib-amd/hiddenProperty/HiddenPropertyPlugin.d.ts +38 -0
  21. package/lib-amd/hiddenProperty/HiddenPropertyPlugin.js +58 -0
  22. package/lib-amd/hiddenProperty/HiddenPropertyPlugin.js.map +1 -0
  23. package/lib-amd/hiddenProperty/fixupHiddenProperties.d.ts +9 -0
  24. package/lib-amd/hiddenProperty/fixupHiddenProperties.js +38 -0
  25. package/lib-amd/hiddenProperty/fixupHiddenProperties.js.map +1 -0
  26. package/lib-amd/index.d.ts +2 -0
  27. package/lib-amd/index.js +3 -2
  28. package/lib-amd/index.js.map +1 -1
  29. package/lib-mjs/edit/keyboardDelete.js +29 -8
  30. package/lib-mjs/edit/keyboardDelete.js.map +1 -1
  31. package/lib-mjs/hiddenProperty/HiddenPropertyOptions.d.ts +11 -0
  32. package/lib-mjs/hiddenProperty/HiddenPropertyOptions.js +2 -0
  33. package/lib-mjs/hiddenProperty/HiddenPropertyOptions.js.map +1 -0
  34. package/lib-mjs/hiddenProperty/HiddenPropertyPlugin.d.ts +38 -0
  35. package/lib-mjs/hiddenProperty/HiddenPropertyPlugin.js +55 -0
  36. package/lib-mjs/hiddenProperty/HiddenPropertyPlugin.js.map +1 -0
  37. package/lib-mjs/hiddenProperty/fixupHiddenProperties.d.ts +9 -0
  38. package/lib-mjs/hiddenProperty/fixupHiddenProperties.js +34 -0
  39. package/lib-mjs/hiddenProperty/fixupHiddenProperties.js.map +1 -0
  40. package/lib-mjs/index.d.ts +2 -0
  41. package/lib-mjs/index.js +1 -0
  42. package/lib-mjs/index.js.map +1 -1
  43. package/package.json +5 -5
@@ -77,18 +77,39 @@ function shouldDeleteWithContentModel(selection, rawEvent, handleExpandedSelecti
77
77
  }
78
78
  else {
79
79
  var range = selection.range;
80
+ var startContainer = range.startContainer;
81
+ var startOffset = range.startOffset;
80
82
  // When selection is collapsed and is in middle of text node, no need to use Content Model to delete
81
- return !((0, roosterjs_content_model_dom_1.isNodeOfType)(range.startContainer, 'TEXT_NODE') &&
83
+ return !((0, roosterjs_content_model_dom_1.isNodeOfType)(startContainer, 'TEXT_NODE') &&
82
84
  !(0, roosterjs_content_model_dom_1.isModifierKey)(rawEvent) &&
83
- (canDeleteBefore(rawEvent, range) || canDeleteAfter(rawEvent, range)));
85
+ (canDeleteBefore(rawEvent, startContainer, startOffset) ||
86
+ canDeleteAfter(rawEvent, startContainer, startOffset)));
84
87
  }
85
88
  }
86
- function canDeleteBefore(rawEvent, range) {
87
- return rawEvent.key == 'Backspace' && range.startOffset > 1;
89
+ function canDeleteBefore(rawEvent, text, offset) {
90
+ var _a, _b;
91
+ if (rawEvent.key != 'Backspace' || offset <= 1) {
92
+ return false;
93
+ }
94
+ var length = (_b = (_a = text.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
95
+ if (offset == length) {
96
+ // At the end of text, need to check if next segment is deletable
97
+ var nextSibling = text.nextSibling;
98
+ var isNextSiblingUndeletable = (0, roosterjs_content_model_dom_1.isNodeOfType)(nextSibling, 'ELEMENT_NODE') &&
99
+ (0, roosterjs_content_model_dom_1.isElementOfType)(nextSibling, 'a') &&
100
+ (0, roosterjs_content_model_dom_1.isLinkUndeletable)(nextSibling) &&
101
+ !nextSibling.firstChild;
102
+ // If next sibling is undeletable, we cannot let browser handle it since it will remove the anchor
103
+ // So we return false here to let Content Model handle it
104
+ return !isNextSiblingUndeletable;
105
+ }
106
+ else {
107
+ // In middle of text, we can safely let browser handle deletion
108
+ return true;
109
+ }
88
110
  }
89
- function canDeleteAfter(rawEvent, range) {
111
+ function canDeleteAfter(rawEvent, text, offset) {
90
112
  var _a, _b;
91
- return (rawEvent.key == 'Delete' &&
92
- range.startOffset < ((_b = (_a = range.startContainer.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) - 1);
113
+ return rawEvent.key == 'Delete' && offset < ((_b = (_a = text.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) - 1;
93
114
  }
94
115
  //# sourceMappingURL=keyboardDelete.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"keyboardDelete.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/keyboardDelete.ts"],"names":[],"mappings":"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","sourcesContent":["import { deleteAllSegmentBefore } from './deleteSteps/deleteAllSegmentBefore';\nimport { deleteEmptyQuote } from './deleteSteps/deleteEmptyQuote';\nimport { deleteList } from './deleteSteps/deleteList';\nimport {\n ChangeSource,\n deleteSelection,\n isModifierKey,\n isNodeOfType,\n} from 'roosterjs-content-model-dom';\nimport {\n handleKeyboardEventResult,\n shouldDeleteAllSegmentsBefore,\n shouldDeleteWord,\n} from './handleKeyboardEventCommon';\nimport {\n backwardDeleteWordSelection,\n forwardDeleteWordSelection,\n} from './deleteSteps/deleteWordSelection';\nimport {\n backwardDeleteCollapsedSelection,\n forwardDeleteCollapsedSelection,\n} from './deleteSteps/deleteCollapsedSelection';\nimport type { DOMSelection, DeleteSelectionStep, IEditor } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * Do keyboard event handling for DELETE/BACKSPACE key\n * @param editor The editor object\n * @param rawEvent DOM keyboard event\n * @param handleExpandedSelection Whether to handle expanded selection within a text node by CM\n * @returns True if the event is handled by content model, otherwise false\n */\nexport function keyboardDelete(\n editor: IEditor,\n rawEvent: KeyboardEvent,\n handleExpandedSelection: boolean = true\n) {\n let handled = false;\n const selection = editor.getDOMSelection();\n\n if (shouldDeleteWithContentModel(selection, rawEvent, handleExpandedSelection)) {\n editor.formatContentModel(\n (model, context) => {\n const result = deleteSelection(\n model,\n getDeleteSteps(rawEvent, !!editor.getEnvironment().isMac),\n context\n ).deleteResult;\n\n handled = handleKeyboardEventResult(editor, model, rawEvent, result, context);\n return handled;\n },\n {\n rawEvent,\n changeSource: ChangeSource.Keyboard,\n getChangeData: () => rawEvent.which,\n scrollCaretIntoView: true,\n apiName: rawEvent.key == 'Delete' ? 'handleDeleteKey' : 'handleBackspaceKey',\n }\n );\n }\n\n return handled;\n}\n\nfunction getDeleteSteps(rawEvent: KeyboardEvent, isMac: boolean): (DeleteSelectionStep | null)[] {\n const isForward = rawEvent.key == 'Delete';\n const deleteAllSegmentBeforeStep =\n shouldDeleteAllSegmentsBefore(rawEvent) && !isForward ? deleteAllSegmentBefore : null;\n const deleteWordSelection = shouldDeleteWord(rawEvent, isMac)\n ? isForward\n ? forwardDeleteWordSelection\n : backwardDeleteWordSelection\n : null;\n const deleteCollapsedSelection = isForward\n ? forwardDeleteCollapsedSelection\n : backwardDeleteCollapsedSelection;\n const deleteQuote = !isForward ? deleteEmptyQuote : null;\n return [\n deleteAllSegmentBeforeStep,\n deleteWordSelection,\n isForward ? null : deleteList,\n deleteCollapsedSelection,\n deleteQuote,\n ];\n}\n\nfunction shouldDeleteWithContentModel(\n selection: DOMSelection | null,\n rawEvent: KeyboardEvent,\n handleExpandedSelection: boolean\n) {\n if (!selection) {\n return false; // Nothing to delete\n } else if (selection.type != 'range') {\n return true;\n } else if (!selection.range.collapsed) {\n if (handleExpandedSelection) {\n return true; // Selection is not collapsed, need to delete all selections\n }\n\n const range = selection.range;\n const { startContainer, endContainer } = selection.range;\n const isInSameTextNode =\n startContainer === endContainer && isNodeOfType(startContainer, 'TEXT_NODE');\n return !(\n isInSameTextNode &&\n !isModifierKey(rawEvent) &&\n range.endOffset - range.startOffset < (startContainer.nodeValue?.length ?? 0)\n );\n } else {\n const range = selection.range;\n\n // When selection is collapsed and is in middle of text node, no need to use Content Model to delete\n return !(\n isNodeOfType(range.startContainer, 'TEXT_NODE') &&\n !isModifierKey(rawEvent) &&\n (canDeleteBefore(rawEvent, range) || canDeleteAfter(rawEvent, range))\n );\n }\n}\n\nfunction canDeleteBefore(rawEvent: KeyboardEvent, range: Range) {\n return rawEvent.key == 'Backspace' && range.startOffset > 1;\n}\n\nfunction canDeleteAfter(rawEvent: KeyboardEvent, range: Range) {\n return (\n rawEvent.key == 'Delete' &&\n range.startOffset < (range.startContainer.nodeValue?.length ?? 0) - 1\n );\n}\n"]}
1
+ {"version":3,"file":"keyboardDelete.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/keyboardDelete.ts"],"names":[],"mappings":"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","sourcesContent":["import { deleteAllSegmentBefore } from './deleteSteps/deleteAllSegmentBefore';\nimport { deleteEmptyQuote } from './deleteSteps/deleteEmptyQuote';\nimport { deleteList } from './deleteSteps/deleteList';\nimport {\n ChangeSource,\n deleteSelection,\n isElementOfType,\n isLinkUndeletable,\n isModifierKey,\n isNodeOfType,\n} from 'roosterjs-content-model-dom';\nimport {\n handleKeyboardEventResult,\n shouldDeleteAllSegmentsBefore,\n shouldDeleteWord,\n} from './handleKeyboardEventCommon';\nimport {\n backwardDeleteWordSelection,\n forwardDeleteWordSelection,\n} from './deleteSteps/deleteWordSelection';\nimport {\n backwardDeleteCollapsedSelection,\n forwardDeleteCollapsedSelection,\n} from './deleteSteps/deleteCollapsedSelection';\nimport type { DOMSelection, DeleteSelectionStep, IEditor } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * Do keyboard event handling for DELETE/BACKSPACE key\n * @param editor The editor object\n * @param rawEvent DOM keyboard event\n * @param handleExpandedSelection Whether to handle expanded selection within a text node by CM\n * @returns True if the event is handled by content model, otherwise false\n */\nexport function keyboardDelete(\n editor: IEditor,\n rawEvent: KeyboardEvent,\n handleExpandedSelection: boolean = true\n) {\n let handled = false;\n const selection = editor.getDOMSelection();\n\n if (shouldDeleteWithContentModel(selection, rawEvent, handleExpandedSelection)) {\n editor.formatContentModel(\n (model, context) => {\n const result = deleteSelection(\n model,\n getDeleteSteps(rawEvent, !!editor.getEnvironment().isMac),\n context\n ).deleteResult;\n\n handled = handleKeyboardEventResult(editor, model, rawEvent, result, context);\n return handled;\n },\n {\n rawEvent,\n changeSource: ChangeSource.Keyboard,\n getChangeData: () => rawEvent.which,\n scrollCaretIntoView: true,\n apiName: rawEvent.key == 'Delete' ? 'handleDeleteKey' : 'handleBackspaceKey',\n }\n );\n }\n\n return handled;\n}\n\nfunction getDeleteSteps(rawEvent: KeyboardEvent, isMac: boolean): (DeleteSelectionStep | null)[] {\n const isForward = rawEvent.key == 'Delete';\n const deleteAllSegmentBeforeStep =\n shouldDeleteAllSegmentsBefore(rawEvent) && !isForward ? deleteAllSegmentBefore : null;\n const deleteWordSelection = shouldDeleteWord(rawEvent, isMac)\n ? isForward\n ? forwardDeleteWordSelection\n : backwardDeleteWordSelection\n : null;\n const deleteCollapsedSelection = isForward\n ? forwardDeleteCollapsedSelection\n : backwardDeleteCollapsedSelection;\n const deleteQuote = !isForward ? deleteEmptyQuote : null;\n return [\n deleteAllSegmentBeforeStep,\n deleteWordSelection,\n isForward ? null : deleteList,\n deleteCollapsedSelection,\n deleteQuote,\n ];\n}\n\nfunction shouldDeleteWithContentModel(\n selection: DOMSelection | null,\n rawEvent: KeyboardEvent,\n handleExpandedSelection: boolean\n) {\n if (!selection) {\n return false; // Nothing to delete\n } else if (selection.type != 'range') {\n return true;\n } else if (!selection.range.collapsed) {\n if (handleExpandedSelection) {\n return true; // Selection is not collapsed, need to delete all selections\n }\n\n const range = selection.range;\n const { startContainer, endContainer } = selection.range;\n const isInSameTextNode =\n startContainer === endContainer && isNodeOfType(startContainer, 'TEXT_NODE');\n return !(\n isInSameTextNode &&\n !isModifierKey(rawEvent) &&\n range.endOffset - range.startOffset < (startContainer.nodeValue?.length ?? 0)\n );\n } else {\n const range = selection.range;\n const startContainer = range.startContainer;\n const startOffset = range.startOffset;\n\n // When selection is collapsed and is in middle of text node, no need to use Content Model to delete\n return !(\n isNodeOfType(startContainer, 'TEXT_NODE') &&\n !isModifierKey(rawEvent) &&\n (canDeleteBefore(rawEvent, startContainer, startOffset) ||\n canDeleteAfter(rawEvent, startContainer, startOffset))\n );\n }\n}\n\nfunction canDeleteBefore(rawEvent: KeyboardEvent, text: Text, offset: number) {\n if (rawEvent.key != 'Backspace' || offset <= 1) {\n return false;\n }\n\n const length = text.nodeValue?.length ?? 0;\n\n if (offset == length) {\n // At the end of text, need to check if next segment is deletable\n const nextSibling = text.nextSibling;\n const isNextSiblingUndeletable =\n isNodeOfType(nextSibling, 'ELEMENT_NODE') &&\n isElementOfType(nextSibling, 'a') &&\n isLinkUndeletable(nextSibling) &&\n !nextSibling.firstChild;\n\n // If next sibling is undeletable, we cannot let browser handle it since it will remove the anchor\n // So we return false here to let Content Model handle it\n return !isNextSiblingUndeletable;\n } else {\n // In middle of text, we can safely let browser handle deletion\n return true;\n }\n}\n\nfunction canDeleteAfter(rawEvent: KeyboardEvent, text: Text, offset: number) {\n return rawEvent.key == 'Delete' && offset < (text.nodeValue?.length ?? 0) - 1;\n}\n"]}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Options for HiddenProperty plugin
3
+ */
4
+ export interface HiddenPropertyOptions {
5
+ /**
6
+ * A helper function to check if a link should be undeletable or not.
7
+ * @param link The link to check
8
+ * @returns True if the link should be undeletable, false otherwise
9
+ */
10
+ undeletableLinkChecker?: (link: HTMLAnchorElement) => boolean;
11
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=HiddenPropertyOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HiddenPropertyOptions.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/hiddenProperty/HiddenPropertyOptions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Options for HiddenProperty plugin\n */\nexport interface HiddenPropertyOptions {\n /**\n * A helper function to check if a link should be undeletable or not.\n * @param link The link to check\n * @returns True if the link should be undeletable, false otherwise\n */\n undeletableLinkChecker?: (link: HTMLAnchorElement) => boolean;\n}\n"]}
@@ -0,0 +1,38 @@
1
+ import type { IEditor, PluginEvent, EditorPlugin } from 'roosterjs-content-model-types';
2
+ import type { HiddenPropertyOptions } from './HiddenPropertyOptions';
3
+ /**
4
+ * HiddenPropertyPlugin helps editor to maintain hidden properties in DOM after editor content is reset using HTML
5
+ */
6
+ export declare class HiddenPropertyPlugin implements EditorPlugin {
7
+ private option;
8
+ private editor;
9
+ /**
10
+ * Construct a new instance of FormatPlugin class
11
+ * @param option The editor option
12
+ */
13
+ constructor(option: HiddenPropertyOptions);
14
+ /**
15
+ * Get name of this plugin
16
+ */
17
+ getName(): string;
18
+ /**
19
+ * The first method that editor will call to a plugin when editor is initializing.
20
+ * It will pass in the editor instance, plugin should take this chance to save the
21
+ * editor reference so that it can call to any editor method or format API later.
22
+ * @param editor The editor object
23
+ */
24
+ initialize(editor: IEditor): void;
25
+ /**
26
+ * The last method that editor will call to a plugin before it is disposed.
27
+ * Plugin can take this chance to clear the reference to editor. After this method is
28
+ * called, plugin should not call to any editor method since it will result in error.
29
+ */
30
+ dispose(): void;
31
+ /**
32
+ * Core method for a plugin. Once an event happens in editor, editor will call this
33
+ * method of each plugin to handle the event as long as the event is not handled
34
+ * exclusively by another plugin.
35
+ * @param event The event to handle:
36
+ */
37
+ onPluginEvent(event: PluginEvent): void;
38
+ }
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HiddenPropertyPlugin = void 0;
4
+ var roosterjs_content_model_dom_1 = require("roosterjs-content-model-dom");
5
+ var fixupHiddenProperties_1 = require("./fixupHiddenProperties");
6
+ /**
7
+ * HiddenPropertyPlugin helps editor to maintain hidden properties in DOM after editor content is reset using HTML
8
+ */
9
+ var HiddenPropertyPlugin = /** @class */ (function () {
10
+ /**
11
+ * Construct a new instance of FormatPlugin class
12
+ * @param option The editor option
13
+ */
14
+ function HiddenPropertyPlugin(option) {
15
+ this.option = option;
16
+ this.editor = null;
17
+ }
18
+ /**
19
+ * Get name of this plugin
20
+ */
21
+ HiddenPropertyPlugin.prototype.getName = function () {
22
+ return 'HiddenProperty';
23
+ };
24
+ /**
25
+ * The first method that editor will call to a plugin when editor is initializing.
26
+ * It will pass in the editor instance, plugin should take this chance to save the
27
+ * editor reference so that it can call to any editor method or format API later.
28
+ * @param editor The editor object
29
+ */
30
+ HiddenPropertyPlugin.prototype.initialize = function (editor) {
31
+ this.editor = editor;
32
+ };
33
+ /**
34
+ * The last method that editor will call to a plugin before it is disposed.
35
+ * Plugin can take this chance to clear the reference to editor. After this method is
36
+ * called, plugin should not call to any editor method since it will result in error.
37
+ */
38
+ HiddenPropertyPlugin.prototype.dispose = function () {
39
+ this.editor = null;
40
+ };
41
+ /**
42
+ * Core method for a plugin. Once an event happens in editor, editor will call this
43
+ * method of each plugin to handle the event as long as the event is not handled
44
+ * exclusively by another plugin.
45
+ * @param event The event to handle:
46
+ */
47
+ HiddenPropertyPlugin.prototype.onPluginEvent = function (event) {
48
+ if (!this.editor) {
49
+ return;
50
+ }
51
+ if (event.eventType == 'contentChanged' && event.source == roosterjs_content_model_dom_1.ChangeSource.SetContent) {
52
+ (0, fixupHiddenProperties_1.fixupHiddenProperties)(this.editor, this.option);
53
+ }
54
+ };
55
+ return HiddenPropertyPlugin;
56
+ }());
57
+ exports.HiddenPropertyPlugin = HiddenPropertyPlugin;
58
+ //# sourceMappingURL=HiddenPropertyPlugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HiddenPropertyPlugin.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/hiddenProperty/HiddenPropertyPlugin.ts"],"names":[],"mappings":";;;AAAA,2EAA2D;AAC3D,iEAAgE;AAIhE;;GAEG;AACH;IAGI;;;OAGG;IACH,8BAAoB,MAA6B;QAA7B,WAAM,GAAN,MAAM,CAAuB;QANzC,WAAM,GAAmB,IAAI,CAAC;IAMc,CAAC;IAErD;;OAEG;IACH,sCAAO,GAAP;QACI,OAAO,gBAAgB,CAAC;IAC5B,CAAC;IAED;;;;;OAKG;IACH,yCAAU,GAAV,UAAW,MAAe;QACtB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;IAED;;;;OAIG;IACH,sCAAO,GAAP;QACI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IACvB,CAAC;IAED;;;;;OAKG;IACH,4CAAa,GAAb,UAAc,KAAkB;QAC5B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YACd,OAAO;SACV;QAED,IAAI,KAAK,CAAC,SAAS,IAAI,gBAAgB,IAAI,KAAK,CAAC,MAAM,IAAI,0CAAY,CAAC,UAAU,EAAE;YAChF,IAAA,6CAAqB,EAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;SACnD;IACL,CAAC;IACL,2BAAC;AAAD,CAAC,AAlDD,IAkDC;AAlDY,oDAAoB","sourcesContent":["import { ChangeSource } from 'roosterjs-content-model-dom';\nimport { fixupHiddenProperties } from './fixupHiddenProperties';\nimport type { IEditor, PluginEvent, EditorPlugin } from 'roosterjs-content-model-types';\nimport type { HiddenPropertyOptions } from './HiddenPropertyOptions';\n\n/**\n * HiddenPropertyPlugin helps editor to maintain hidden properties in DOM after editor content is reset using HTML\n */\nexport class HiddenPropertyPlugin implements EditorPlugin {\n private editor: IEditor | null = null;\n\n /**\n * Construct a new instance of FormatPlugin class\n * @param option The editor option\n */\n constructor(private option: HiddenPropertyOptions) {}\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'HiddenProperty';\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) {\n return;\n }\n\n if (event.eventType == 'contentChanged' && event.source == ChangeSource.SetContent) {\n fixupHiddenProperties(this.editor, this.option);\n }\n }\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import type { HiddenPropertyOptions } from './HiddenPropertyOptions';
2
+ import type { IEditor } from 'roosterjs-content-model-types';
3
+ /**
4
+ * @internal
5
+ * Maintain hidden properties in DOM after editor content is reset using HTML
6
+ * This includes:
7
+ * 1. Undeletable property
8
+ */
9
+ export declare function fixupHiddenProperties(editor: IEditor, options: HiddenPropertyOptions): void;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fixupHiddenProperties = void 0;
4
+ var tslib_1 = require("tslib");
5
+ var roosterjs_content_model_dom_1 = require("roosterjs-content-model-dom");
6
+ /**
7
+ * @internal
8
+ * Maintain hidden properties in DOM after editor content is reset using HTML
9
+ * This includes:
10
+ * 1. Undeletable property
11
+ */
12
+ function fixupHiddenProperties(editor, options) {
13
+ if (options.undeletableLinkChecker) {
14
+ checkUndeletable(editor, options.undeletableLinkChecker);
15
+ }
16
+ // Add more hidden properties checkers here
17
+ }
18
+ exports.fixupHiddenProperties = fixupHiddenProperties;
19
+ function checkUndeletable(editor, checker) {
20
+ var e_1, _a;
21
+ var anchors = editor.getDOMHelper().queryElements('a');
22
+ try {
23
+ for (var anchors_1 = (0, tslib_1.__values)(anchors), anchors_1_1 = anchors_1.next(); !anchors_1_1.done; anchors_1_1 = anchors_1.next()) {
24
+ var a = anchors_1_1.value;
25
+ if (checker(a)) {
26
+ (0, roosterjs_content_model_dom_1.setLinkUndeletable)(a, true);
27
+ }
28
+ }
29
+ }
30
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
31
+ finally {
32
+ try {
33
+ if (anchors_1_1 && !anchors_1_1.done && (_a = anchors_1.return)) _a.call(anchors_1);
34
+ }
35
+ finally { if (e_1) throw e_1.error; }
36
+ }
37
+ }
38
+ //# sourceMappingURL=fixupHiddenProperties.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixupHiddenProperties.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/hiddenProperty/fixupHiddenProperties.ts"],"names":[],"mappings":";;;;AAAA,2EAAiE;AAIjE;;;;;GAKG;AACH,SAAgB,qBAAqB,CAAC,MAAe,EAAE,OAA8B;IACjF,IAAI,OAAO,CAAC,sBAAsB,EAAE;QAChC,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;KAC5D;IAED,2CAA2C;AAC/C,CAAC;AAND,sDAMC;AAED,SAAS,gBAAgB,CAAC,MAAe,EAAE,OAA6C;;IACpF,IAAM,OAAO,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;;QAEzD,KAAgB,IAAA,YAAA,sBAAA,OAAO,CAAA,gCAAA,qDAAE;YAApB,IAAM,CAAC,oBAAA;YACR,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE;gBACZ,IAAA,gDAAkB,EAAC,CAAC,EAAE,IAAI,CAAC,CAAC;aAC/B;SACJ;;;;;;;;;AACL,CAAC","sourcesContent":["import { setLinkUndeletable } from 'roosterjs-content-model-dom';\nimport type { HiddenPropertyOptions } from './HiddenPropertyOptions';\nimport type { IEditor } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * Maintain hidden properties in DOM after editor content is reset using HTML\n * This includes:\n * 1. Undeletable property\n */\nexport function fixupHiddenProperties(editor: IEditor, options: HiddenPropertyOptions) {\n if (options.undeletableLinkChecker) {\n checkUndeletable(editor, options.undeletableLinkChecker);\n }\n\n // Add more hidden properties checkers here\n}\n\nfunction checkUndeletable(editor: IEditor, checker: (link: HTMLAnchorElement) => boolean) {\n const anchors = editor.getDOMHelper().queryElements('a');\n\n for (const a of anchors) {\n if (checker(a)) {\n setLinkUndeletable(a, true);\n }\n }\n}\n"]}
package/lib/index.d.ts CHANGED
@@ -22,3 +22,5 @@ export { PickerSelectionChangMode, PickerDirection, PickerHandler } from './pick
22
22
  export { CustomReplacePlugin, CustomReplace } from './customReplace/CustomReplacePlugin';
23
23
  export { ImageEditPlugin } from './imageEdit/ImageEditPlugin';
24
24
  export { ImageEditOptions } from './imageEdit/types/ImageEditOptions';
25
+ export { HiddenPropertyPlugin } from './hiddenProperty/HiddenPropertyPlugin';
26
+ export { HiddenPropertyOptions } from './hiddenProperty/HiddenPropertyOptions';
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ImageEditPlugin = exports.CustomReplacePlugin = exports.PickerPlugin = exports.HyperlinkPlugin = exports.MarkdownPlugin = exports.isModelEmptyFast = exports.WatermarkPlugin = exports.ContextMenuPluginBase = exports.ShortcutPlugin = exports.ShortcutOutdentList = exports.ShortcutIndentList = exports.ShortcutDecreaseFont = exports.ShortcutIncreaseFont = exports.ShortcutNumbering = exports.ShortcutBullet = exports.ShortcutRedoMacOS = exports.ShortcutRedoAlt = exports.ShortcutRedo = exports.ShortcutUndo2 = exports.ShortcutUndo = exports.ShortcutClearFormat = exports.ShortcutUnderline = exports.ShortcutItalic = exports.ShortcutBold = exports.AutoFormatPlugin = exports.EditPlugin = exports.DefaultSanitizers = exports.PastePlugin = exports.TableEditPlugin = void 0;
3
+ exports.HiddenPropertyPlugin = exports.ImageEditPlugin = exports.CustomReplacePlugin = exports.PickerPlugin = exports.HyperlinkPlugin = exports.MarkdownPlugin = exports.isModelEmptyFast = exports.WatermarkPlugin = exports.ContextMenuPluginBase = exports.ShortcutPlugin = exports.ShortcutOutdentList = exports.ShortcutIndentList = exports.ShortcutDecreaseFont = exports.ShortcutIncreaseFont = exports.ShortcutNumbering = exports.ShortcutBullet = exports.ShortcutRedoMacOS = exports.ShortcutRedoAlt = exports.ShortcutRedo = exports.ShortcutUndo2 = exports.ShortcutUndo = exports.ShortcutClearFormat = exports.ShortcutUnderline = exports.ShortcutItalic = exports.ShortcutBold = exports.AutoFormatPlugin = exports.EditPlugin = exports.DefaultSanitizers = exports.PastePlugin = exports.TableEditPlugin = void 0;
4
4
  var TableEditPlugin_1 = require("./tableEdit/TableEditPlugin");
5
5
  Object.defineProperty(exports, "TableEditPlugin", { enumerable: true, get: function () { return TableEditPlugin_1.TableEditPlugin; } });
6
6
  var PastePlugin_1 = require("./paste/PastePlugin");
@@ -45,4 +45,6 @@ var CustomReplacePlugin_1 = require("./customReplace/CustomReplacePlugin");
45
45
  Object.defineProperty(exports, "CustomReplacePlugin", { enumerable: true, get: function () { return CustomReplacePlugin_1.CustomReplacePlugin; } });
46
46
  var ImageEditPlugin_1 = require("./imageEdit/ImageEditPlugin");
47
47
  Object.defineProperty(exports, "ImageEditPlugin", { enumerable: true, get: function () { return ImageEditPlugin_1.ImageEditPlugin; } });
48
+ var HiddenPropertyPlugin_1 = require("./hiddenProperty/HiddenPropertyPlugin");
49
+ Object.defineProperty(exports, "HiddenPropertyPlugin", { enumerable: true, get: function () { return HiddenPropertyPlugin_1.HiddenPropertyPlugin; } });
48
50
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../packages/roosterjs-content-model-plugins/lib/index.ts"],"names":[],"mappings":";;;AAAA,+DAA8D;AAArD,kHAAA,eAAe,OAAA;AAGxB,mDAAkD;AAAzC,0GAAA,WAAW,OAAA;AACpB,+DAA8D;AAArD,sHAAA,iBAAiB,OAAA;AAC1B,gDAA4D;AAAnD,wGAAA,UAAU,OAAA;AACnB,kEAAiE;AAAxD,oHAAA,gBAAgB,OAAA;AAGzB,kDAgB8B;AAf1B,yGAAA,YAAY,OAAA;AACZ,2GAAA,cAAc,OAAA;AACd,8GAAA,iBAAiB,OAAA;AACjB,gHAAA,mBAAmB,OAAA;AACnB,yGAAA,YAAY,OAAA;AACZ,0GAAA,aAAa,OAAA;AACb,yGAAA,YAAY,OAAA;AACZ,4GAAA,eAAe,OAAA;AACf,8GAAA,iBAAiB,OAAA;AACjB,2GAAA,cAAc,OAAA;AACd,8GAAA,iBAAiB,OAAA;AACjB,iHAAA,oBAAoB,OAAA;AACpB,iHAAA,oBAAoB,OAAA;AACpB,+GAAA,kBAAkB,OAAA;AAClB,gHAAA,mBAAmB,OAAA;AAEvB,4DAA2D;AAAlD,gHAAA,cAAc,OAAA;AAEvB,iFAAoG;AAA3F,8HAAA,qBAAqB,OAAA;AAC9B,+DAA8D;AAArD,kHAAA,eAAe,OAAA;AAExB,iEAAgE;AAAvD,oHAAA,gBAAgB,OAAA;AACzB,4DAA4E;AAAnE,gHAAA,cAAc,OAAA;AACvB,+DAA8D;AAArD,kHAAA,eAAe,OAAA;AAExB,sDAAqD;AAA5C,4GAAA,YAAY,OAAA;AAGrB,2EAAyF;AAAhF,0HAAA,mBAAmB,OAAA;AAC5B,+DAA8D;AAArD,kHAAA,eAAe,OAAA","sourcesContent":["export { TableEditPlugin } from './tableEdit/TableEditPlugin';\nexport { OnTableEditorCreatedCallback } from './tableEdit/OnTableEditorCreatedCallback';\nexport { TableEditFeatureName } from './tableEdit/editors/features/TableEditFeatureName';\nexport { PastePlugin } from './paste/PastePlugin';\nexport { DefaultSanitizers } from './paste/DefaultSanitizers';\nexport { EditPlugin, EditOptions } from './edit/EditPlugin';\nexport { AutoFormatPlugin } from './autoFormat/AutoFormatPlugin';\nexport { AutoFormatOptions } from './autoFormat/interface/AutoFormatOptions';\n\nexport {\n ShortcutBold,\n ShortcutItalic,\n ShortcutUnderline,\n ShortcutClearFormat,\n ShortcutUndo,\n ShortcutUndo2,\n ShortcutRedo,\n ShortcutRedoAlt,\n ShortcutRedoMacOS,\n ShortcutBullet,\n ShortcutNumbering,\n ShortcutIncreaseFont,\n ShortcutDecreaseFont,\n ShortcutIndentList,\n ShortcutOutdentList,\n} from './shortcut/shortcuts';\nexport { ShortcutPlugin } from './shortcut/ShortcutPlugin';\nexport { ShortcutKeyDefinition, ShortcutCommand } from './shortcut/ShortcutCommand';\nexport { ContextMenuPluginBase, ContextMenuOptions } from './contextMenuBase/ContextMenuPluginBase';\nexport { WatermarkPlugin } from './watermark/WatermarkPlugin';\nexport { WatermarkFormat } from './watermark/WatermarkFormat';\nexport { isModelEmptyFast } from './watermark/isModelEmptyFast';\nexport { MarkdownPlugin, MarkdownOptions } from './markdown/MarkdownPlugin';\nexport { HyperlinkPlugin } from './hyperlink/HyperlinkPlugin';\nexport { HyperlinkToolTip } from './hyperlink/HyperlinkToolTip';\nexport { PickerPlugin } from './picker/PickerPlugin';\nexport { PickerHelper } from './picker/PickerHelper';\nexport { PickerSelectionChangMode, PickerDirection, PickerHandler } from './picker/PickerHandler';\nexport { CustomReplacePlugin, CustomReplace } from './customReplace/CustomReplacePlugin';\nexport { ImageEditPlugin } from './imageEdit/ImageEditPlugin';\nexport { ImageEditOptions } from './imageEdit/types/ImageEditOptions';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../packages/roosterjs-content-model-plugins/lib/index.ts"],"names":[],"mappings":";;;AAAA,+DAA8D;AAArD,kHAAA,eAAe,OAAA;AAGxB,mDAAkD;AAAzC,0GAAA,WAAW,OAAA;AACpB,+DAA8D;AAArD,sHAAA,iBAAiB,OAAA;AAC1B,gDAA4D;AAAnD,wGAAA,UAAU,OAAA;AACnB,kEAAiE;AAAxD,oHAAA,gBAAgB,OAAA;AAGzB,kDAgB8B;AAf1B,yGAAA,YAAY,OAAA;AACZ,2GAAA,cAAc,OAAA;AACd,8GAAA,iBAAiB,OAAA;AACjB,gHAAA,mBAAmB,OAAA;AACnB,yGAAA,YAAY,OAAA;AACZ,0GAAA,aAAa,OAAA;AACb,yGAAA,YAAY,OAAA;AACZ,4GAAA,eAAe,OAAA;AACf,8GAAA,iBAAiB,OAAA;AACjB,2GAAA,cAAc,OAAA;AACd,8GAAA,iBAAiB,OAAA;AACjB,iHAAA,oBAAoB,OAAA;AACpB,iHAAA,oBAAoB,OAAA;AACpB,+GAAA,kBAAkB,OAAA;AAClB,gHAAA,mBAAmB,OAAA;AAEvB,4DAA2D;AAAlD,gHAAA,cAAc,OAAA;AAEvB,iFAAoG;AAA3F,8HAAA,qBAAqB,OAAA;AAC9B,+DAA8D;AAArD,kHAAA,eAAe,OAAA;AAExB,iEAAgE;AAAvD,oHAAA,gBAAgB,OAAA;AACzB,4DAA4E;AAAnE,gHAAA,cAAc,OAAA;AACvB,+DAA8D;AAArD,kHAAA,eAAe,OAAA;AAExB,sDAAqD;AAA5C,4GAAA,YAAY,OAAA;AAGrB,2EAAyF;AAAhF,0HAAA,mBAAmB,OAAA;AAC5B,+DAA8D;AAArD,kHAAA,eAAe,OAAA;AAExB,8EAA6E;AAApE,4HAAA,oBAAoB,OAAA","sourcesContent":["export { TableEditPlugin } from './tableEdit/TableEditPlugin';\nexport { OnTableEditorCreatedCallback } from './tableEdit/OnTableEditorCreatedCallback';\nexport { TableEditFeatureName } from './tableEdit/editors/features/TableEditFeatureName';\nexport { PastePlugin } from './paste/PastePlugin';\nexport { DefaultSanitizers } from './paste/DefaultSanitizers';\nexport { EditPlugin, EditOptions } from './edit/EditPlugin';\nexport { AutoFormatPlugin } from './autoFormat/AutoFormatPlugin';\nexport { AutoFormatOptions } from './autoFormat/interface/AutoFormatOptions';\n\nexport {\n ShortcutBold,\n ShortcutItalic,\n ShortcutUnderline,\n ShortcutClearFormat,\n ShortcutUndo,\n ShortcutUndo2,\n ShortcutRedo,\n ShortcutRedoAlt,\n ShortcutRedoMacOS,\n ShortcutBullet,\n ShortcutNumbering,\n ShortcutIncreaseFont,\n ShortcutDecreaseFont,\n ShortcutIndentList,\n ShortcutOutdentList,\n} from './shortcut/shortcuts';\nexport { ShortcutPlugin } from './shortcut/ShortcutPlugin';\nexport { ShortcutKeyDefinition, ShortcutCommand } from './shortcut/ShortcutCommand';\nexport { ContextMenuPluginBase, ContextMenuOptions } from './contextMenuBase/ContextMenuPluginBase';\nexport { WatermarkPlugin } from './watermark/WatermarkPlugin';\nexport { WatermarkFormat } from './watermark/WatermarkFormat';\nexport { isModelEmptyFast } from './watermark/isModelEmptyFast';\nexport { MarkdownPlugin, MarkdownOptions } from './markdown/MarkdownPlugin';\nexport { HyperlinkPlugin } from './hyperlink/HyperlinkPlugin';\nexport { HyperlinkToolTip } from './hyperlink/HyperlinkToolTip';\nexport { PickerPlugin } from './picker/PickerPlugin';\nexport { PickerHelper } from './picker/PickerHelper';\nexport { PickerSelectionChangMode, PickerDirection, PickerHandler } from './picker/PickerHandler';\nexport { CustomReplacePlugin, CustomReplace } from './customReplace/CustomReplacePlugin';\nexport { ImageEditPlugin } from './imageEdit/ImageEditPlugin';\nexport { ImageEditOptions } from './imageEdit/types/ImageEditOptions';\nexport { HiddenPropertyPlugin } from './hiddenProperty/HiddenPropertyPlugin';\nexport { HiddenPropertyOptions } from './hiddenProperty/HiddenPropertyOptions';\n"]}
@@ -71,19 +71,40 @@ define(["require", "exports", "./deleteSteps/deleteAllSegmentBefore", "./deleteS
71
71
  }
72
72
  else {
73
73
  var range = selection.range;
74
+ var startContainer = range.startContainer;
75
+ var startOffset = range.startOffset;
74
76
  // When selection is collapsed and is in middle of text node, no need to use Content Model to delete
75
- return !((0, roosterjs_content_model_dom_1.isNodeOfType)(range.startContainer, 'TEXT_NODE') &&
77
+ return !((0, roosterjs_content_model_dom_1.isNodeOfType)(startContainer, 'TEXT_NODE') &&
76
78
  !(0, roosterjs_content_model_dom_1.isModifierKey)(rawEvent) &&
77
- (canDeleteBefore(rawEvent, range) || canDeleteAfter(rawEvent, range)));
79
+ (canDeleteBefore(rawEvent, startContainer, startOffset) ||
80
+ canDeleteAfter(rawEvent, startContainer, startOffset)));
78
81
  }
79
82
  }
80
- function canDeleteBefore(rawEvent, range) {
81
- return rawEvent.key == 'Backspace' && range.startOffset > 1;
83
+ function canDeleteBefore(rawEvent, text, offset) {
84
+ var _a, _b;
85
+ if (rawEvent.key != 'Backspace' || offset <= 1) {
86
+ return false;
87
+ }
88
+ var length = (_b = (_a = text.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
89
+ if (offset == length) {
90
+ // At the end of text, need to check if next segment is deletable
91
+ var nextSibling = text.nextSibling;
92
+ var isNextSiblingUndeletable = (0, roosterjs_content_model_dom_1.isNodeOfType)(nextSibling, 'ELEMENT_NODE') &&
93
+ (0, roosterjs_content_model_dom_1.isElementOfType)(nextSibling, 'a') &&
94
+ (0, roosterjs_content_model_dom_1.isLinkUndeletable)(nextSibling) &&
95
+ !nextSibling.firstChild;
96
+ // If next sibling is undeletable, we cannot let browser handle it since it will remove the anchor
97
+ // So we return false here to let Content Model handle it
98
+ return !isNextSiblingUndeletable;
99
+ }
100
+ else {
101
+ // In middle of text, we can safely let browser handle deletion
102
+ return true;
103
+ }
82
104
  }
83
- function canDeleteAfter(rawEvent, range) {
105
+ function canDeleteAfter(rawEvent, text, offset) {
84
106
  var _a, _b;
85
- return (rawEvent.key == 'Delete' &&
86
- range.startOffset < ((_b = (_a = range.startContainer.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) - 1);
107
+ return rawEvent.key == 'Delete' && offset < ((_b = (_a = text.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) - 1;
87
108
  }
88
109
  });
89
110
  //# sourceMappingURL=keyboardDelete.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"keyboardDelete.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/keyboardDelete.ts"],"names":[],"mappings":"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","sourcesContent":["import { deleteAllSegmentBefore } from './deleteSteps/deleteAllSegmentBefore';\nimport { deleteEmptyQuote } from './deleteSteps/deleteEmptyQuote';\nimport { deleteList } from './deleteSteps/deleteList';\nimport {\n ChangeSource,\n deleteSelection,\n isModifierKey,\n isNodeOfType,\n} from 'roosterjs-content-model-dom';\nimport {\n handleKeyboardEventResult,\n shouldDeleteAllSegmentsBefore,\n shouldDeleteWord,\n} from './handleKeyboardEventCommon';\nimport {\n backwardDeleteWordSelection,\n forwardDeleteWordSelection,\n} from './deleteSteps/deleteWordSelection';\nimport {\n backwardDeleteCollapsedSelection,\n forwardDeleteCollapsedSelection,\n} from './deleteSteps/deleteCollapsedSelection';\nimport type { DOMSelection, DeleteSelectionStep, IEditor } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * Do keyboard event handling for DELETE/BACKSPACE key\n * @param editor The editor object\n * @param rawEvent DOM keyboard event\n * @param handleExpandedSelection Whether to handle expanded selection within a text node by CM\n * @returns True if the event is handled by content model, otherwise false\n */\nexport function keyboardDelete(\n editor: IEditor,\n rawEvent: KeyboardEvent,\n handleExpandedSelection: boolean = true\n) {\n let handled = false;\n const selection = editor.getDOMSelection();\n\n if (shouldDeleteWithContentModel(selection, rawEvent, handleExpandedSelection)) {\n editor.formatContentModel(\n (model, context) => {\n const result = deleteSelection(\n model,\n getDeleteSteps(rawEvent, !!editor.getEnvironment().isMac),\n context\n ).deleteResult;\n\n handled = handleKeyboardEventResult(editor, model, rawEvent, result, context);\n return handled;\n },\n {\n rawEvent,\n changeSource: ChangeSource.Keyboard,\n getChangeData: () => rawEvent.which,\n scrollCaretIntoView: true,\n apiName: rawEvent.key == 'Delete' ? 'handleDeleteKey' : 'handleBackspaceKey',\n }\n );\n }\n\n return handled;\n}\n\nfunction getDeleteSteps(rawEvent: KeyboardEvent, isMac: boolean): (DeleteSelectionStep | null)[] {\n const isForward = rawEvent.key == 'Delete';\n const deleteAllSegmentBeforeStep =\n shouldDeleteAllSegmentsBefore(rawEvent) && !isForward ? deleteAllSegmentBefore : null;\n const deleteWordSelection = shouldDeleteWord(rawEvent, isMac)\n ? isForward\n ? forwardDeleteWordSelection\n : backwardDeleteWordSelection\n : null;\n const deleteCollapsedSelection = isForward\n ? forwardDeleteCollapsedSelection\n : backwardDeleteCollapsedSelection;\n const deleteQuote = !isForward ? deleteEmptyQuote : null;\n return [\n deleteAllSegmentBeforeStep,\n deleteWordSelection,\n isForward ? null : deleteList,\n deleteCollapsedSelection,\n deleteQuote,\n ];\n}\n\nfunction shouldDeleteWithContentModel(\n selection: DOMSelection | null,\n rawEvent: KeyboardEvent,\n handleExpandedSelection: boolean\n) {\n if (!selection) {\n return false; // Nothing to delete\n } else if (selection.type != 'range') {\n return true;\n } else if (!selection.range.collapsed) {\n if (handleExpandedSelection) {\n return true; // Selection is not collapsed, need to delete all selections\n }\n\n const range = selection.range;\n const { startContainer, endContainer } = selection.range;\n const isInSameTextNode =\n startContainer === endContainer && isNodeOfType(startContainer, 'TEXT_NODE');\n return !(\n isInSameTextNode &&\n !isModifierKey(rawEvent) &&\n range.endOffset - range.startOffset < (startContainer.nodeValue?.length ?? 0)\n );\n } else {\n const range = selection.range;\n\n // When selection is collapsed and is in middle of text node, no need to use Content Model to delete\n return !(\n isNodeOfType(range.startContainer, 'TEXT_NODE') &&\n !isModifierKey(rawEvent) &&\n (canDeleteBefore(rawEvent, range) || canDeleteAfter(rawEvent, range))\n );\n }\n}\n\nfunction canDeleteBefore(rawEvent: KeyboardEvent, range: Range) {\n return rawEvent.key == 'Backspace' && range.startOffset > 1;\n}\n\nfunction canDeleteAfter(rawEvent: KeyboardEvent, range: Range) {\n return (\n rawEvent.key == 'Delete' &&\n range.startOffset < (range.startContainer.nodeValue?.length ?? 0) - 1\n );\n}\n"]}
1
+ {"version":3,"file":"keyboardDelete.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/keyboardDelete.ts"],"names":[],"mappings":"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","sourcesContent":["import { deleteAllSegmentBefore } from './deleteSteps/deleteAllSegmentBefore';\nimport { deleteEmptyQuote } from './deleteSteps/deleteEmptyQuote';\nimport { deleteList } from './deleteSteps/deleteList';\nimport {\n ChangeSource,\n deleteSelection,\n isElementOfType,\n isLinkUndeletable,\n isModifierKey,\n isNodeOfType,\n} from 'roosterjs-content-model-dom';\nimport {\n handleKeyboardEventResult,\n shouldDeleteAllSegmentsBefore,\n shouldDeleteWord,\n} from './handleKeyboardEventCommon';\nimport {\n backwardDeleteWordSelection,\n forwardDeleteWordSelection,\n} from './deleteSteps/deleteWordSelection';\nimport {\n backwardDeleteCollapsedSelection,\n forwardDeleteCollapsedSelection,\n} from './deleteSteps/deleteCollapsedSelection';\nimport type { DOMSelection, DeleteSelectionStep, IEditor } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * Do keyboard event handling for DELETE/BACKSPACE key\n * @param editor The editor object\n * @param rawEvent DOM keyboard event\n * @param handleExpandedSelection Whether to handle expanded selection within a text node by CM\n * @returns True if the event is handled by content model, otherwise false\n */\nexport function keyboardDelete(\n editor: IEditor,\n rawEvent: KeyboardEvent,\n handleExpandedSelection: boolean = true\n) {\n let handled = false;\n const selection = editor.getDOMSelection();\n\n if (shouldDeleteWithContentModel(selection, rawEvent, handleExpandedSelection)) {\n editor.formatContentModel(\n (model, context) => {\n const result = deleteSelection(\n model,\n getDeleteSteps(rawEvent, !!editor.getEnvironment().isMac),\n context\n ).deleteResult;\n\n handled = handleKeyboardEventResult(editor, model, rawEvent, result, context);\n return handled;\n },\n {\n rawEvent,\n changeSource: ChangeSource.Keyboard,\n getChangeData: () => rawEvent.which,\n scrollCaretIntoView: true,\n apiName: rawEvent.key == 'Delete' ? 'handleDeleteKey' : 'handleBackspaceKey',\n }\n );\n }\n\n return handled;\n}\n\nfunction getDeleteSteps(rawEvent: KeyboardEvent, isMac: boolean): (DeleteSelectionStep | null)[] {\n const isForward = rawEvent.key == 'Delete';\n const deleteAllSegmentBeforeStep =\n shouldDeleteAllSegmentsBefore(rawEvent) && !isForward ? deleteAllSegmentBefore : null;\n const deleteWordSelection = shouldDeleteWord(rawEvent, isMac)\n ? isForward\n ? forwardDeleteWordSelection\n : backwardDeleteWordSelection\n : null;\n const deleteCollapsedSelection = isForward\n ? forwardDeleteCollapsedSelection\n : backwardDeleteCollapsedSelection;\n const deleteQuote = !isForward ? deleteEmptyQuote : null;\n return [\n deleteAllSegmentBeforeStep,\n deleteWordSelection,\n isForward ? null : deleteList,\n deleteCollapsedSelection,\n deleteQuote,\n ];\n}\n\nfunction shouldDeleteWithContentModel(\n selection: DOMSelection | null,\n rawEvent: KeyboardEvent,\n handleExpandedSelection: boolean\n) {\n if (!selection) {\n return false; // Nothing to delete\n } else if (selection.type != 'range') {\n return true;\n } else if (!selection.range.collapsed) {\n if (handleExpandedSelection) {\n return true; // Selection is not collapsed, need to delete all selections\n }\n\n const range = selection.range;\n const { startContainer, endContainer } = selection.range;\n const isInSameTextNode =\n startContainer === endContainer && isNodeOfType(startContainer, 'TEXT_NODE');\n return !(\n isInSameTextNode &&\n !isModifierKey(rawEvent) &&\n range.endOffset - range.startOffset < (startContainer.nodeValue?.length ?? 0)\n );\n } else {\n const range = selection.range;\n const startContainer = range.startContainer;\n const startOffset = range.startOffset;\n\n // When selection is collapsed and is in middle of text node, no need to use Content Model to delete\n return !(\n isNodeOfType(startContainer, 'TEXT_NODE') &&\n !isModifierKey(rawEvent) &&\n (canDeleteBefore(rawEvent, startContainer, startOffset) ||\n canDeleteAfter(rawEvent, startContainer, startOffset))\n );\n }\n}\n\nfunction canDeleteBefore(rawEvent: KeyboardEvent, text: Text, offset: number) {\n if (rawEvent.key != 'Backspace' || offset <= 1) {\n return false;\n }\n\n const length = text.nodeValue?.length ?? 0;\n\n if (offset == length) {\n // At the end of text, need to check if next segment is deletable\n const nextSibling = text.nextSibling;\n const isNextSiblingUndeletable =\n isNodeOfType(nextSibling, 'ELEMENT_NODE') &&\n isElementOfType(nextSibling, 'a') &&\n isLinkUndeletable(nextSibling) &&\n !nextSibling.firstChild;\n\n // If next sibling is undeletable, we cannot let browser handle it since it will remove the anchor\n // So we return false here to let Content Model handle it\n return !isNextSiblingUndeletable;\n } else {\n // In middle of text, we can safely let browser handle deletion\n return true;\n }\n}\n\nfunction canDeleteAfter(rawEvent: KeyboardEvent, text: Text, offset: number) {\n return rawEvent.key == 'Delete' && offset < (text.nodeValue?.length ?? 0) - 1;\n}\n"]}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Options for HiddenProperty plugin
3
+ */
4
+ export interface HiddenPropertyOptions {
5
+ /**
6
+ * A helper function to check if a link should be undeletable or not.
7
+ * @param link The link to check
8
+ * @returns True if the link should be undeletable, false otherwise
9
+ */
10
+ undeletableLinkChecker?: (link: HTMLAnchorElement) => boolean;
11
+ }
@@ -0,0 +1,5 @@
1
+ define(["require", "exports"], function (require, exports) {
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ });
5
+ //# sourceMappingURL=HiddenPropertyOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HiddenPropertyOptions.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/hiddenProperty/HiddenPropertyOptions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Options for HiddenProperty plugin\n */\nexport interface HiddenPropertyOptions {\n /**\n * A helper function to check if a link should be undeletable or not.\n * @param link The link to check\n * @returns True if the link should be undeletable, false otherwise\n */\n undeletableLinkChecker?: (link: HTMLAnchorElement) => boolean;\n}\n"]}
@@ -0,0 +1,38 @@
1
+ import type { IEditor, PluginEvent, EditorPlugin } from 'roosterjs-content-model-types';
2
+ import type { HiddenPropertyOptions } from './HiddenPropertyOptions';
3
+ /**
4
+ * HiddenPropertyPlugin helps editor to maintain hidden properties in DOM after editor content is reset using HTML
5
+ */
6
+ export declare class HiddenPropertyPlugin implements EditorPlugin {
7
+ private option;
8
+ private editor;
9
+ /**
10
+ * Construct a new instance of FormatPlugin class
11
+ * @param option The editor option
12
+ */
13
+ constructor(option: HiddenPropertyOptions);
14
+ /**
15
+ * Get name of this plugin
16
+ */
17
+ getName(): string;
18
+ /**
19
+ * The first method that editor will call to a plugin when editor is initializing.
20
+ * It will pass in the editor instance, plugin should take this chance to save the
21
+ * editor reference so that it can call to any editor method or format API later.
22
+ * @param editor The editor object
23
+ */
24
+ initialize(editor: IEditor): void;
25
+ /**
26
+ * The last method that editor will call to a plugin before it is disposed.
27
+ * Plugin can take this chance to clear the reference to editor. After this method is
28
+ * called, plugin should not call to any editor method since it will result in error.
29
+ */
30
+ dispose(): void;
31
+ /**
32
+ * Core method for a plugin. Once an event happens in editor, editor will call this
33
+ * method of each plugin to handle the event as long as the event is not handled
34
+ * exclusively by another plugin.
35
+ * @param event The event to handle:
36
+ */
37
+ onPluginEvent(event: PluginEvent): void;
38
+ }
@@ -0,0 +1,58 @@
1
+ define(["require", "exports", "roosterjs-content-model-dom", "./fixupHiddenProperties"], function (require, exports, roosterjs_content_model_dom_1, fixupHiddenProperties_1) {
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.HiddenPropertyPlugin = void 0;
5
+ /**
6
+ * HiddenPropertyPlugin helps editor to maintain hidden properties in DOM after editor content is reset using HTML
7
+ */
8
+ var HiddenPropertyPlugin = /** @class */ (function () {
9
+ /**
10
+ * Construct a new instance of FormatPlugin class
11
+ * @param option The editor option
12
+ */
13
+ function HiddenPropertyPlugin(option) {
14
+ this.option = option;
15
+ this.editor = null;
16
+ }
17
+ /**
18
+ * Get name of this plugin
19
+ */
20
+ HiddenPropertyPlugin.prototype.getName = function () {
21
+ return 'HiddenProperty';
22
+ };
23
+ /**
24
+ * The first method that editor will call to a plugin when editor is initializing.
25
+ * It will pass in the editor instance, plugin should take this chance to save the
26
+ * editor reference so that it can call to any editor method or format API later.
27
+ * @param editor The editor object
28
+ */
29
+ HiddenPropertyPlugin.prototype.initialize = function (editor) {
30
+ this.editor = editor;
31
+ };
32
+ /**
33
+ * The last method that editor will call to a plugin before it is disposed.
34
+ * Plugin can take this chance to clear the reference to editor. After this method is
35
+ * called, plugin should not call to any editor method since it will result in error.
36
+ */
37
+ HiddenPropertyPlugin.prototype.dispose = function () {
38
+ this.editor = null;
39
+ };
40
+ /**
41
+ * Core method for a plugin. Once an event happens in editor, editor will call this
42
+ * method of each plugin to handle the event as long as the event is not handled
43
+ * exclusively by another plugin.
44
+ * @param event The event to handle:
45
+ */
46
+ HiddenPropertyPlugin.prototype.onPluginEvent = function (event) {
47
+ if (!this.editor) {
48
+ return;
49
+ }
50
+ if (event.eventType == 'contentChanged' && event.source == roosterjs_content_model_dom_1.ChangeSource.SetContent) {
51
+ (0, fixupHiddenProperties_1.fixupHiddenProperties)(this.editor, this.option);
52
+ }
53
+ };
54
+ return HiddenPropertyPlugin;
55
+ }());
56
+ exports.HiddenPropertyPlugin = HiddenPropertyPlugin;
57
+ });
58
+ //# sourceMappingURL=HiddenPropertyPlugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HiddenPropertyPlugin.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/hiddenProperty/HiddenPropertyPlugin.ts"],"names":[],"mappings":";;;;IAKA;;OAEG;IACH;QAGI;;;WAGG;QACH,8BAAoB,MAA6B;YAA7B,WAAM,GAAN,MAAM,CAAuB;YANzC,WAAM,GAAmB,IAAI,CAAC;QAMc,CAAC;QAErD;;WAEG;QACH,sCAAO,GAAP;YACI,OAAO,gBAAgB,CAAC;QAC5B,CAAC;QAED;;;;;WAKG;QACH,yCAAU,GAAV,UAAW,MAAe;YACtB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACzB,CAAC;QAED;;;;WAIG;QACH,sCAAO,GAAP;YACI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACvB,CAAC;QAED;;;;;WAKG;QACH,4CAAa,GAAb,UAAc,KAAkB;YAC5B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;gBACd,OAAO;aACV;YAED,IAAI,KAAK,CAAC,SAAS,IAAI,gBAAgB,IAAI,KAAK,CAAC,MAAM,IAAI,0CAAY,CAAC,UAAU,EAAE;gBAChF,IAAA,6CAAqB,EAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;aACnD;QACL,CAAC;QACL,2BAAC;IAAD,CAAC,AAlDD,IAkDC;IAlDY,oDAAoB","sourcesContent":["import { ChangeSource } from 'roosterjs-content-model-dom';\nimport { fixupHiddenProperties } from './fixupHiddenProperties';\nimport type { IEditor, PluginEvent, EditorPlugin } from 'roosterjs-content-model-types';\nimport type { HiddenPropertyOptions } from './HiddenPropertyOptions';\n\n/**\n * HiddenPropertyPlugin helps editor to maintain hidden properties in DOM after editor content is reset using HTML\n */\nexport class HiddenPropertyPlugin implements EditorPlugin {\n private editor: IEditor | null = null;\n\n /**\n * Construct a new instance of FormatPlugin class\n * @param option The editor option\n */\n constructor(private option: HiddenPropertyOptions) {}\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'HiddenProperty';\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) {\n return;\n }\n\n if (event.eventType == 'contentChanged' && event.source == ChangeSource.SetContent) {\n fixupHiddenProperties(this.editor, this.option);\n }\n }\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import type { HiddenPropertyOptions } from './HiddenPropertyOptions';
2
+ import type { IEditor } from 'roosterjs-content-model-types';
3
+ /**
4
+ * @internal
5
+ * Maintain hidden properties in DOM after editor content is reset using HTML
6
+ * This includes:
7
+ * 1. Undeletable property
8
+ */
9
+ export declare function fixupHiddenProperties(editor: IEditor, options: HiddenPropertyOptions): void;
@@ -0,0 +1,38 @@
1
+ define(["require", "exports", "tslib", "roosterjs-content-model-dom"], function (require, exports, tslib_1, roosterjs_content_model_dom_1) {
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.fixupHiddenProperties = void 0;
5
+ /**
6
+ * @internal
7
+ * Maintain hidden properties in DOM after editor content is reset using HTML
8
+ * This includes:
9
+ * 1. Undeletable property
10
+ */
11
+ function fixupHiddenProperties(editor, options) {
12
+ if (options.undeletableLinkChecker) {
13
+ checkUndeletable(editor, options.undeletableLinkChecker);
14
+ }
15
+ // Add more hidden properties checkers here
16
+ }
17
+ exports.fixupHiddenProperties = fixupHiddenProperties;
18
+ function checkUndeletable(editor, checker) {
19
+ var e_1, _a;
20
+ var anchors = editor.getDOMHelper().queryElements('a');
21
+ try {
22
+ for (var anchors_1 = (0, tslib_1.__values)(anchors), anchors_1_1 = anchors_1.next(); !anchors_1_1.done; anchors_1_1 = anchors_1.next()) {
23
+ var a = anchors_1_1.value;
24
+ if (checker(a)) {
25
+ (0, roosterjs_content_model_dom_1.setLinkUndeletable)(a, true);
26
+ }
27
+ }
28
+ }
29
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
30
+ finally {
31
+ try {
32
+ if (anchors_1_1 && !anchors_1_1.done && (_a = anchors_1.return)) _a.call(anchors_1);
33
+ }
34
+ finally { if (e_1) throw e_1.error; }
35
+ }
36
+ }
37
+ });
38
+ //# sourceMappingURL=fixupHiddenProperties.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixupHiddenProperties.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/hiddenProperty/fixupHiddenProperties.ts"],"names":[],"mappings":";;;;IAIA;;;;;OAKG;IACH,SAAgB,qBAAqB,CAAC,MAAe,EAAE,OAA8B;QACjF,IAAI,OAAO,CAAC,sBAAsB,EAAE;YAChC,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;SAC5D;QAED,2CAA2C;IAC/C,CAAC;IAND,sDAMC;IAED,SAAS,gBAAgB,CAAC,MAAe,EAAE,OAA6C;;QACpF,IAAM,OAAO,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;;YAEzD,KAAgB,IAAA,YAAA,sBAAA,OAAO,CAAA,gCAAA,qDAAE;gBAApB,IAAM,CAAC,oBAAA;gBACR,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE;oBACZ,IAAA,gDAAkB,EAAC,CAAC,EAAE,IAAI,CAAC,CAAC;iBAC/B;aACJ;;;;;;;;;IACL,CAAC","sourcesContent":["import { setLinkUndeletable } from 'roosterjs-content-model-dom';\nimport type { HiddenPropertyOptions } from './HiddenPropertyOptions';\nimport type { IEditor } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * Maintain hidden properties in DOM after editor content is reset using HTML\n * This includes:\n * 1. Undeletable property\n */\nexport function fixupHiddenProperties(editor: IEditor, options: HiddenPropertyOptions) {\n if (options.undeletableLinkChecker) {\n checkUndeletable(editor, options.undeletableLinkChecker);\n }\n\n // Add more hidden properties checkers here\n}\n\nfunction checkUndeletable(editor: IEditor, checker: (link: HTMLAnchorElement) => boolean) {\n const anchors = editor.getDOMHelper().queryElements('a');\n\n for (const a of anchors) {\n if (checker(a)) {\n setLinkUndeletable(a, true);\n }\n }\n}\n"]}
@@ -22,3 +22,5 @@ export { PickerSelectionChangMode, PickerDirection, PickerHandler } from './pick
22
22
  export { CustomReplacePlugin, CustomReplace } from './customReplace/CustomReplacePlugin';
23
23
  export { ImageEditPlugin } from './imageEdit/ImageEditPlugin';
24
24
  export { ImageEditOptions } from './imageEdit/types/ImageEditOptions';
25
+ export { HiddenPropertyPlugin } from './hiddenProperty/HiddenPropertyPlugin';
26
+ export { HiddenPropertyOptions } from './hiddenProperty/HiddenPropertyOptions';
package/lib-amd/index.js CHANGED
@@ -1,7 +1,7 @@
1
- define(["require", "exports", "./tableEdit/TableEditPlugin", "./paste/PastePlugin", "./paste/DefaultSanitizers", "./edit/EditPlugin", "./autoFormat/AutoFormatPlugin", "./shortcut/shortcuts", "./shortcut/ShortcutPlugin", "./contextMenuBase/ContextMenuPluginBase", "./watermark/WatermarkPlugin", "./watermark/isModelEmptyFast", "./markdown/MarkdownPlugin", "./hyperlink/HyperlinkPlugin", "./picker/PickerPlugin", "./customReplace/CustomReplacePlugin", "./imageEdit/ImageEditPlugin"], function (require, exports, TableEditPlugin_1, PastePlugin_1, DefaultSanitizers_1, EditPlugin_1, AutoFormatPlugin_1, shortcuts_1, ShortcutPlugin_1, ContextMenuPluginBase_1, WatermarkPlugin_1, isModelEmptyFast_1, MarkdownPlugin_1, HyperlinkPlugin_1, PickerPlugin_1, CustomReplacePlugin_1, ImageEditPlugin_1) {
1
+ define(["require", "exports", "./tableEdit/TableEditPlugin", "./paste/PastePlugin", "./paste/DefaultSanitizers", "./edit/EditPlugin", "./autoFormat/AutoFormatPlugin", "./shortcut/shortcuts", "./shortcut/ShortcutPlugin", "./contextMenuBase/ContextMenuPluginBase", "./watermark/WatermarkPlugin", "./watermark/isModelEmptyFast", "./markdown/MarkdownPlugin", "./hyperlink/HyperlinkPlugin", "./picker/PickerPlugin", "./customReplace/CustomReplacePlugin", "./imageEdit/ImageEditPlugin", "./hiddenProperty/HiddenPropertyPlugin"], function (require, exports, TableEditPlugin_1, PastePlugin_1, DefaultSanitizers_1, EditPlugin_1, AutoFormatPlugin_1, shortcuts_1, ShortcutPlugin_1, ContextMenuPluginBase_1, WatermarkPlugin_1, isModelEmptyFast_1, MarkdownPlugin_1, HyperlinkPlugin_1, PickerPlugin_1, CustomReplacePlugin_1, ImageEditPlugin_1, HiddenPropertyPlugin_1) {
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.ImageEditPlugin = exports.CustomReplacePlugin = exports.PickerPlugin = exports.HyperlinkPlugin = exports.MarkdownPlugin = exports.isModelEmptyFast = exports.WatermarkPlugin = exports.ContextMenuPluginBase = exports.ShortcutPlugin = exports.ShortcutOutdentList = exports.ShortcutIndentList = exports.ShortcutDecreaseFont = exports.ShortcutIncreaseFont = exports.ShortcutNumbering = exports.ShortcutBullet = exports.ShortcutRedoMacOS = exports.ShortcutRedoAlt = exports.ShortcutRedo = exports.ShortcutUndo2 = exports.ShortcutUndo = exports.ShortcutClearFormat = exports.ShortcutUnderline = exports.ShortcutItalic = exports.ShortcutBold = exports.AutoFormatPlugin = exports.EditPlugin = exports.DefaultSanitizers = exports.PastePlugin = exports.TableEditPlugin = void 0;
4
+ exports.HiddenPropertyPlugin = exports.ImageEditPlugin = exports.CustomReplacePlugin = exports.PickerPlugin = exports.HyperlinkPlugin = exports.MarkdownPlugin = exports.isModelEmptyFast = exports.WatermarkPlugin = exports.ContextMenuPluginBase = exports.ShortcutPlugin = exports.ShortcutOutdentList = exports.ShortcutIndentList = exports.ShortcutDecreaseFont = exports.ShortcutIncreaseFont = exports.ShortcutNumbering = exports.ShortcutBullet = exports.ShortcutRedoMacOS = exports.ShortcutRedoAlt = exports.ShortcutRedo = exports.ShortcutUndo2 = exports.ShortcutUndo = exports.ShortcutClearFormat = exports.ShortcutUnderline = exports.ShortcutItalic = exports.ShortcutBold = exports.AutoFormatPlugin = exports.EditPlugin = exports.DefaultSanitizers = exports.PastePlugin = exports.TableEditPlugin = void 0;
5
5
  Object.defineProperty(exports, "TableEditPlugin", { enumerable: true, get: function () { return TableEditPlugin_1.TableEditPlugin; } });
6
6
  Object.defineProperty(exports, "PastePlugin", { enumerable: true, get: function () { return PastePlugin_1.PastePlugin; } });
7
7
  Object.defineProperty(exports, "DefaultSanitizers", { enumerable: true, get: function () { return DefaultSanitizers_1.DefaultSanitizers; } });
@@ -31,5 +31,6 @@ define(["require", "exports", "./tableEdit/TableEditPlugin", "./paste/PastePlugi
31
31
  Object.defineProperty(exports, "PickerPlugin", { enumerable: true, get: function () { return PickerPlugin_1.PickerPlugin; } });
32
32
  Object.defineProperty(exports, "CustomReplacePlugin", { enumerable: true, get: function () { return CustomReplacePlugin_1.CustomReplacePlugin; } });
33
33
  Object.defineProperty(exports, "ImageEditPlugin", { enumerable: true, get: function () { return ImageEditPlugin_1.ImageEditPlugin; } });
34
+ Object.defineProperty(exports, "HiddenPropertyPlugin", { enumerable: true, get: function () { return HiddenPropertyPlugin_1.HiddenPropertyPlugin; } });
34
35
  });
35
36
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../packages/roosterjs-content-model-plugins/lib/index.ts"],"names":[],"mappings":";;;;IAAS,kHAAA,eAAe,OAAA;IAGf,0GAAA,WAAW,OAAA;IACX,sHAAA,iBAAiB,OAAA;IACjB,wGAAA,UAAU,OAAA;IACV,oHAAA,gBAAgB,OAAA;IAIrB,yGAAA,YAAY,OAAA;IACZ,2GAAA,cAAc,OAAA;IACd,8GAAA,iBAAiB,OAAA;IACjB,gHAAA,mBAAmB,OAAA;IACnB,yGAAA,YAAY,OAAA;IACZ,0GAAA,aAAa,OAAA;IACb,yGAAA,YAAY,OAAA;IACZ,4GAAA,eAAe,OAAA;IACf,8GAAA,iBAAiB,OAAA;IACjB,2GAAA,cAAc,OAAA;IACd,8GAAA,iBAAiB,OAAA;IACjB,iHAAA,oBAAoB,OAAA;IACpB,iHAAA,oBAAoB,OAAA;IACpB,+GAAA,kBAAkB,OAAA;IAClB,gHAAA,mBAAmB,OAAA;IAEd,gHAAA,cAAc,OAAA;IAEd,8HAAA,qBAAqB,OAAA;IACrB,kHAAA,eAAe,OAAA;IAEf,oHAAA,gBAAgB,OAAA;IAChB,gHAAA,cAAc,OAAA;IACd,kHAAA,eAAe,OAAA;IAEf,4GAAA,YAAY,OAAA;IAGZ,0HAAA,mBAAmB,OAAA;IACnB,kHAAA,eAAe,OAAA","sourcesContent":["export { TableEditPlugin } from './tableEdit/TableEditPlugin';\nexport { OnTableEditorCreatedCallback } from './tableEdit/OnTableEditorCreatedCallback';\nexport { TableEditFeatureName } from './tableEdit/editors/features/TableEditFeatureName';\nexport { PastePlugin } from './paste/PastePlugin';\nexport { DefaultSanitizers } from './paste/DefaultSanitizers';\nexport { EditPlugin, EditOptions } from './edit/EditPlugin';\nexport { AutoFormatPlugin } from './autoFormat/AutoFormatPlugin';\nexport { AutoFormatOptions } from './autoFormat/interface/AutoFormatOptions';\n\nexport {\n ShortcutBold,\n ShortcutItalic,\n ShortcutUnderline,\n ShortcutClearFormat,\n ShortcutUndo,\n ShortcutUndo2,\n ShortcutRedo,\n ShortcutRedoAlt,\n ShortcutRedoMacOS,\n ShortcutBullet,\n ShortcutNumbering,\n ShortcutIncreaseFont,\n ShortcutDecreaseFont,\n ShortcutIndentList,\n ShortcutOutdentList,\n} from './shortcut/shortcuts';\nexport { ShortcutPlugin } from './shortcut/ShortcutPlugin';\nexport { ShortcutKeyDefinition, ShortcutCommand } from './shortcut/ShortcutCommand';\nexport { ContextMenuPluginBase, ContextMenuOptions } from './contextMenuBase/ContextMenuPluginBase';\nexport { WatermarkPlugin } from './watermark/WatermarkPlugin';\nexport { WatermarkFormat } from './watermark/WatermarkFormat';\nexport { isModelEmptyFast } from './watermark/isModelEmptyFast';\nexport { MarkdownPlugin, MarkdownOptions } from './markdown/MarkdownPlugin';\nexport { HyperlinkPlugin } from './hyperlink/HyperlinkPlugin';\nexport { HyperlinkToolTip } from './hyperlink/HyperlinkToolTip';\nexport { PickerPlugin } from './picker/PickerPlugin';\nexport { PickerHelper } from './picker/PickerHelper';\nexport { PickerSelectionChangMode, PickerDirection, PickerHandler } from './picker/PickerHandler';\nexport { CustomReplacePlugin, CustomReplace } from './customReplace/CustomReplacePlugin';\nexport { ImageEditPlugin } from './imageEdit/ImageEditPlugin';\nexport { ImageEditOptions } from './imageEdit/types/ImageEditOptions';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../packages/roosterjs-content-model-plugins/lib/index.ts"],"names":[],"mappings":";;;;IAAS,kHAAA,eAAe,OAAA;IAGf,0GAAA,WAAW,OAAA;IACX,sHAAA,iBAAiB,OAAA;IACjB,wGAAA,UAAU,OAAA;IACV,oHAAA,gBAAgB,OAAA;IAIrB,yGAAA,YAAY,OAAA;IACZ,2GAAA,cAAc,OAAA;IACd,8GAAA,iBAAiB,OAAA;IACjB,gHAAA,mBAAmB,OAAA;IACnB,yGAAA,YAAY,OAAA;IACZ,0GAAA,aAAa,OAAA;IACb,yGAAA,YAAY,OAAA;IACZ,4GAAA,eAAe,OAAA;IACf,8GAAA,iBAAiB,OAAA;IACjB,2GAAA,cAAc,OAAA;IACd,8GAAA,iBAAiB,OAAA;IACjB,iHAAA,oBAAoB,OAAA;IACpB,iHAAA,oBAAoB,OAAA;IACpB,+GAAA,kBAAkB,OAAA;IAClB,gHAAA,mBAAmB,OAAA;IAEd,gHAAA,cAAc,OAAA;IAEd,8HAAA,qBAAqB,OAAA;IACrB,kHAAA,eAAe,OAAA;IAEf,oHAAA,gBAAgB,OAAA;IAChB,gHAAA,cAAc,OAAA;IACd,kHAAA,eAAe,OAAA;IAEf,4GAAA,YAAY,OAAA;IAGZ,0HAAA,mBAAmB,OAAA;IACnB,kHAAA,eAAe,OAAA;IAEf,4HAAA,oBAAoB,OAAA","sourcesContent":["export { TableEditPlugin } from './tableEdit/TableEditPlugin';\nexport { OnTableEditorCreatedCallback } from './tableEdit/OnTableEditorCreatedCallback';\nexport { TableEditFeatureName } from './tableEdit/editors/features/TableEditFeatureName';\nexport { PastePlugin } from './paste/PastePlugin';\nexport { DefaultSanitizers } from './paste/DefaultSanitizers';\nexport { EditPlugin, EditOptions } from './edit/EditPlugin';\nexport { AutoFormatPlugin } from './autoFormat/AutoFormatPlugin';\nexport { AutoFormatOptions } from './autoFormat/interface/AutoFormatOptions';\n\nexport {\n ShortcutBold,\n ShortcutItalic,\n ShortcutUnderline,\n ShortcutClearFormat,\n ShortcutUndo,\n ShortcutUndo2,\n ShortcutRedo,\n ShortcutRedoAlt,\n ShortcutRedoMacOS,\n ShortcutBullet,\n ShortcutNumbering,\n ShortcutIncreaseFont,\n ShortcutDecreaseFont,\n ShortcutIndentList,\n ShortcutOutdentList,\n} from './shortcut/shortcuts';\nexport { ShortcutPlugin } from './shortcut/ShortcutPlugin';\nexport { ShortcutKeyDefinition, ShortcutCommand } from './shortcut/ShortcutCommand';\nexport { ContextMenuPluginBase, ContextMenuOptions } from './contextMenuBase/ContextMenuPluginBase';\nexport { WatermarkPlugin } from './watermark/WatermarkPlugin';\nexport { WatermarkFormat } from './watermark/WatermarkFormat';\nexport { isModelEmptyFast } from './watermark/isModelEmptyFast';\nexport { MarkdownPlugin, MarkdownOptions } from './markdown/MarkdownPlugin';\nexport { HyperlinkPlugin } from './hyperlink/HyperlinkPlugin';\nexport { HyperlinkToolTip } from './hyperlink/HyperlinkToolTip';\nexport { PickerPlugin } from './picker/PickerPlugin';\nexport { PickerHelper } from './picker/PickerHelper';\nexport { PickerSelectionChangMode, PickerDirection, PickerHandler } from './picker/PickerHandler';\nexport { CustomReplacePlugin, CustomReplace } from './customReplace/CustomReplacePlugin';\nexport { ImageEditPlugin } from './imageEdit/ImageEditPlugin';\nexport { ImageEditOptions } from './imageEdit/types/ImageEditOptions';\nexport { HiddenPropertyPlugin } from './hiddenProperty/HiddenPropertyPlugin';\nexport { HiddenPropertyOptions } from './hiddenProperty/HiddenPropertyOptions';\n"]}
@@ -1,7 +1,7 @@
1
1
  import { deleteAllSegmentBefore } from './deleteSteps/deleteAllSegmentBefore';
2
2
  import { deleteEmptyQuote } from './deleteSteps/deleteEmptyQuote';
3
3
  import { deleteList } from './deleteSteps/deleteList';
4
- import { ChangeSource, deleteSelection, isModifierKey, isNodeOfType, } from 'roosterjs-content-model-dom';
4
+ import { ChangeSource, deleteSelection, isElementOfType, isLinkUndeletable, isModifierKey, isNodeOfType, } from 'roosterjs-content-model-dom';
5
5
  import { handleKeyboardEventResult, shouldDeleteAllSegmentsBefore, shouldDeleteWord, } from './handleKeyboardEventCommon';
6
6
  import { backwardDeleteWordSelection, forwardDeleteWordSelection, } from './deleteSteps/deleteWordSelection';
7
7
  import { backwardDeleteCollapsedSelection, forwardDeleteCollapsedSelection, } from './deleteSteps/deleteCollapsedSelection';
@@ -73,18 +73,39 @@ function shouldDeleteWithContentModel(selection, rawEvent, handleExpandedSelecti
73
73
  }
74
74
  else {
75
75
  var range = selection.range;
76
+ var startContainer = range.startContainer;
77
+ var startOffset = range.startOffset;
76
78
  // When selection is collapsed and is in middle of text node, no need to use Content Model to delete
77
- return !(isNodeOfType(range.startContainer, 'TEXT_NODE') &&
79
+ return !(isNodeOfType(startContainer, 'TEXT_NODE') &&
78
80
  !isModifierKey(rawEvent) &&
79
- (canDeleteBefore(rawEvent, range) || canDeleteAfter(rawEvent, range)));
81
+ (canDeleteBefore(rawEvent, startContainer, startOffset) ||
82
+ canDeleteAfter(rawEvent, startContainer, startOffset)));
80
83
  }
81
84
  }
82
- function canDeleteBefore(rawEvent, range) {
83
- return rawEvent.key == 'Backspace' && range.startOffset > 1;
85
+ function canDeleteBefore(rawEvent, text, offset) {
86
+ var _a, _b;
87
+ if (rawEvent.key != 'Backspace' || offset <= 1) {
88
+ return false;
89
+ }
90
+ var length = (_b = (_a = text.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
91
+ if (offset == length) {
92
+ // At the end of text, need to check if next segment is deletable
93
+ var nextSibling = text.nextSibling;
94
+ var isNextSiblingUndeletable = isNodeOfType(nextSibling, 'ELEMENT_NODE') &&
95
+ isElementOfType(nextSibling, 'a') &&
96
+ isLinkUndeletable(nextSibling) &&
97
+ !nextSibling.firstChild;
98
+ // If next sibling is undeletable, we cannot let browser handle it since it will remove the anchor
99
+ // So we return false here to let Content Model handle it
100
+ return !isNextSiblingUndeletable;
101
+ }
102
+ else {
103
+ // In middle of text, we can safely let browser handle deletion
104
+ return true;
105
+ }
84
106
  }
85
- function canDeleteAfter(rawEvent, range) {
107
+ function canDeleteAfter(rawEvent, text, offset) {
86
108
  var _a, _b;
87
- return (rawEvent.key == 'Delete' &&
88
- range.startOffset < ((_b = (_a = range.startContainer.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) - 1);
109
+ return rawEvent.key == 'Delete' && offset < ((_b = (_a = text.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) - 1;
89
110
  }
90
111
  //# sourceMappingURL=keyboardDelete.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"keyboardDelete.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/keyboardDelete.ts"],"names":[],"mappings":"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","sourcesContent":["import { deleteAllSegmentBefore } from './deleteSteps/deleteAllSegmentBefore';\nimport { deleteEmptyQuote } from './deleteSteps/deleteEmptyQuote';\nimport { deleteList } from './deleteSteps/deleteList';\nimport {\n ChangeSource,\n deleteSelection,\n isModifierKey,\n isNodeOfType,\n} from 'roosterjs-content-model-dom';\nimport {\n handleKeyboardEventResult,\n shouldDeleteAllSegmentsBefore,\n shouldDeleteWord,\n} from './handleKeyboardEventCommon';\nimport {\n backwardDeleteWordSelection,\n forwardDeleteWordSelection,\n} from './deleteSteps/deleteWordSelection';\nimport {\n backwardDeleteCollapsedSelection,\n forwardDeleteCollapsedSelection,\n} from './deleteSteps/deleteCollapsedSelection';\nimport type { DOMSelection, DeleteSelectionStep, IEditor } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * Do keyboard event handling for DELETE/BACKSPACE key\n * @param editor The editor object\n * @param rawEvent DOM keyboard event\n * @param handleExpandedSelection Whether to handle expanded selection within a text node by CM\n * @returns True if the event is handled by content model, otherwise false\n */\nexport function keyboardDelete(\n editor: IEditor,\n rawEvent: KeyboardEvent,\n handleExpandedSelection: boolean = true\n) {\n let handled = false;\n const selection = editor.getDOMSelection();\n\n if (shouldDeleteWithContentModel(selection, rawEvent, handleExpandedSelection)) {\n editor.formatContentModel(\n (model, context) => {\n const result = deleteSelection(\n model,\n getDeleteSteps(rawEvent, !!editor.getEnvironment().isMac),\n context\n ).deleteResult;\n\n handled = handleKeyboardEventResult(editor, model, rawEvent, result, context);\n return handled;\n },\n {\n rawEvent,\n changeSource: ChangeSource.Keyboard,\n getChangeData: () => rawEvent.which,\n scrollCaretIntoView: true,\n apiName: rawEvent.key == 'Delete' ? 'handleDeleteKey' : 'handleBackspaceKey',\n }\n );\n }\n\n return handled;\n}\n\nfunction getDeleteSteps(rawEvent: KeyboardEvent, isMac: boolean): (DeleteSelectionStep | null)[] {\n const isForward = rawEvent.key == 'Delete';\n const deleteAllSegmentBeforeStep =\n shouldDeleteAllSegmentsBefore(rawEvent) && !isForward ? deleteAllSegmentBefore : null;\n const deleteWordSelection = shouldDeleteWord(rawEvent, isMac)\n ? isForward\n ? forwardDeleteWordSelection\n : backwardDeleteWordSelection\n : null;\n const deleteCollapsedSelection = isForward\n ? forwardDeleteCollapsedSelection\n : backwardDeleteCollapsedSelection;\n const deleteQuote = !isForward ? deleteEmptyQuote : null;\n return [\n deleteAllSegmentBeforeStep,\n deleteWordSelection,\n isForward ? null : deleteList,\n deleteCollapsedSelection,\n deleteQuote,\n ];\n}\n\nfunction shouldDeleteWithContentModel(\n selection: DOMSelection | null,\n rawEvent: KeyboardEvent,\n handleExpandedSelection: boolean\n) {\n if (!selection) {\n return false; // Nothing to delete\n } else if (selection.type != 'range') {\n return true;\n } else if (!selection.range.collapsed) {\n if (handleExpandedSelection) {\n return true; // Selection is not collapsed, need to delete all selections\n }\n\n const range = selection.range;\n const { startContainer, endContainer } = selection.range;\n const isInSameTextNode =\n startContainer === endContainer && isNodeOfType(startContainer, 'TEXT_NODE');\n return !(\n isInSameTextNode &&\n !isModifierKey(rawEvent) &&\n range.endOffset - range.startOffset < (startContainer.nodeValue?.length ?? 0)\n );\n } else {\n const range = selection.range;\n\n // When selection is collapsed and is in middle of text node, no need to use Content Model to delete\n return !(\n isNodeOfType(range.startContainer, 'TEXT_NODE') &&\n !isModifierKey(rawEvent) &&\n (canDeleteBefore(rawEvent, range) || canDeleteAfter(rawEvent, range))\n );\n }\n}\n\nfunction canDeleteBefore(rawEvent: KeyboardEvent, range: Range) {\n return rawEvent.key == 'Backspace' && range.startOffset > 1;\n}\n\nfunction canDeleteAfter(rawEvent: KeyboardEvent, range: Range) {\n return (\n rawEvent.key == 'Delete' &&\n range.startOffset < (range.startContainer.nodeValue?.length ?? 0) - 1\n );\n}\n"]}
1
+ {"version":3,"file":"keyboardDelete.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/keyboardDelete.ts"],"names":[],"mappings":"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","sourcesContent":["import { deleteAllSegmentBefore } from './deleteSteps/deleteAllSegmentBefore';\nimport { deleteEmptyQuote } from './deleteSteps/deleteEmptyQuote';\nimport { deleteList } from './deleteSteps/deleteList';\nimport {\n ChangeSource,\n deleteSelection,\n isElementOfType,\n isLinkUndeletable,\n isModifierKey,\n isNodeOfType,\n} from 'roosterjs-content-model-dom';\nimport {\n handleKeyboardEventResult,\n shouldDeleteAllSegmentsBefore,\n shouldDeleteWord,\n} from './handleKeyboardEventCommon';\nimport {\n backwardDeleteWordSelection,\n forwardDeleteWordSelection,\n} from './deleteSteps/deleteWordSelection';\nimport {\n backwardDeleteCollapsedSelection,\n forwardDeleteCollapsedSelection,\n} from './deleteSteps/deleteCollapsedSelection';\nimport type { DOMSelection, DeleteSelectionStep, IEditor } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * Do keyboard event handling for DELETE/BACKSPACE key\n * @param editor The editor object\n * @param rawEvent DOM keyboard event\n * @param handleExpandedSelection Whether to handle expanded selection within a text node by CM\n * @returns True if the event is handled by content model, otherwise false\n */\nexport function keyboardDelete(\n editor: IEditor,\n rawEvent: KeyboardEvent,\n handleExpandedSelection: boolean = true\n) {\n let handled = false;\n const selection = editor.getDOMSelection();\n\n if (shouldDeleteWithContentModel(selection, rawEvent, handleExpandedSelection)) {\n editor.formatContentModel(\n (model, context) => {\n const result = deleteSelection(\n model,\n getDeleteSteps(rawEvent, !!editor.getEnvironment().isMac),\n context\n ).deleteResult;\n\n handled = handleKeyboardEventResult(editor, model, rawEvent, result, context);\n return handled;\n },\n {\n rawEvent,\n changeSource: ChangeSource.Keyboard,\n getChangeData: () => rawEvent.which,\n scrollCaretIntoView: true,\n apiName: rawEvent.key == 'Delete' ? 'handleDeleteKey' : 'handleBackspaceKey',\n }\n );\n }\n\n return handled;\n}\n\nfunction getDeleteSteps(rawEvent: KeyboardEvent, isMac: boolean): (DeleteSelectionStep | null)[] {\n const isForward = rawEvent.key == 'Delete';\n const deleteAllSegmentBeforeStep =\n shouldDeleteAllSegmentsBefore(rawEvent) && !isForward ? deleteAllSegmentBefore : null;\n const deleteWordSelection = shouldDeleteWord(rawEvent, isMac)\n ? isForward\n ? forwardDeleteWordSelection\n : backwardDeleteWordSelection\n : null;\n const deleteCollapsedSelection = isForward\n ? forwardDeleteCollapsedSelection\n : backwardDeleteCollapsedSelection;\n const deleteQuote = !isForward ? deleteEmptyQuote : null;\n return [\n deleteAllSegmentBeforeStep,\n deleteWordSelection,\n isForward ? null : deleteList,\n deleteCollapsedSelection,\n deleteQuote,\n ];\n}\n\nfunction shouldDeleteWithContentModel(\n selection: DOMSelection | null,\n rawEvent: KeyboardEvent,\n handleExpandedSelection: boolean\n) {\n if (!selection) {\n return false; // Nothing to delete\n } else if (selection.type != 'range') {\n return true;\n } else if (!selection.range.collapsed) {\n if (handleExpandedSelection) {\n return true; // Selection is not collapsed, need to delete all selections\n }\n\n const range = selection.range;\n const { startContainer, endContainer } = selection.range;\n const isInSameTextNode =\n startContainer === endContainer && isNodeOfType(startContainer, 'TEXT_NODE');\n return !(\n isInSameTextNode &&\n !isModifierKey(rawEvent) &&\n range.endOffset - range.startOffset < (startContainer.nodeValue?.length ?? 0)\n );\n } else {\n const range = selection.range;\n const startContainer = range.startContainer;\n const startOffset = range.startOffset;\n\n // When selection is collapsed and is in middle of text node, no need to use Content Model to delete\n return !(\n isNodeOfType(startContainer, 'TEXT_NODE') &&\n !isModifierKey(rawEvent) &&\n (canDeleteBefore(rawEvent, startContainer, startOffset) ||\n canDeleteAfter(rawEvent, startContainer, startOffset))\n );\n }\n}\n\nfunction canDeleteBefore(rawEvent: KeyboardEvent, text: Text, offset: number) {\n if (rawEvent.key != 'Backspace' || offset <= 1) {\n return false;\n }\n\n const length = text.nodeValue?.length ?? 0;\n\n if (offset == length) {\n // At the end of text, need to check if next segment is deletable\n const nextSibling = text.nextSibling;\n const isNextSiblingUndeletable =\n isNodeOfType(nextSibling, 'ELEMENT_NODE') &&\n isElementOfType(nextSibling, 'a') &&\n isLinkUndeletable(nextSibling) &&\n !nextSibling.firstChild;\n\n // If next sibling is undeletable, we cannot let browser handle it since it will remove the anchor\n // So we return false here to let Content Model handle it\n return !isNextSiblingUndeletable;\n } else {\n // In middle of text, we can safely let browser handle deletion\n return true;\n }\n}\n\nfunction canDeleteAfter(rawEvent: KeyboardEvent, text: Text, offset: number) {\n return rawEvent.key == 'Delete' && offset < (text.nodeValue?.length ?? 0) - 1;\n}\n"]}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Options for HiddenProperty plugin
3
+ */
4
+ export interface HiddenPropertyOptions {
5
+ /**
6
+ * A helper function to check if a link should be undeletable or not.
7
+ * @param link The link to check
8
+ * @returns True if the link should be undeletable, false otherwise
9
+ */
10
+ undeletableLinkChecker?: (link: HTMLAnchorElement) => boolean;
11
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=HiddenPropertyOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HiddenPropertyOptions.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/hiddenProperty/HiddenPropertyOptions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Options for HiddenProperty plugin\n */\nexport interface HiddenPropertyOptions {\n /**\n * A helper function to check if a link should be undeletable or not.\n * @param link The link to check\n * @returns True if the link should be undeletable, false otherwise\n */\n undeletableLinkChecker?: (link: HTMLAnchorElement) => boolean;\n}\n"]}
@@ -0,0 +1,38 @@
1
+ import type { IEditor, PluginEvent, EditorPlugin } from 'roosterjs-content-model-types';
2
+ import type { HiddenPropertyOptions } from './HiddenPropertyOptions';
3
+ /**
4
+ * HiddenPropertyPlugin helps editor to maintain hidden properties in DOM after editor content is reset using HTML
5
+ */
6
+ export declare class HiddenPropertyPlugin implements EditorPlugin {
7
+ private option;
8
+ private editor;
9
+ /**
10
+ * Construct a new instance of FormatPlugin class
11
+ * @param option The editor option
12
+ */
13
+ constructor(option: HiddenPropertyOptions);
14
+ /**
15
+ * Get name of this plugin
16
+ */
17
+ getName(): string;
18
+ /**
19
+ * The first method that editor will call to a plugin when editor is initializing.
20
+ * It will pass in the editor instance, plugin should take this chance to save the
21
+ * editor reference so that it can call to any editor method or format API later.
22
+ * @param editor The editor object
23
+ */
24
+ initialize(editor: IEditor): void;
25
+ /**
26
+ * The last method that editor will call to a plugin before it is disposed.
27
+ * Plugin can take this chance to clear the reference to editor. After this method is
28
+ * called, plugin should not call to any editor method since it will result in error.
29
+ */
30
+ dispose(): void;
31
+ /**
32
+ * Core method for a plugin. Once an event happens in editor, editor will call this
33
+ * method of each plugin to handle the event as long as the event is not handled
34
+ * exclusively by another plugin.
35
+ * @param event The event to handle:
36
+ */
37
+ onPluginEvent(event: PluginEvent): void;
38
+ }
@@ -0,0 +1,55 @@
1
+ import { ChangeSource } from 'roosterjs-content-model-dom';
2
+ import { fixupHiddenProperties } from './fixupHiddenProperties';
3
+ /**
4
+ * HiddenPropertyPlugin helps editor to maintain hidden properties in DOM after editor content is reset using HTML
5
+ */
6
+ var HiddenPropertyPlugin = /** @class */ (function () {
7
+ /**
8
+ * Construct a new instance of FormatPlugin class
9
+ * @param option The editor option
10
+ */
11
+ function HiddenPropertyPlugin(option) {
12
+ this.option = option;
13
+ this.editor = null;
14
+ }
15
+ /**
16
+ * Get name of this plugin
17
+ */
18
+ HiddenPropertyPlugin.prototype.getName = function () {
19
+ return 'HiddenProperty';
20
+ };
21
+ /**
22
+ * The first method that editor will call to a plugin when editor is initializing.
23
+ * It will pass in the editor instance, plugin should take this chance to save the
24
+ * editor reference so that it can call to any editor method or format API later.
25
+ * @param editor The editor object
26
+ */
27
+ HiddenPropertyPlugin.prototype.initialize = function (editor) {
28
+ this.editor = editor;
29
+ };
30
+ /**
31
+ * The last method that editor will call to a plugin before it is disposed.
32
+ * Plugin can take this chance to clear the reference to editor. After this method is
33
+ * called, plugin should not call to any editor method since it will result in error.
34
+ */
35
+ HiddenPropertyPlugin.prototype.dispose = function () {
36
+ this.editor = null;
37
+ };
38
+ /**
39
+ * Core method for a plugin. Once an event happens in editor, editor will call this
40
+ * method of each plugin to handle the event as long as the event is not handled
41
+ * exclusively by another plugin.
42
+ * @param event The event to handle:
43
+ */
44
+ HiddenPropertyPlugin.prototype.onPluginEvent = function (event) {
45
+ if (!this.editor) {
46
+ return;
47
+ }
48
+ if (event.eventType == 'contentChanged' && event.source == ChangeSource.SetContent) {
49
+ fixupHiddenProperties(this.editor, this.option);
50
+ }
51
+ };
52
+ return HiddenPropertyPlugin;
53
+ }());
54
+ export { HiddenPropertyPlugin };
55
+ //# sourceMappingURL=HiddenPropertyPlugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HiddenPropertyPlugin.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/hiddenProperty/HiddenPropertyPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAIhE;;GAEG;AACH;IAGI;;;OAGG;IACH,8BAAoB,MAA6B;QAA7B,WAAM,GAAN,MAAM,CAAuB;QANzC,WAAM,GAAmB,IAAI,CAAC;IAMc,CAAC;IAErD;;OAEG;IACH,sCAAO,GAAP;QACI,OAAO,gBAAgB,CAAC;IAC5B,CAAC;IAED;;;;;OAKG;IACH,yCAAU,GAAV,UAAW,MAAe;QACtB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;IAED;;;;OAIG;IACH,sCAAO,GAAP;QACI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IACvB,CAAC;IAED;;;;;OAKG;IACH,4CAAa,GAAb,UAAc,KAAkB;QAC5B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YACd,OAAO;SACV;QAED,IAAI,KAAK,CAAC,SAAS,IAAI,gBAAgB,IAAI,KAAK,CAAC,MAAM,IAAI,YAAY,CAAC,UAAU,EAAE;YAChF,qBAAqB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;SACnD;IACL,CAAC;IACL,2BAAC;AAAD,CAAC,AAlDD,IAkDC","sourcesContent":["import { ChangeSource } from 'roosterjs-content-model-dom';\nimport { fixupHiddenProperties } from './fixupHiddenProperties';\nimport type { IEditor, PluginEvent, EditorPlugin } from 'roosterjs-content-model-types';\nimport type { HiddenPropertyOptions } from './HiddenPropertyOptions';\n\n/**\n * HiddenPropertyPlugin helps editor to maintain hidden properties in DOM after editor content is reset using HTML\n */\nexport class HiddenPropertyPlugin implements EditorPlugin {\n private editor: IEditor | null = null;\n\n /**\n * Construct a new instance of FormatPlugin class\n * @param option The editor option\n */\n constructor(private option: HiddenPropertyOptions) {}\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'HiddenProperty';\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) {\n return;\n }\n\n if (event.eventType == 'contentChanged' && event.source == ChangeSource.SetContent) {\n fixupHiddenProperties(this.editor, this.option);\n }\n }\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import type { HiddenPropertyOptions } from './HiddenPropertyOptions';
2
+ import type { IEditor } from 'roosterjs-content-model-types';
3
+ /**
4
+ * @internal
5
+ * Maintain hidden properties in DOM after editor content is reset using HTML
6
+ * This includes:
7
+ * 1. Undeletable property
8
+ */
9
+ export declare function fixupHiddenProperties(editor: IEditor, options: HiddenPropertyOptions): void;
@@ -0,0 +1,34 @@
1
+ import { __values } from "tslib";
2
+ import { setLinkUndeletable } from 'roosterjs-content-model-dom';
3
+ /**
4
+ * @internal
5
+ * Maintain hidden properties in DOM after editor content is reset using HTML
6
+ * This includes:
7
+ * 1. Undeletable property
8
+ */
9
+ export function fixupHiddenProperties(editor, options) {
10
+ if (options.undeletableLinkChecker) {
11
+ checkUndeletable(editor, options.undeletableLinkChecker);
12
+ }
13
+ // Add more hidden properties checkers here
14
+ }
15
+ function checkUndeletable(editor, checker) {
16
+ var e_1, _a;
17
+ var anchors = editor.getDOMHelper().queryElements('a');
18
+ try {
19
+ for (var anchors_1 = __values(anchors), anchors_1_1 = anchors_1.next(); !anchors_1_1.done; anchors_1_1 = anchors_1.next()) {
20
+ var a = anchors_1_1.value;
21
+ if (checker(a)) {
22
+ setLinkUndeletable(a, true);
23
+ }
24
+ }
25
+ }
26
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
27
+ finally {
28
+ try {
29
+ if (anchors_1_1 && !anchors_1_1.done && (_a = anchors_1.return)) _a.call(anchors_1);
30
+ }
31
+ finally { if (e_1) throw e_1.error; }
32
+ }
33
+ }
34
+ //# sourceMappingURL=fixupHiddenProperties.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixupHiddenProperties.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/hiddenProperty/fixupHiddenProperties.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAIjE;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAe,EAAE,OAA8B;IACjF,IAAI,OAAO,CAAC,sBAAsB,EAAE;QAChC,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;KAC5D;IAED,2CAA2C;AAC/C,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAe,EAAE,OAA6C;;IACpF,IAAM,OAAO,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;;QAEzD,KAAgB,IAAA,YAAA,SAAA,OAAO,CAAA,gCAAA,qDAAE;YAApB,IAAM,CAAC,oBAAA;YACR,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE;gBACZ,kBAAkB,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;aAC/B;SACJ;;;;;;;;;AACL,CAAC","sourcesContent":["import { setLinkUndeletable } from 'roosterjs-content-model-dom';\nimport type { HiddenPropertyOptions } from './HiddenPropertyOptions';\nimport type { IEditor } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * Maintain hidden properties in DOM after editor content is reset using HTML\n * This includes:\n * 1. Undeletable property\n */\nexport function fixupHiddenProperties(editor: IEditor, options: HiddenPropertyOptions) {\n if (options.undeletableLinkChecker) {\n checkUndeletable(editor, options.undeletableLinkChecker);\n }\n\n // Add more hidden properties checkers here\n}\n\nfunction checkUndeletable(editor: IEditor, checker: (link: HTMLAnchorElement) => boolean) {\n const anchors = editor.getDOMHelper().queryElements('a');\n\n for (const a of anchors) {\n if (checker(a)) {\n setLinkUndeletable(a, true);\n }\n }\n}\n"]}
@@ -22,3 +22,5 @@ export { PickerSelectionChangMode, PickerDirection, PickerHandler } from './pick
22
22
  export { CustomReplacePlugin, CustomReplace } from './customReplace/CustomReplacePlugin';
23
23
  export { ImageEditPlugin } from './imageEdit/ImageEditPlugin';
24
24
  export { ImageEditOptions } from './imageEdit/types/ImageEditOptions';
25
+ export { HiddenPropertyPlugin } from './hiddenProperty/HiddenPropertyPlugin';
26
+ export { HiddenPropertyOptions } from './hiddenProperty/HiddenPropertyOptions';
package/lib-mjs/index.js CHANGED
@@ -13,4 +13,5 @@ export { HyperlinkPlugin } from './hyperlink/HyperlinkPlugin';
13
13
  export { PickerPlugin } from './picker/PickerPlugin';
14
14
  export { CustomReplacePlugin } from './customReplace/CustomReplacePlugin';
15
15
  export { ImageEditPlugin } from './imageEdit/ImageEditPlugin';
16
+ export { HiddenPropertyPlugin } from './hiddenProperty/HiddenPropertyPlugin';
16
17
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../packages/roosterjs-content-model-plugins/lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAG9D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAe,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,OAAO,EACH,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,GACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,qBAAqB,EAAsB,MAAM,yCAAyC,CAAC;AACpG,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAmB,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGrD,OAAO,EAAE,mBAAmB,EAAiB,MAAM,qCAAqC,CAAC;AACzF,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC","sourcesContent":["export { TableEditPlugin } from './tableEdit/TableEditPlugin';\nexport { OnTableEditorCreatedCallback } from './tableEdit/OnTableEditorCreatedCallback';\nexport { TableEditFeatureName } from './tableEdit/editors/features/TableEditFeatureName';\nexport { PastePlugin } from './paste/PastePlugin';\nexport { DefaultSanitizers } from './paste/DefaultSanitizers';\nexport { EditPlugin, EditOptions } from './edit/EditPlugin';\nexport { AutoFormatPlugin } from './autoFormat/AutoFormatPlugin';\nexport { AutoFormatOptions } from './autoFormat/interface/AutoFormatOptions';\n\nexport {\n ShortcutBold,\n ShortcutItalic,\n ShortcutUnderline,\n ShortcutClearFormat,\n ShortcutUndo,\n ShortcutUndo2,\n ShortcutRedo,\n ShortcutRedoAlt,\n ShortcutRedoMacOS,\n ShortcutBullet,\n ShortcutNumbering,\n ShortcutIncreaseFont,\n ShortcutDecreaseFont,\n ShortcutIndentList,\n ShortcutOutdentList,\n} from './shortcut/shortcuts';\nexport { ShortcutPlugin } from './shortcut/ShortcutPlugin';\nexport { ShortcutKeyDefinition, ShortcutCommand } from './shortcut/ShortcutCommand';\nexport { ContextMenuPluginBase, ContextMenuOptions } from './contextMenuBase/ContextMenuPluginBase';\nexport { WatermarkPlugin } from './watermark/WatermarkPlugin';\nexport { WatermarkFormat } from './watermark/WatermarkFormat';\nexport { isModelEmptyFast } from './watermark/isModelEmptyFast';\nexport { MarkdownPlugin, MarkdownOptions } from './markdown/MarkdownPlugin';\nexport { HyperlinkPlugin } from './hyperlink/HyperlinkPlugin';\nexport { HyperlinkToolTip } from './hyperlink/HyperlinkToolTip';\nexport { PickerPlugin } from './picker/PickerPlugin';\nexport { PickerHelper } from './picker/PickerHelper';\nexport { PickerSelectionChangMode, PickerDirection, PickerHandler } from './picker/PickerHandler';\nexport { CustomReplacePlugin, CustomReplace } from './customReplace/CustomReplacePlugin';\nexport { ImageEditPlugin } from './imageEdit/ImageEditPlugin';\nexport { ImageEditOptions } from './imageEdit/types/ImageEditOptions';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../packages/roosterjs-content-model-plugins/lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAG9D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAe,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,OAAO,EACH,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,GACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,qBAAqB,EAAsB,MAAM,yCAAyC,CAAC;AACpG,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAmB,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGrD,OAAO,EAAE,mBAAmB,EAAiB,MAAM,qCAAqC,CAAC;AACzF,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC","sourcesContent":["export { TableEditPlugin } from './tableEdit/TableEditPlugin';\nexport { OnTableEditorCreatedCallback } from './tableEdit/OnTableEditorCreatedCallback';\nexport { TableEditFeatureName } from './tableEdit/editors/features/TableEditFeatureName';\nexport { PastePlugin } from './paste/PastePlugin';\nexport { DefaultSanitizers } from './paste/DefaultSanitizers';\nexport { EditPlugin, EditOptions } from './edit/EditPlugin';\nexport { AutoFormatPlugin } from './autoFormat/AutoFormatPlugin';\nexport { AutoFormatOptions } from './autoFormat/interface/AutoFormatOptions';\n\nexport {\n ShortcutBold,\n ShortcutItalic,\n ShortcutUnderline,\n ShortcutClearFormat,\n ShortcutUndo,\n ShortcutUndo2,\n ShortcutRedo,\n ShortcutRedoAlt,\n ShortcutRedoMacOS,\n ShortcutBullet,\n ShortcutNumbering,\n ShortcutIncreaseFont,\n ShortcutDecreaseFont,\n ShortcutIndentList,\n ShortcutOutdentList,\n} from './shortcut/shortcuts';\nexport { ShortcutPlugin } from './shortcut/ShortcutPlugin';\nexport { ShortcutKeyDefinition, ShortcutCommand } from './shortcut/ShortcutCommand';\nexport { ContextMenuPluginBase, ContextMenuOptions } from './contextMenuBase/ContextMenuPluginBase';\nexport { WatermarkPlugin } from './watermark/WatermarkPlugin';\nexport { WatermarkFormat } from './watermark/WatermarkFormat';\nexport { isModelEmptyFast } from './watermark/isModelEmptyFast';\nexport { MarkdownPlugin, MarkdownOptions } from './markdown/MarkdownPlugin';\nexport { HyperlinkPlugin } from './hyperlink/HyperlinkPlugin';\nexport { HyperlinkToolTip } from './hyperlink/HyperlinkToolTip';\nexport { PickerPlugin } from './picker/PickerPlugin';\nexport { PickerHelper } from './picker/PickerHelper';\nexport { PickerSelectionChangMode, PickerDirection, PickerHandler } from './picker/PickerHandler';\nexport { CustomReplacePlugin, CustomReplace } from './customReplace/CustomReplacePlugin';\nexport { ImageEditPlugin } from './imageEdit/ImageEditPlugin';\nexport { ImageEditOptions } from './imageEdit/types/ImageEditOptions';\nexport { HiddenPropertyPlugin } from './hiddenProperty/HiddenPropertyPlugin';\nexport { HiddenPropertyOptions } from './hiddenProperty/HiddenPropertyOptions';\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.22.0",
7
- "roosterjs-content-model-dom": "^9.22.0",
8
- "roosterjs-content-model-types": "^9.22.0",
9
- "roosterjs-content-model-api": "^9.22.0"
6
+ "roosterjs-content-model-core": "^9.23.0",
7
+ "roosterjs-content-model-dom": "^9.23.0",
8
+ "roosterjs-content-model-types": "^9.23.0",
9
+ "roosterjs-content-model-api": "^9.23.0"
10
10
  },
11
- "version": "9.22.0",
11
+ "version": "9.23.0",
12
12
  "main": "./lib/index.js",
13
13
  "typings": "./lib/index.d.ts",
14
14
  "module": "./lib-mjs/index.js",