roosterjs-content-model-plugins 9.39.0 → 9.40.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.
- package/lib/edit/EditOptions.d.ts +45 -0
- package/lib/edit/EditOptions.js +3 -0
- package/lib/edit/EditOptions.js.map +1 -0
- package/lib/edit/EditPlugin.d.ts +1 -28
- package/lib/edit/EditPlugin.js +6 -9
- package/lib/edit/EditPlugin.js.map +1 -1
- package/lib/edit/deleteSteps/deleteCollapsedSelection.d.ts +7 -6
- package/lib/edit/deleteSteps/deleteCollapsedSelection.js +12 -10
- package/lib/edit/deleteSteps/deleteCollapsedSelection.js.map +1 -1
- package/lib/edit/inputSteps/handleEnterOnParagraph.d.ts +1 -1
- package/lib/edit/inputSteps/handleEnterOnParagraph.js +3 -3
- package/lib/edit/inputSteps/handleEnterOnParagraph.js.map +1 -1
- package/lib/edit/keyboardDelete.d.ts +2 -1
- package/lib/edit/keyboardDelete.js +7 -9
- package/lib/edit/keyboardDelete.js.map +1 -1
- package/lib/edit/keyboardEnter.d.ts +1 -1
- package/lib/edit/keyboardEnter.js +3 -2
- package/lib/edit/keyboardEnter.js.map +1 -1
- package/lib/edit/utils/preserveParagraphFormat.d.ts +9 -0
- package/lib/edit/utils/preserveParagraphFormat.js +24 -0
- package/lib/edit/utils/preserveParagraphFormat.js.map +1 -0
- package/lib/edit/utils/splitParagraph.d.ts +1 -1
- package/lib/edit/utils/splitParagraph.js +4 -1
- package/lib/edit/utils/splitParagraph.js.map +1 -1
- package/lib/index.d.ts +2 -1
- package/lib/index.js.map +1 -1
- package/lib-amd/edit/EditOptions.d.ts +45 -0
- package/lib-amd/edit/EditOptions.js +5 -0
- package/lib-amd/edit/EditOptions.js.map +1 -0
- package/lib-amd/edit/EditPlugin.d.ts +1 -28
- package/lib-amd/edit/EditPlugin.js +6 -9
- package/lib-amd/edit/EditPlugin.js.map +1 -1
- package/lib-amd/edit/deleteSteps/deleteCollapsedSelection.d.ts +7 -6
- package/lib-amd/edit/deleteSteps/deleteCollapsedSelection.js +12 -11
- package/lib-amd/edit/deleteSteps/deleteCollapsedSelection.js.map +1 -1
- package/lib-amd/edit/inputSteps/handleEnterOnParagraph.d.ts +1 -1
- package/lib-amd/edit/inputSteps/handleEnterOnParagraph.js +3 -3
- package/lib-amd/edit/inputSteps/handleEnterOnParagraph.js.map +1 -1
- package/lib-amd/edit/keyboardDelete.d.ts +2 -1
- package/lib-amd/edit/keyboardDelete.js +7 -9
- package/lib-amd/edit/keyboardDelete.js.map +1 -1
- package/lib-amd/edit/keyboardEnter.d.ts +1 -1
- package/lib-amd/edit/keyboardEnter.js +3 -2
- package/lib-amd/edit/keyboardEnter.js.map +1 -1
- package/lib-amd/edit/utils/preserveParagraphFormat.d.ts +9 -0
- package/lib-amd/edit/utils/preserveParagraphFormat.js +26 -0
- package/lib-amd/edit/utils/preserveParagraphFormat.js.map +1 -0
- package/lib-amd/edit/utils/splitParagraph.d.ts +1 -1
- package/lib-amd/edit/utils/splitParagraph.js +4 -2
- package/lib-amd/edit/utils/splitParagraph.js.map +1 -1
- package/lib-amd/index.d.ts +2 -1
- package/lib-amd/index.js.map +1 -1
- package/lib-mjs/edit/EditOptions.d.ts +45 -0
- package/lib-mjs/edit/EditOptions.js +2 -0
- package/lib-mjs/edit/EditOptions.js.map +1 -0
- package/lib-mjs/edit/EditPlugin.d.ts +1 -28
- package/lib-mjs/edit/EditPlugin.js +6 -9
- package/lib-mjs/edit/EditPlugin.js.map +1 -1
- package/lib-mjs/edit/deleteSteps/deleteCollapsedSelection.d.ts +7 -6
- package/lib-mjs/edit/deleteSteps/deleteCollapsedSelection.js +10 -9
- package/lib-mjs/edit/deleteSteps/deleteCollapsedSelection.js.map +1 -1
- package/lib-mjs/edit/inputSteps/handleEnterOnParagraph.d.ts +1 -1
- package/lib-mjs/edit/inputSteps/handleEnterOnParagraph.js +3 -3
- package/lib-mjs/edit/inputSteps/handleEnterOnParagraph.js.map +1 -1
- package/lib-mjs/edit/keyboardDelete.d.ts +2 -1
- package/lib-mjs/edit/keyboardDelete.js +7 -9
- package/lib-mjs/edit/keyboardDelete.js.map +1 -1
- package/lib-mjs/edit/keyboardEnter.d.ts +1 -1
- package/lib-mjs/edit/keyboardEnter.js +3 -2
- package/lib-mjs/edit/keyboardEnter.js.map +1 -1
- package/lib-mjs/edit/utils/preserveParagraphFormat.d.ts +9 -0
- package/lib-mjs/edit/utils/preserveParagraphFormat.js +20 -0
- package/lib-mjs/edit/utils/preserveParagraphFormat.js.map +1 -0
- package/lib-mjs/edit/utils/splitParagraph.d.ts +1 -1
- package/lib-mjs/edit/utils/splitParagraph.js +4 -1
- package/lib-mjs/edit/utils/splitParagraph.js.map +1 -1
- package/lib-mjs/index.d.ts +2 -1
- package/lib-mjs/index.js.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { IEditor } from 'roosterjs-content-model-types';
|
|
2
|
+
/**
|
|
3
|
+
* Options to customize the keyboard handling behavior of Edit plugin
|
|
4
|
+
*/
|
|
5
|
+
export declare type EditOptions = {
|
|
6
|
+
/**
|
|
7
|
+
* Whether to handle Tab key in keyboard. @default true
|
|
8
|
+
*/
|
|
9
|
+
handleTabKey?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Whether expanded selection within a text node should be handled by CM when pressing Backspace/Delete key.
|
|
12
|
+
* @default true
|
|
13
|
+
*/
|
|
14
|
+
handleExpandedSelectionOnDelete?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Callback function to determine whether the Rooster should handle the Enter key press.
|
|
17
|
+
* If the function returns true, the Rooster will handle the Enter key press instead of the browser.
|
|
18
|
+
* @param editor - The editor instance.
|
|
19
|
+
* @returns A boolean
|
|
20
|
+
*/
|
|
21
|
+
shouldHandleEnterKey?: ((editor: IEditor) => boolean) | boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Callback or boolean to determine whether the browser (not Content Model) should handle the Backspace key press.
|
|
24
|
+
* If the value/callback returns true, Rooster will NOT handle Backspace and will defer to the browser's native behavior.
|
|
25
|
+
* @param editor - The editor instance (when using callback).
|
|
26
|
+
* @returns A boolean
|
|
27
|
+
*/
|
|
28
|
+
shouldHandleBackspaceKey?: ((editor: IEditor) => boolean) | boolean;
|
|
29
|
+
/**
|
|
30
|
+
* An array of format property names that should be preserved when merging paragraphs
|
|
31
|
+
* during editing operations such as pressing Enter, Backspace, or Delete keys.
|
|
32
|
+
* This ensures consistent formatting is maintained across paragraph operations.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* // Preserve font family and class name during paragraph operations
|
|
36
|
+
* formatsToPreserveOnMerge: ['fontFamily', 'className']
|
|
37
|
+
*
|
|
38
|
+
* // When pressing Enter in a paragraph with fontFamily='Arial' and className='highlight',
|
|
39
|
+
* // the new paragraph will inherit both properties: fontFamily='Arial' and className='highlight'
|
|
40
|
+
*
|
|
41
|
+
* // When pressing Backspace to merge two paragraphs, the preserved formats from the first
|
|
42
|
+
* // paragraph will be applied to the merged result
|
|
43
|
+
*/
|
|
44
|
+
formatsToPreserveOnMerge?: string[];
|
|
45
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EditOptions.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/EditOptions.ts"],"names":[],"mappings":"","sourcesContent":["import type { IEditor } from 'roosterjs-content-model-types';\n\n/**\n * Options to customize the keyboard handling behavior of Edit plugin\n */\n\nexport type EditOptions = {\n /**\n * Whether to handle Tab key in keyboard. @default true\n */\n handleTabKey?: boolean;\n\n /**\n * Whether expanded selection within a text node should be handled by CM when pressing Backspace/Delete key.\n * @default true\n */\n handleExpandedSelectionOnDelete?: boolean;\n\n /**\n * Callback function to determine whether the Rooster should handle the Enter key press.\n * If the function returns true, the Rooster will handle the Enter key press instead of the browser.\n * @param editor - The editor instance.\n * @returns A boolean\n */\n shouldHandleEnterKey?: ((editor: IEditor) => boolean) | boolean;\n\n /**\n * Callback or boolean to determine whether the browser (not Content Model) should handle the Backspace key press.\n * If the value/callback returns true, Rooster will NOT handle Backspace and will defer to the browser's native behavior.\n * @param editor - The editor instance (when using callback).\n * @returns A boolean\n */\n shouldHandleBackspaceKey?: ((editor: IEditor) => boolean) | boolean;\n\n /**\n * An array of format property names that should be preserved when merging paragraphs\n * during editing operations such as pressing Enter, Backspace, or Delete keys.\n * This ensures consistent formatting is maintained across paragraph operations.\n *\n * @example\n * // Preserve font family and class name during paragraph operations\n * formatsToPreserveOnMerge: ['fontFamily', 'className']\n *\n * // When pressing Enter in a paragraph with fontFamily='Arial' and className='highlight',\n * // the new paragraph will inherit both properties: fontFamily='Arial' and className='highlight'\n *\n * // When pressing Backspace to merge two paragraphs, the preserved formats from the first\n * // paragraph will be applied to the merged result\n */\n formatsToPreserveOnMerge?: string[];\n};\n"]}
|
package/lib/edit/EditPlugin.d.ts
CHANGED
|
@@ -1,32 +1,5 @@
|
|
|
1
|
+
import type { EditOptions } from './EditOptions';
|
|
1
2
|
import type { EditorPlugin, IEditor, PluginEvent } from 'roosterjs-content-model-types';
|
|
2
|
-
/**
|
|
3
|
-
* Options to customize the keyboard handling behavior of Edit plugin
|
|
4
|
-
*/
|
|
5
|
-
export declare type EditOptions = {
|
|
6
|
-
/**
|
|
7
|
-
* Whether to handle Tab key in keyboard. @default true
|
|
8
|
-
*/
|
|
9
|
-
handleTabKey?: boolean;
|
|
10
|
-
/**
|
|
11
|
-
* Whether expanded selection within a text node should be handled by CM when pressing Backspace/Delete key.
|
|
12
|
-
* @default true
|
|
13
|
-
*/
|
|
14
|
-
handleExpandedSelectionOnDelete?: boolean;
|
|
15
|
-
/**
|
|
16
|
-
* Callback function to determine whether the Rooster should handle the Enter key press.
|
|
17
|
-
* If the function returns true, the Rooster will handle the Enter key press instead of the browser.
|
|
18
|
-
* @param editor - The editor instance.
|
|
19
|
-
* @returns A boolean
|
|
20
|
-
*/
|
|
21
|
-
shouldHandleEnterKey?: ((editor: IEditor) => boolean) | boolean;
|
|
22
|
-
/**
|
|
23
|
-
* Callback or boolean to determine whether the browser (not Content Model) should handle the Backspace key press.
|
|
24
|
-
* If the value/callback returns true, Rooster will NOT handle Backspace and will defer to the browser's native behavior.
|
|
25
|
-
* @param editor - The editor instance (when using callback).
|
|
26
|
-
* @returns A boolean
|
|
27
|
-
*/
|
|
28
|
-
shouldHandleBackspaceKey?: ((editor: IEditor) => boolean) | boolean;
|
|
29
|
-
};
|
|
30
3
|
/**
|
|
31
4
|
* Edit plugins helps editor to do editing operation on top of content model.
|
|
32
5
|
* This includes:
|
package/lib/edit/EditPlugin.js
CHANGED
|
@@ -39,7 +39,7 @@ var EditPlugin = /** @class */ (function () {
|
|
|
39
39
|
this.disposer = null;
|
|
40
40
|
this.shouldHandleNextInputEvent = false;
|
|
41
41
|
this.selectionAfterDelete = null;
|
|
42
|
-
this.handleNormalEnter = function (
|
|
42
|
+
this.handleNormalEnter = function () { return false; };
|
|
43
43
|
this.options = (0, tslib_1.__assign)((0, tslib_1.__assign)({}, DefaultOptions), options);
|
|
44
44
|
}
|
|
45
45
|
EditPlugin.prototype.createNormalEnterChecker = function (result) {
|
|
@@ -49,13 +49,10 @@ var EditPlugin = /** @class */ (function () {
|
|
|
49
49
|
switch (typeof this.options.shouldHandleEnterKey) {
|
|
50
50
|
case 'function':
|
|
51
51
|
return this.options.shouldHandleEnterKey;
|
|
52
|
-
break;
|
|
53
52
|
case 'boolean':
|
|
54
53
|
return this.createNormalEnterChecker(this.options.shouldHandleEnterKey);
|
|
55
|
-
break;
|
|
56
54
|
default:
|
|
57
55
|
return this.createNormalEnterChecker(editor.isExperimentalFeatureEnabled('HandleEnterKey'));
|
|
58
|
-
break;
|
|
59
56
|
}
|
|
60
57
|
};
|
|
61
58
|
/**
|
|
@@ -155,7 +152,7 @@ var EditPlugin = /** @class */ (function () {
|
|
|
155
152
|
// Use our API to handle BACKSPACE/DELETE key.
|
|
156
153
|
// No need to clear cache here since if we rely on browser's behavior, there will be Input event and its handler will reconcile cache
|
|
157
154
|
if (!this.shouldBrowserHandleBackspace(editor)) {
|
|
158
|
-
(0, keyboardDelete_1.keyboardDelete)(editor, rawEvent, this.options
|
|
155
|
+
(0, keyboardDelete_1.keyboardDelete)(editor, rawEvent, this.options);
|
|
159
156
|
}
|
|
160
157
|
break;
|
|
161
158
|
case 'Delete':
|
|
@@ -163,7 +160,7 @@ var EditPlugin = /** @class */ (function () {
|
|
|
163
160
|
// No need to clear cache here since if we rely on browser's behavior, there will be Input event and its handler will reconcile cache
|
|
164
161
|
// And leave it to browser when shift key is pressed so that browser will trigger cut event
|
|
165
162
|
if (!event.rawEvent.shiftKey) {
|
|
166
|
-
(0, keyboardDelete_1.keyboardDelete)(editor, rawEvent, this.options
|
|
163
|
+
(0, keyboardDelete_1.keyboardDelete)(editor, rawEvent, this.options);
|
|
167
164
|
}
|
|
168
165
|
break;
|
|
169
166
|
case 'Tab':
|
|
@@ -180,7 +177,7 @@ var EditPlugin = /** @class */ (function () {
|
|
|
180
177
|
if (!hasCtrlOrMetaKey &&
|
|
181
178
|
!event.rawEvent.isComposing &&
|
|
182
179
|
event.rawEvent.keyCode !== DEAD_KEY) {
|
|
183
|
-
(0, keyboardEnter_1.keyboardEnter)(editor, rawEvent, this.handleNormalEnter(editor));
|
|
180
|
+
(0, keyboardEnter_1.keyboardEnter)(editor, rawEvent, this.handleNormalEnter(editor), this.options.formatsToPreserveOnMerge);
|
|
184
181
|
}
|
|
185
182
|
break;
|
|
186
183
|
default:
|
|
@@ -207,7 +204,7 @@ var EditPlugin = /** @class */ (function () {
|
|
|
207
204
|
key: 'Backspace',
|
|
208
205
|
keyCode: BACKSPACE_KEY,
|
|
209
206
|
which: BACKSPACE_KEY,
|
|
210
|
-
}), this.options
|
|
207
|
+
}), this.options);
|
|
211
208
|
}
|
|
212
209
|
break;
|
|
213
210
|
case 'deleteContentForward':
|
|
@@ -215,7 +212,7 @@ var EditPlugin = /** @class */ (function () {
|
|
|
215
212
|
key: 'Delete',
|
|
216
213
|
keyCode: DELETE_KEY,
|
|
217
214
|
which: DELETE_KEY,
|
|
218
|
-
}), this.options
|
|
215
|
+
}), this.options);
|
|
219
216
|
break;
|
|
220
217
|
}
|
|
221
218
|
if (handled) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditPlugin.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/EditPlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { keyboardDelete } from './keyboardDelete';\nimport { keyboardEnter } from './keyboardEnter';\nimport { keyboardInput } from './keyboardInput';\nimport { keyboardTab } from './keyboardTab';\nimport { parseTableCells } from 'roosterjs-content-model-dom';\nimport type {\n DOMSelection,\n EditorPlugin,\n IEditor,\n KeyDownEvent,\n PluginEvent,\n} from 'roosterjs-content-model-types';\n\n/**\n * Options to customize the keyboard handling behavior of Edit plugin\n */\nexport type EditOptions = {\n /**\n * Whether to handle Tab key in keyboard. @default true\n */\n handleTabKey?: boolean;\n\n /**\n * Whether expanded selection within a text node should be handled by CM when pressing Backspace/Delete key.\n * @default true\n */\n handleExpandedSelectionOnDelete?: boolean;\n\n /**\n * Callback function to determine whether the Rooster should handle the Enter key press.\n * If the function returns true, the Rooster will handle the Enter key press instead of the browser.\n * @param editor - The editor instance.\n * @returns A boolean\n */\n shouldHandleEnterKey?: ((editor: IEditor) => boolean) | boolean;\n\n /**\n * Callback or boolean to determine whether the browser (not Content Model) should handle the Backspace key press.\n * If the value/callback returns true, Rooster will NOT handle Backspace and will defer to the browser's native behavior.\n * @param editor - The editor instance (when using callback).\n * @returns A boolean\n */\n shouldHandleBackspaceKey?: ((editor: IEditor) => boolean) | boolean;\n};\n\nconst BACKSPACE_KEY = 8;\nconst DELETE_KEY = 46;\n/**\n * According to https://lists.w3.org/Archives/Public/www-dom/2010JulSep/att-0182/keyCode-spec.html\n * 229 can be sent in variants generated when Long press (iOS) or using IM.\n *\n * Other cases: https://stackoverflow.com/questions/25043934/is-it-ok-to-ignore-keydown-events-with-keycode-229\n */\nconst DEAD_KEY = 229;\n\nconst DefaultOptions: Partial<EditOptions> = {\n handleTabKey: true,\n handleExpandedSelectionOnDelete: true,\n};\n\n/**\n * Edit plugins helps editor to do editing operation on top of content model.\n * This includes:\n * 1. Delete Key\n * 2. Backspace Key\n * 3. Tab Key\n */\nexport class EditPlugin implements EditorPlugin {\n private editor: IEditor | null = null;\n private disposer: (() => void) | null = null;\n private shouldHandleNextInputEvent = false;\n private selectionAfterDelete: DOMSelection | null = null;\n private handleNormalEnter: (editor: IEditor) => boolean = (editor: IEditor) => false;\n\n /**\n * @param options An optional parameter that takes in an object of type EditOptions, which includes the following properties:\n * handleTabKey: A boolean that enables or disables Tab key handling. Defaults to true.\n */\n constructor(private options: EditOptions = DefaultOptions) {\n this.options = { ...DefaultOptions, ...options };\n }\n\n private createNormalEnterChecker(result: boolean) {\n return result ? () => true : () => false;\n }\n\n private getHandleNormalEnter(editor: IEditor) {\n switch (typeof this.options.shouldHandleEnterKey) {\n case 'function':\n return this.options.shouldHandleEnterKey;\n break;\n case 'boolean':\n return this.createNormalEnterChecker(this.options.shouldHandleEnterKey);\n break;\n default:\n return this.createNormalEnterChecker(\n editor.isExperimentalFeatureEnabled('HandleEnterKey')\n );\n break;\n }\n }\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'Edit';\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 this.handleNormalEnter = this.getHandleNormalEnter(editor);\n\n if (editor.getEnvironment().isAndroid) {\n this.disposer = this.editor.attachDomEvent({\n beforeinput: {\n beforeDispatch: e => this.handleBeforeInputEvent(editor, e),\n },\n });\n }\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 this.disposer?.();\n this.disposer = 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 switch (event.eventType) {\n case 'keyDown':\n this.handleKeyDownEvent(this.editor, event);\n break;\n case 'keyUp':\n if (this.selectionAfterDelete) {\n this.editor.setDOMSelection(this.selectionAfterDelete);\n this.selectionAfterDelete = null;\n }\n break;\n }\n }\n }\n\n /**\n * Check if the plugin should handle the given event exclusively.\n * Handle an event exclusively means other plugin will not receive this event in\n * onPluginEvent method.\n * If two plugins will return true in willHandleEventExclusively() for the same event,\n * the final result depends on the order of the plugins are added into editor\n * @param event The event to check:\n */\n willHandleEventExclusively(event: PluginEvent) {\n if (\n this.editor &&\n this.options.handleTabKey &&\n event.eventType == 'keyDown' &&\n event.rawEvent.key == 'Tab' &&\n !event.rawEvent.shiftKey\n ) {\n const selection = this.editor.getDOMSelection();\n const startContainer =\n selection?.type == 'range' ? selection.range.startContainer : null;\n const table = startContainer\n ? this.editor.getDOMHelper().findClosestElementAncestor(startContainer, 'table')\n : null;\n const parsedTable = table && parseTableCells(table);\n\n if (parsedTable) {\n const lastRow = parsedTable[parsedTable.length - 1];\n const lastCell = lastRow && lastRow[lastRow.length - 1];\n\n if (typeof lastCell == 'object' && lastCell.contains(startContainer)) {\n // When TAB in the last cell of a table, we will generate new table row, so prevent other plugins handling this event\n // e.g. SelectionPlugin will move the focus out of table, which is conflict with this behavior\n return true;\n }\n }\n }\n\n return false;\n }\n\n private handleKeyDownEvent(editor: IEditor, event: KeyDownEvent) {\n const rawEvent = event.rawEvent;\n const hasCtrlOrMetaKey = rawEvent.ctrlKey || rawEvent.metaKey;\n\n if (!rawEvent.defaultPrevented && !event.handledByEditFeature) {\n switch (rawEvent.key) {\n case 'Backspace':\n // Use our API to handle BACKSPACE/DELETE key.\n // No need to clear cache here since if we rely on browser's behavior, there will be Input event and its handler will reconcile cache\n if (!this.shouldBrowserHandleBackspace(editor)) {\n keyboardDelete(\n editor,\n rawEvent,\n this.options.handleExpandedSelectionOnDelete\n );\n }\n break;\n\n case 'Delete':\n // Use our API to handle BACKSPACE/DELETE key.\n // No need to clear cache here since if we rely on browser's behavior, there will be Input event and its handler will reconcile cache\n // And leave it to browser when shift key is pressed so that browser will trigger cut event\n if (!event.rawEvent.shiftKey) {\n keyboardDelete(\n editor,\n rawEvent,\n this.options.handleExpandedSelectionOnDelete\n );\n }\n break;\n\n case 'Tab':\n if (this.options.handleTabKey && !hasCtrlOrMetaKey) {\n keyboardTab(editor, rawEvent);\n }\n break;\n case 'Unidentified':\n if (editor.getEnvironment().isAndroid) {\n this.shouldHandleNextInputEvent = true;\n }\n break;\n\n case 'Enter':\n if (\n !hasCtrlOrMetaKey &&\n !event.rawEvent.isComposing &&\n event.rawEvent.keyCode !== DEAD_KEY\n ) {\n keyboardEnter(editor, rawEvent, this.handleNormalEnter(editor));\n }\n break;\n\n default:\n keyboardInput(editor, rawEvent);\n break;\n }\n }\n }\n\n private handleBeforeInputEvent(editor: IEditor, rawEvent: Event) {\n // Some Android IMEs doesn't fire correct keydown event for BACKSPACE/DELETE key\n // Here we translate input event to BACKSPACE/DELETE keydown event to be compatible with existing logic\n if (\n !this.shouldHandleNextInputEvent ||\n !(rawEvent instanceof InputEvent) ||\n rawEvent.defaultPrevented\n ) {\n return;\n }\n this.shouldHandleNextInputEvent = false;\n\n let handled = false;\n switch (rawEvent.inputType) {\n case 'deleteContentBackward':\n if (!this.shouldBrowserHandleBackspace(editor)) {\n // This logic is Android specific. It's because some Android keyboard doesn't support key and keycode, the value of them is always Unidentified, so we have to manually create a new one.\n handled = keyboardDelete(\n editor,\n new KeyboardEvent('keydown', {\n key: 'Backspace',\n keyCode: BACKSPACE_KEY,\n which: BACKSPACE_KEY,\n }),\n this.options.handleExpandedSelectionOnDelete\n );\n }\n break;\n case 'deleteContentForward':\n handled = keyboardDelete(\n editor,\n new KeyboardEvent('keydown', {\n key: 'Delete',\n keyCode: DELETE_KEY,\n which: DELETE_KEY,\n }),\n this.options.handleExpandedSelectionOnDelete\n );\n break;\n }\n\n if (handled) {\n rawEvent.preventDefault();\n\n // Restore the selection on keyup event to avoid the cursor jump issue\n // See: https://issues.chromium.org/issues/330596261\n this.selectionAfterDelete = editor.getDOMSelection();\n }\n }\n\n private shouldBrowserHandleBackspace(editor: IEditor): boolean {\n const opt = this.options.shouldHandleBackspaceKey;\n switch (typeof opt) {\n case 'function':\n return opt(editor);\n case 'boolean':\n return opt;\n default:\n return false;\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"EditPlugin.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/EditPlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { keyboardDelete } from './keyboardDelete';\nimport { keyboardEnter } from './keyboardEnter';\nimport { keyboardInput } from './keyboardInput';\nimport { keyboardTab } from './keyboardTab';\nimport { parseTableCells } from 'roosterjs-content-model-dom';\nimport type { EditOptions } from './EditOptions';\nimport type {\n DOMSelection,\n EditorPlugin,\n IEditor,\n KeyDownEvent,\n PluginEvent,\n} from 'roosterjs-content-model-types';\n\nconst BACKSPACE_KEY = 8;\nconst DELETE_KEY = 46;\n/**\n * According to https://lists.w3.org/Archives/Public/www-dom/2010JulSep/att-0182/keyCode-spec.html\n * 229 can be sent in variants generated when Long press (iOS) or using IM.\n *\n * Other cases: https://stackoverflow.com/questions/25043934/is-it-ok-to-ignore-keydown-events-with-keycode-229\n */\nconst DEAD_KEY = 229;\n\nconst DefaultOptions: Partial<EditOptions> = {\n handleTabKey: true,\n handleExpandedSelectionOnDelete: true,\n};\n\n/**\n * Edit plugins helps editor to do editing operation on top of content model.\n * This includes:\n * 1. Delete Key\n * 2. Backspace Key\n * 3. Tab Key\n */\nexport class EditPlugin implements EditorPlugin {\n private editor: IEditor | null = null;\n private disposer: (() => void) | null = null;\n private shouldHandleNextInputEvent = false;\n private selectionAfterDelete: DOMSelection | null = null;\n private handleNormalEnter: (editor: IEditor) => boolean = () => false;\n\n /**\n * @param options An optional parameter that takes in an object of type EditOptions, which includes the following properties:\n * handleTabKey: A boolean that enables or disables Tab key handling. Defaults to true.\n */\n constructor(private options: EditOptions = DefaultOptions) {\n this.options = { ...DefaultOptions, ...options };\n }\n\n private createNormalEnterChecker(result: boolean) {\n return result ? () => true : () => false;\n }\n\n private getHandleNormalEnter(editor: IEditor) {\n switch (typeof this.options.shouldHandleEnterKey) {\n case 'function':\n return this.options.shouldHandleEnterKey;\n case 'boolean':\n return this.createNormalEnterChecker(this.options.shouldHandleEnterKey);\n default:\n return this.createNormalEnterChecker(\n editor.isExperimentalFeatureEnabled('HandleEnterKey')\n );\n }\n }\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'Edit';\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 this.handleNormalEnter = this.getHandleNormalEnter(editor);\n\n if (editor.getEnvironment().isAndroid) {\n this.disposer = this.editor.attachDomEvent({\n beforeinput: {\n beforeDispatch: e => this.handleBeforeInputEvent(editor, e),\n },\n });\n }\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 this.disposer?.();\n this.disposer = 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 switch (event.eventType) {\n case 'keyDown':\n this.handleKeyDownEvent(this.editor, event);\n break;\n case 'keyUp':\n if (this.selectionAfterDelete) {\n this.editor.setDOMSelection(this.selectionAfterDelete);\n this.selectionAfterDelete = null;\n }\n break;\n }\n }\n }\n\n /**\n * Check if the plugin should handle the given event exclusively.\n * Handle an event exclusively means other plugin will not receive this event in\n * onPluginEvent method.\n * If two plugins will return true in willHandleEventExclusively() for the same event,\n * the final result depends on the order of the plugins are added into editor\n * @param event The event to check:\n */\n willHandleEventExclusively(event: PluginEvent) {\n if (\n this.editor &&\n this.options.handleTabKey &&\n event.eventType == 'keyDown' &&\n event.rawEvent.key == 'Tab' &&\n !event.rawEvent.shiftKey\n ) {\n const selection = this.editor.getDOMSelection();\n const startContainer =\n selection?.type == 'range' ? selection.range.startContainer : null;\n const table = startContainer\n ? this.editor.getDOMHelper().findClosestElementAncestor(startContainer, 'table')\n : null;\n const parsedTable = table && parseTableCells(table);\n\n if (parsedTable) {\n const lastRow = parsedTable[parsedTable.length - 1];\n const lastCell = lastRow && lastRow[lastRow.length - 1];\n\n if (typeof lastCell == 'object' && lastCell.contains(startContainer)) {\n // When TAB in the last cell of a table, we will generate new table row, so prevent other plugins handling this event\n // e.g. SelectionPlugin will move the focus out of table, which is conflict with this behavior\n return true;\n }\n }\n }\n\n return false;\n }\n\n private handleKeyDownEvent(editor: IEditor, event: KeyDownEvent) {\n const rawEvent = event.rawEvent;\n const hasCtrlOrMetaKey = rawEvent.ctrlKey || rawEvent.metaKey;\n\n if (!rawEvent.defaultPrevented && !event.handledByEditFeature) {\n switch (rawEvent.key) {\n case 'Backspace':\n // Use our API to handle BACKSPACE/DELETE key.\n // No need to clear cache here since if we rely on browser's behavior, there will be Input event and its handler will reconcile cache\n if (!this.shouldBrowserHandleBackspace(editor)) {\n keyboardDelete(editor, rawEvent, this.options);\n }\n break;\n\n case 'Delete':\n // Use our API to handle BACKSPACE/DELETE key.\n // No need to clear cache here since if we rely on browser's behavior, there will be Input event and its handler will reconcile cache\n // And leave it to browser when shift key is pressed so that browser will trigger cut event\n if (!event.rawEvent.shiftKey) {\n keyboardDelete(editor, rawEvent, this.options);\n }\n break;\n\n case 'Tab':\n if (this.options.handleTabKey && !hasCtrlOrMetaKey) {\n keyboardTab(editor, rawEvent);\n }\n break;\n case 'Unidentified':\n if (editor.getEnvironment().isAndroid) {\n this.shouldHandleNextInputEvent = true;\n }\n break;\n\n case 'Enter':\n if (\n !hasCtrlOrMetaKey &&\n !event.rawEvent.isComposing &&\n event.rawEvent.keyCode !== DEAD_KEY\n ) {\n keyboardEnter(\n editor,\n rawEvent,\n this.handleNormalEnter(editor),\n this.options.formatsToPreserveOnMerge\n );\n }\n break;\n\n default:\n keyboardInput(editor, rawEvent);\n break;\n }\n }\n }\n\n private handleBeforeInputEvent(editor: IEditor, rawEvent: Event) {\n // Some Android IMEs doesn't fire correct keydown event for BACKSPACE/DELETE key\n // Here we translate input event to BACKSPACE/DELETE keydown event to be compatible with existing logic\n if (\n !this.shouldHandleNextInputEvent ||\n !(rawEvent instanceof InputEvent) ||\n rawEvent.defaultPrevented\n ) {\n return;\n }\n this.shouldHandleNextInputEvent = false;\n\n let handled = false;\n switch (rawEvent.inputType) {\n case 'deleteContentBackward':\n if (!this.shouldBrowserHandleBackspace(editor)) {\n // This logic is Android specific. It's because some Android keyboard doesn't support key and keycode, the value of them is always Unidentified, so we have to manually create a new one.\n handled = keyboardDelete(\n editor,\n new KeyboardEvent('keydown', {\n key: 'Backspace',\n keyCode: BACKSPACE_KEY,\n which: BACKSPACE_KEY,\n }),\n this.options\n );\n }\n break;\n case 'deleteContentForward':\n handled = keyboardDelete(\n editor,\n new KeyboardEvent('keydown', {\n key: 'Delete',\n keyCode: DELETE_KEY,\n which: DELETE_KEY,\n }),\n this.options\n );\n break;\n }\n\n if (handled) {\n rawEvent.preventDefault();\n\n // Restore the selection on keyup event to avoid the cursor jump issue\n // See: https://issues.chromium.org/issues/330596261\n this.selectionAfterDelete = editor.getDOMSelection();\n }\n }\n\n private shouldBrowserHandleBackspace(editor: IEditor): boolean {\n const opt = this.options.shouldHandleBackspaceKey;\n switch (typeof opt) {\n case 'function':\n return opt(editor);\n case 'boolean':\n return opt;\n default:\n return false;\n }\n }\n}\n"]}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { DeleteSelectionStep } from 'roosterjs-content-model-types';
|
|
2
|
+
import type { EditOptions } from '../EditOptions';
|
|
2
3
|
/**
|
|
3
|
-
* @internal
|
|
4
|
+
* @internal
|
|
5
|
+
* Get a delete step for collapsed selection at specified direction
|
|
6
|
+
* @param direction The direction to delete
|
|
7
|
+
* @param options Options for the delete operation
|
|
8
|
+
* @returns A delete step
|
|
4
9
|
*/
|
|
5
|
-
export declare
|
|
6
|
-
/**
|
|
7
|
-
* @internal if we didn't delete anything, and we want to delete backward, now perform it
|
|
8
|
-
*/
|
|
9
|
-
export declare const backwardDeleteCollapsedSelection: DeleteSelectionStep;
|
|
10
|
+
export declare function getDeleteCollapsedSelection(direction: 'forward' | 'backward', options: EditOptions): DeleteSelectionStep;
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.getDeleteCollapsedSelection = void 0;
|
|
4
4
|
var getLeafSiblingBlock_1 = require("../utils/getLeafSiblingBlock");
|
|
5
|
+
var preserveParagraphFormat_1 = require("../utils/preserveParagraphFormat");
|
|
5
6
|
var roosterjs_content_model_api_1 = require("roosterjs-content-model-api");
|
|
6
7
|
var roosterjs_content_model_dom_1 = require("roosterjs-content-model-dom");
|
|
7
|
-
|
|
8
|
+
/**
|
|
9
|
+
* @internal
|
|
10
|
+
* Get a delete step for collapsed selection at specified direction
|
|
11
|
+
* @param direction The direction to delete
|
|
12
|
+
* @param options Options for the delete operation
|
|
13
|
+
* @returns A delete step
|
|
14
|
+
*/
|
|
15
|
+
function getDeleteCollapsedSelection(direction, options) {
|
|
8
16
|
return function (context) {
|
|
9
17
|
var _a;
|
|
10
18
|
if (context.deleteResult != 'notDeleted') {
|
|
@@ -57,6 +65,7 @@ function getDeleteCollapsedSelection(direction) {
|
|
|
57
65
|
};
|
|
58
66
|
context.lastParagraph = paragraph;
|
|
59
67
|
}
|
|
68
|
+
(0, preserveParagraphFormat_1.preserveParagraphFormat)(options.formatsToPreserveOnMerge, context.insertPoint.paragraph, context.lastParagraph);
|
|
60
69
|
context.deleteResult = 'range';
|
|
61
70
|
}
|
|
62
71
|
// When go across table, getLeafSiblingBlock will return null, when we are here, we must be in the same table context
|
|
@@ -76,6 +85,7 @@ function getDeleteCollapsedSelection(direction) {
|
|
|
76
85
|
}
|
|
77
86
|
};
|
|
78
87
|
}
|
|
88
|
+
exports.getDeleteCollapsedSelection = getDeleteCollapsedSelection;
|
|
79
89
|
function getRoot(path) {
|
|
80
90
|
var lastInPath = path[path.length - 1];
|
|
81
91
|
return lastInPath.blockGroupType == 'Document' ? lastInPath : null;
|
|
@@ -102,12 +112,4 @@ function fixupBr(paragraph) {
|
|
|
102
112
|
}
|
|
103
113
|
}
|
|
104
114
|
}
|
|
105
|
-
/**
|
|
106
|
-
* @internal if we didn't delete anything, and we want to delete forward, now perform it
|
|
107
|
-
*/
|
|
108
|
-
exports.forwardDeleteCollapsedSelection = getDeleteCollapsedSelection('forward');
|
|
109
|
-
/**
|
|
110
|
-
* @internal if we didn't delete anything, and we want to delete backward, now perform it
|
|
111
|
-
*/
|
|
112
|
-
exports.backwardDeleteCollapsedSelection = getDeleteCollapsedSelection('backward');
|
|
113
115
|
//# sourceMappingURL=deleteCollapsedSelection.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deleteCollapsedSelection.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/edit/deleteSteps/deleteCollapsedSelection.ts"],"names":[],"mappings":"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","sourcesContent":["import { getLeafSiblingBlock } from '../utils/getLeafSiblingBlock';\nimport { setModelIndentation } from 'roosterjs-content-model-api';\nimport {\n deleteBlock,\n deleteSegment,\n getClosestAncestorBlockGroupIndex,\n mutateBlock,\n setParagraphNotImplicit,\n} from 'roosterjs-content-model-dom';\nimport type { ReadonlyBlockAndPath } from '../utils/getLeafSiblingBlock';\nimport type {\n DeleteSelectionStep,\n ReadonlyContentModelBlockGroup,\n ReadonlyContentModelDocument,\n ReadonlyContentModelParagraph,\n ReadonlyContentModelSegment,\n} from 'roosterjs-content-model-types';\n\nfunction getDeleteCollapsedSelection(direction: 'forward' | 'backward'): DeleteSelectionStep {\n return context => {\n if (context.deleteResult != 'notDeleted') {\n return;\n }\n\n const isForward = direction == 'forward';\n const { paragraph, marker, path, tableContext } = context.insertPoint;\n const segments = paragraph.segments;\n\n fixupBr(paragraph);\n\n const index = segments.indexOf(marker) + (isForward ? 1 : -1);\n const segmentToDelete = segments[index];\n let blockToDelete: ReadonlyBlockAndPath | null;\n let root: ReadonlyContentModelDocument | null;\n\n if (segmentToDelete) {\n if (deleteSegment(paragraph, segmentToDelete, context.formatContext, direction)) {\n context.deleteResult = 'singleChar';\n\n // It is possible that we have deleted everything from this paragraph, so we need to mark it as not implicit\n // to avoid losing its format. See https://github.com/microsoft/roosterjs/issues/1953\n setParagraphNotImplicit(paragraph);\n }\n } else if (\n shouldOutdentParagraph(isForward, segments, paragraph, path) &&\n (root = getRoot(path))\n ) {\n setModelIndentation(root, 'outdent');\n context.deleteResult = 'range';\n } else if ((blockToDelete = getLeafSiblingBlock(path, paragraph, isForward))) {\n const { block: readonlyBlock, path, siblingSegment } = blockToDelete;\n\n if (readonlyBlock.blockType == 'Paragraph') {\n const block = mutateBlock(readonlyBlock);\n\n if (siblingSegment) {\n // When selection is under general segment, need to check if it has a sibling sibling, and delete from it\n if (deleteSegment(block, siblingSegment, context.formatContext, direction)) {\n context.deleteResult = 'range';\n }\n } else {\n if (isForward) {\n context.lastParagraph = block;\n } else {\n if (block.segments[block.segments.length - 1]?.segmentType == 'Br') {\n mutateBlock(block).segments.pop();\n }\n\n context.insertPoint = {\n marker,\n paragraph: block,\n path,\n tableContext,\n };\n context.lastParagraph = paragraph;\n }\n\n context.deleteResult = 'range';\n }\n\n // When go across table, getLeafSiblingBlock will return null, when we are here, we must be in the same table context\n context.lastTableContext = tableContext;\n } else {\n if (\n deleteBlock(\n mutateBlock(path[0]).blocks,\n readonlyBlock,\n undefined /*replacement*/,\n context.formatContext,\n direction\n )\n ) {\n context.deleteResult = 'range';\n }\n }\n } else {\n // We have nothing to delete, in this case we don't want browser handle it as well.\n // Because when Backspace on an empty document, it will also delete the only DIV and SPAN element, causes\n // editor is really empty. We don't want that happen. So the handling should stop here.\n context.deleteResult = 'nothingToDelete';\n }\n };\n}\n\nfunction getRoot(path: ReadonlyContentModelBlockGroup[]): ReadonlyContentModelDocument | null {\n const lastInPath = path[path.length - 1];\n return lastInPath.blockGroupType == 'Document' ? lastInPath : null;\n}\n\nfunction shouldOutdentParagraph(\n isForward: boolean,\n segments: ReadonlyContentModelSegment[],\n paragraph: ReadonlyContentModelParagraph,\n path: ReadonlyContentModelBlockGroup[]\n) {\n return (\n !isForward &&\n segments.length == 1 &&\n segments[0].segmentType == 'SelectionMarker' &&\n paragraph.format.marginLeft &&\n parseInt(paragraph.format.marginLeft) &&\n getClosestAncestorBlockGroupIndex(path, ['Document', 'TableCell'], ['ListItem']) > -1\n );\n}\n\n/**\n * If the last segment is BR, remove it for now. We may add it back later when normalize model.\n * So that if this is an empty paragraph, it will start to delete next block\n */\nfunction fixupBr(paragraph: ReadonlyContentModelParagraph) {\n const { segments } = paragraph;\n\n if (segments[segments.length - 1]?.segmentType == 'Br') {\n const segmentsWithoutBr = segments.filter(x => x.segmentType != 'SelectionMarker');\n\n if (segmentsWithoutBr[segmentsWithoutBr.length - 2]?.segmentType != 'Br') {\n mutateBlock(paragraph).segments.pop();\n }\n }\n}\n\n/**\n * @internal if we didn't delete anything, and we want to delete forward, now perform it\n */\nexport const forwardDeleteCollapsedSelection = getDeleteCollapsedSelection('forward');\n\n/**\n * @internal if we didn't delete anything, and we want to delete backward, now perform it\n */\nexport const backwardDeleteCollapsedSelection = getDeleteCollapsedSelection('backward');\n"]}
|
|
1
|
+
{"version":3,"file":"deleteCollapsedSelection.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/edit/deleteSteps/deleteCollapsedSelection.ts"],"names":[],"mappings":"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","sourcesContent":["import { getLeafSiblingBlock } from '../utils/getLeafSiblingBlock';\nimport { preserveParagraphFormat } from '../utils/preserveParagraphFormat';\nimport { setModelIndentation } from 'roosterjs-content-model-api';\nimport {\n deleteBlock,\n deleteSegment,\n getClosestAncestorBlockGroupIndex,\n mutateBlock,\n setParagraphNotImplicit,\n} from 'roosterjs-content-model-dom';\nimport type { ReadonlyBlockAndPath } from '../utils/getLeafSiblingBlock';\nimport type {\n DeleteSelectionStep,\n ReadonlyContentModelBlockGroup,\n ReadonlyContentModelDocument,\n ReadonlyContentModelParagraph,\n ReadonlyContentModelSegment,\n} from 'roosterjs-content-model-types';\nimport type { EditOptions } from '../EditOptions';\n\n/**\n * @internal\n * Get a delete step for collapsed selection at specified direction\n * @param direction The direction to delete\n * @param options Options for the delete operation\n * @returns A delete step\n */\nexport function getDeleteCollapsedSelection(\n direction: 'forward' | 'backward',\n options: EditOptions\n): DeleteSelectionStep {\n return context => {\n if (context.deleteResult != 'notDeleted') {\n return;\n }\n\n const isForward = direction == 'forward';\n const { paragraph, marker, path, tableContext } = context.insertPoint;\n const segments = paragraph.segments;\n\n fixupBr(paragraph);\n\n const index = segments.indexOf(marker) + (isForward ? 1 : -1);\n const segmentToDelete = segments[index];\n let blockToDelete: ReadonlyBlockAndPath | null;\n let root: ReadonlyContentModelDocument | null;\n\n if (segmentToDelete) {\n if (deleteSegment(paragraph, segmentToDelete, context.formatContext, direction)) {\n context.deleteResult = 'singleChar';\n\n // It is possible that we have deleted everything from this paragraph, so we need to mark it as not implicit\n // to avoid losing its format. See https://github.com/microsoft/roosterjs/issues/1953\n setParagraphNotImplicit(paragraph);\n }\n } else if (\n shouldOutdentParagraph(isForward, segments, paragraph, path) &&\n (root = getRoot(path))\n ) {\n setModelIndentation(root, 'outdent');\n context.deleteResult = 'range';\n } else if ((blockToDelete = getLeafSiblingBlock(path, paragraph, isForward))) {\n const { block: readonlyBlock, path, siblingSegment } = blockToDelete;\n\n if (readonlyBlock.blockType == 'Paragraph') {\n const block = mutateBlock(readonlyBlock);\n\n if (siblingSegment) {\n // When selection is under general segment, need to check if it has a sibling sibling, and delete from it\n if (deleteSegment(block, siblingSegment, context.formatContext, direction)) {\n context.deleteResult = 'range';\n }\n } else {\n if (isForward) {\n context.lastParagraph = block;\n } else {\n if (block.segments[block.segments.length - 1]?.segmentType == 'Br') {\n mutateBlock(block).segments.pop();\n }\n\n context.insertPoint = {\n marker,\n paragraph: block,\n path,\n tableContext,\n };\n context.lastParagraph = paragraph;\n }\n\n preserveParagraphFormat(\n options.formatsToPreserveOnMerge,\n context.insertPoint.paragraph,\n context.lastParagraph\n );\n\n context.deleteResult = 'range';\n }\n\n // When go across table, getLeafSiblingBlock will return null, when we are here, we must be in the same table context\n context.lastTableContext = tableContext;\n } else {\n if (\n deleteBlock(\n mutateBlock(path[0]).blocks,\n readonlyBlock,\n undefined /*replacement*/,\n context.formatContext,\n direction\n )\n ) {\n context.deleteResult = 'range';\n }\n }\n } else {\n // We have nothing to delete, in this case we don't want browser handle it as well.\n // Because when Backspace on an empty document, it will also delete the only DIV and SPAN element, causes\n // editor is really empty. We don't want that happen. So the handling should stop here.\n context.deleteResult = 'nothingToDelete';\n }\n };\n}\n\nfunction getRoot(path: ReadonlyContentModelBlockGroup[]): ReadonlyContentModelDocument | null {\n const lastInPath = path[path.length - 1];\n return lastInPath.blockGroupType == 'Document' ? lastInPath : null;\n}\n\nfunction shouldOutdentParagraph(\n isForward: boolean,\n segments: ReadonlyContentModelSegment[],\n paragraph: ReadonlyContentModelParagraph,\n path: ReadonlyContentModelBlockGroup[]\n) {\n return (\n !isForward &&\n segments.length == 1 &&\n segments[0].segmentType == 'SelectionMarker' &&\n paragraph.format.marginLeft &&\n parseInt(paragraph.format.marginLeft) &&\n getClosestAncestorBlockGroupIndex(path, ['Document', 'TableCell'], ['ListItem']) > -1\n );\n}\n\n/**\n * If the last segment is BR, remove it for now. We may add it back later when normalize model.\n * So that if this is an empty paragraph, it will start to delete next block\n */\nfunction fixupBr(paragraph: ReadonlyContentModelParagraph) {\n const { segments } = paragraph;\n\n if (segments[segments.length - 1]?.segmentType == 'Br') {\n const segmentsWithoutBr = segments.filter(x => x.segmentType != 'SelectionMarker');\n\n if (segmentsWithoutBr[segmentsWithoutBr.length - 2]?.segmentType != 'Br') {\n mutateBlock(paragraph).segments.pop();\n }\n }\n}\n"]}
|
|
@@ -2,4 +2,4 @@ import type { DeleteSelectionStep } from 'roosterjs-content-model-types';
|
|
|
2
2
|
/**
|
|
3
3
|
* @internal
|
|
4
4
|
*/
|
|
5
|
-
export declare const handleEnterOnParagraph: DeleteSelectionStep;
|
|
5
|
+
export declare const handleEnterOnParagraph: (formatsToPreserveOnMerge: string[]) => DeleteSelectionStep;
|
|
@@ -6,17 +6,17 @@ var splitParagraph_1 = require("../utils/splitParagraph");
|
|
|
6
6
|
/**
|
|
7
7
|
* @internal
|
|
8
8
|
*/
|
|
9
|
-
var handleEnterOnParagraph = function (context) {
|
|
9
|
+
var handleEnterOnParagraph = function (formatsToPreserveOnMerge) { return function (context) {
|
|
10
10
|
var _a, _b;
|
|
11
11
|
var _c = context.insertPoint, paragraph = _c.paragraph, path = _c.path;
|
|
12
12
|
var paraIndex = (_b = (_a = path[0]) === null || _a === void 0 ? void 0 : _a.blocks.indexOf(paragraph)) !== null && _b !== void 0 ? _b : -1;
|
|
13
13
|
if (context.deleteResult == 'notDeleted' && paraIndex >= 0) {
|
|
14
|
-
var newPara = (0, splitParagraph_1.splitParagraph)(context.insertPoint, false /* removeImplicitParagraph
|
|
14
|
+
var newPara = (0, splitParagraph_1.splitParagraph)(context.insertPoint, false /* removeImplicitParagraph */, formatsToPreserveOnMerge);
|
|
15
15
|
(0, roosterjs_content_model_dom_1.mutateBlock)(path[0]).blocks.splice(paraIndex + 1, 0, newPara);
|
|
16
16
|
context.deleteResult = 'range';
|
|
17
17
|
context.lastParagraph = newPara;
|
|
18
18
|
context.insertPoint.paragraph = newPara;
|
|
19
19
|
}
|
|
20
|
-
};
|
|
20
|
+
}; };
|
|
21
21
|
exports.handleEnterOnParagraph = handleEnterOnParagraph;
|
|
22
22
|
//# sourceMappingURL=handleEnterOnParagraph.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handleEnterOnParagraph.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/edit/inputSteps/handleEnterOnParagraph.ts"],"names":[],"mappings":";;;AAAA,2EAA0D;AAC1D,0DAAyD;AAGzD;;GAEG;AACI,IAAM,sBAAsB,
|
|
1
|
+
{"version":3,"file":"handleEnterOnParagraph.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/edit/inputSteps/handleEnterOnParagraph.ts"],"names":[],"mappings":";;;AAAA,2EAA0D;AAC1D,0DAAyD;AAGzD;;GAEG;AACI,IAAM,sBAAsB,GAER,UAAA,wBAAwB,IAAI,OAAA,UAAA,OAAO;;IACpD,IAAA,KAAsB,OAAO,CAAC,WAAW,EAAvC,SAAS,eAAA,EAAE,IAAI,UAAwB,CAAC;IAChD,IAAM,SAAS,GAAG,MAAA,MAAA,IAAI,CAAC,CAAC,CAAC,0CAAE,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,mCAAI,CAAC,CAAC,CAAC;IAE3D,IAAI,OAAO,CAAC,YAAY,IAAI,YAAY,IAAI,SAAS,IAAI,CAAC,EAAE;QACxD,IAAM,OAAO,GAAG,IAAA,+BAAc,EAC1B,OAAO,CAAC,WAAW,EACnB,KAAK,CAAC,6BAA6B,EACnC,wBAAwB,CAC3B,CAAC;QAEF,IAAA,yCAAW,EAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;QAE9D,OAAO,CAAC,YAAY,GAAG,OAAO,CAAC;QAC/B,OAAO,CAAC,aAAa,GAAG,OAAO,CAAC;QAChC,OAAO,CAAC,WAAW,CAAC,SAAS,GAAG,OAAO,CAAC;KAC3C;AACL,CAAC,EAjBsD,CAiBtD,CAAC;AAnBW,QAAA,sBAAsB,0BAmBjC","sourcesContent":["import { mutateBlock } from 'roosterjs-content-model-dom';\nimport { splitParagraph } from '../utils/splitParagraph';\nimport type { DeleteSelectionStep } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport const handleEnterOnParagraph: (\n formatsToPreserveOnMerge: string[]\n) => DeleteSelectionStep = formatsToPreserveOnMerge => context => {\n const { paragraph, path } = context.insertPoint;\n const paraIndex = path[0]?.blocks.indexOf(paragraph) ?? -1;\n\n if (context.deleteResult == 'notDeleted' && paraIndex >= 0) {\n const newPara = splitParagraph(\n context.insertPoint,\n false /* removeImplicitParagraph */,\n formatsToPreserveOnMerge\n );\n\n mutateBlock(path[0]).blocks.splice(paraIndex + 1, 0, newPara);\n\n context.deleteResult = 'range';\n context.lastParagraph = newPara;\n context.insertPoint.paragraph = newPara;\n }\n};\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { IEditor } from 'roosterjs-content-model-types';
|
|
2
|
+
import type { EditOptions } from './EditOptions';
|
|
2
3
|
/**
|
|
3
4
|
* @internal
|
|
4
5
|
* Do keyboard event handling for DELETE/BACKSPACE key
|
|
@@ -7,4 +8,4 @@ import type { IEditor } from 'roosterjs-content-model-types';
|
|
|
7
8
|
* @param handleExpandedSelection Whether to handle expanded selection within a text node by CM
|
|
8
9
|
* @returns True if the event is handled by content model, otherwise false
|
|
9
10
|
*/
|
|
10
|
-
export declare function keyboardDelete(editor: IEditor, rawEvent: KeyboardEvent,
|
|
11
|
+
export declare function keyboardDelete(editor: IEditor, rawEvent: KeyboardEvent, options: EditOptions): boolean;
|
|
@@ -5,10 +5,10 @@ var deleteAllSegmentBefore_1 = require("./deleteSteps/deleteAllSegmentBefore");
|
|
|
5
5
|
var deleteEmptyQuote_1 = require("./deleteSteps/deleteEmptyQuote");
|
|
6
6
|
var deleteList_1 = require("./deleteSteps/deleteList");
|
|
7
7
|
var deleteParagraphStyle_1 = require("./deleteSteps/deleteParagraphStyle");
|
|
8
|
+
var deleteCollapsedSelection_1 = require("./deleteSteps/deleteCollapsedSelection");
|
|
8
9
|
var roosterjs_content_model_dom_1 = require("roosterjs-content-model-dom");
|
|
9
10
|
var handleKeyboardEventCommon_1 = require("./handleKeyboardEventCommon");
|
|
10
11
|
var deleteWordSelection_1 = require("./deleteSteps/deleteWordSelection");
|
|
11
|
-
var deleteCollapsedSelection_1 = require("./deleteSteps/deleteCollapsedSelection");
|
|
12
12
|
/**
|
|
13
13
|
* @internal
|
|
14
14
|
* Do keyboard event handling for DELETE/BACKSPACE key
|
|
@@ -17,13 +17,13 @@ var deleteCollapsedSelection_1 = require("./deleteSteps/deleteCollapsedSelection
|
|
|
17
17
|
* @param handleExpandedSelection Whether to handle expanded selection within a text node by CM
|
|
18
18
|
* @returns True if the event is handled by content model, otherwise false
|
|
19
19
|
*/
|
|
20
|
-
function keyboardDelete(editor, rawEvent,
|
|
21
|
-
if (handleExpandedSelection === void 0) { handleExpandedSelection = true; }
|
|
20
|
+
function keyboardDelete(editor, rawEvent, options) {
|
|
22
21
|
var handled = false;
|
|
23
22
|
var selection = editor.getDOMSelection();
|
|
24
|
-
|
|
23
|
+
var handleExpandedSelectionOnDelete = options.handleExpandedSelectionOnDelete;
|
|
24
|
+
if (shouldDeleteWithContentModel(selection, rawEvent, !!handleExpandedSelectionOnDelete)) {
|
|
25
25
|
editor.formatContentModel(function (model, context) {
|
|
26
|
-
var result = (0, roosterjs_content_model_dom_1.deleteSelection)(model, getDeleteSteps(rawEvent, !!editor.getEnvironment().isMac), context).deleteResult;
|
|
26
|
+
var result = (0, roosterjs_content_model_dom_1.deleteSelection)(model, getDeleteSteps(rawEvent, !!editor.getEnvironment().isMac, options), context).deleteResult;
|
|
27
27
|
handled = (0, handleKeyboardEventCommon_1.handleKeyboardEventResult)(editor, model, rawEvent, result, context);
|
|
28
28
|
return handled;
|
|
29
29
|
}, {
|
|
@@ -37,7 +37,7 @@ function keyboardDelete(editor, rawEvent, handleExpandedSelection) {
|
|
|
37
37
|
return handled;
|
|
38
38
|
}
|
|
39
39
|
exports.keyboardDelete = keyboardDelete;
|
|
40
|
-
function getDeleteSteps(rawEvent, isMac) {
|
|
40
|
+
function getDeleteSteps(rawEvent, isMac, options) {
|
|
41
41
|
var isForward = rawEvent.key == 'Delete';
|
|
42
42
|
var deleteAllSegmentBeforeStep = (0, handleKeyboardEventCommon_1.shouldDeleteAllSegmentsBefore)(rawEvent) && !isForward ? deleteAllSegmentBefore_1.deleteAllSegmentBefore : null;
|
|
43
43
|
var deleteWordSelection = (0, handleKeyboardEventCommon_1.shouldDeleteWord)(rawEvent, isMac)
|
|
@@ -45,9 +45,7 @@ function getDeleteSteps(rawEvent, isMac) {
|
|
|
45
45
|
? deleteWordSelection_1.forwardDeleteWordSelection
|
|
46
46
|
: deleteWordSelection_1.backwardDeleteWordSelection
|
|
47
47
|
: null;
|
|
48
|
-
var deleteCollapsedSelection = isForward
|
|
49
|
-
? deleteCollapsedSelection_1.forwardDeleteCollapsedSelection
|
|
50
|
-
: deleteCollapsedSelection_1.backwardDeleteCollapsedSelection;
|
|
48
|
+
var deleteCollapsedSelection = (0, deleteCollapsedSelection_1.getDeleteCollapsedSelection)(isForward ? 'forward' : 'backward', options);
|
|
51
49
|
var deleteQuote = !isForward ? deleteEmptyQuote_1.deleteEmptyQuote : null;
|
|
52
50
|
return [
|
|
53
51
|
deleteAllSegmentBeforeStep,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyboardDelete.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/keyboardDelete.ts"],"names":[],"mappings":";;;AAAA,+EAA8E;AAC9E,mEAAkE;AAClE,uDAAsD;AACtD,2EAA0E;AAC1E,2EAOqC;AACrC,yEAIqC;AACrC,yEAG2C;
|
|
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 { deleteParagraphStyle } from './deleteSteps/deleteParagraphStyle';\nimport { getDeleteCollapsedSelection } from './deleteSteps/deleteCollapsedSelection';\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 type { DOMSelection, DeleteSelectionStep, IEditor } from 'roosterjs-content-model-types';\nimport type { EditOptions } from './EditOptions';\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(editor: IEditor, rawEvent: KeyboardEvent, options: EditOptions) {\n let handled = false;\n const selection = editor.getDOMSelection();\n const { handleExpandedSelectionOnDelete } = options;\n\n if (shouldDeleteWithContentModel(selection, rawEvent, !!handleExpandedSelectionOnDelete)) {\n editor.formatContentModel(\n (model, context) => {\n const result = deleteSelection(\n model,\n getDeleteSteps(rawEvent, !!editor.getEnvironment().isMac, options),\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(\n rawEvent: KeyboardEvent,\n isMac: boolean,\n options: EditOptions\n): (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\n const deleteCollapsedSelection = getDeleteCollapsedSelection(\n isForward ? 'forward' : 'backward',\n options\n );\n\n const deleteQuote = !isForward ? deleteEmptyQuote : null;\n return [\n deleteAllSegmentBeforeStep,\n deleteWordSelection,\n isForward ? null : deleteList,\n deleteCollapsedSelection,\n deleteQuote,\n deleteParagraphStyle,\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"]}
|
|
@@ -2,4 +2,4 @@ import type { IEditor } from 'roosterjs-content-model-types';
|
|
|
2
2
|
/**
|
|
3
3
|
* @internal
|
|
4
4
|
*/
|
|
5
|
-
export declare function keyboardEnter(editor: IEditor, rawEvent: KeyboardEvent, handleNormalEnter: boolean): void;
|
|
5
|
+
export declare function keyboardEnter(editor: IEditor, rawEvent: KeyboardEvent, handleNormalEnter: boolean, formatsToPreserveOnMerge?: string[]): void;
|
|
@@ -9,7 +9,8 @@ var roosterjs_content_model_dom_1 = require("roosterjs-content-model-dom");
|
|
|
9
9
|
/**
|
|
10
10
|
* @internal
|
|
11
11
|
*/
|
|
12
|
-
function keyboardEnter(editor, rawEvent, handleNormalEnter) {
|
|
12
|
+
function keyboardEnter(editor, rawEvent, handleNormalEnter, formatsToPreserveOnMerge) {
|
|
13
|
+
if (formatsToPreserveOnMerge === void 0) { formatsToPreserveOnMerge = []; }
|
|
13
14
|
var selection = editor.getDOMSelection();
|
|
14
15
|
editor.formatContentModel(function (model, context) {
|
|
15
16
|
var _a, _b;
|
|
@@ -24,7 +25,7 @@ function keyboardEnter(editor, rawEvent, handleNormalEnter) {
|
|
|
24
25
|
? []
|
|
25
26
|
: [handleAutoLink_1.handleAutoLink, handleEnterOnList_1.handleEnterOnList, deleteEmptyQuote_1.deleteEmptyQuote];
|
|
26
27
|
if (handleNormalEnter || handleEnterForEntity((_a = result.insertPoint) === null || _a === void 0 ? void 0 : _a.paragraph)) {
|
|
27
|
-
steps.push(handleEnterOnParagraph_1.handleEnterOnParagraph);
|
|
28
|
+
steps.push((0, handleEnterOnParagraph_1.handleEnterOnParagraph)(formatsToPreserveOnMerge));
|
|
28
29
|
}
|
|
29
30
|
(0, roosterjs_content_model_dom_1.runEditSteps)(steps, result);
|
|
30
31
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyboardEnter.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/keyboardEnter.ts"],"names":[],"mappings":";;;AAAA,mEAAkE;AAClE,8DAA6D;AAC7D,oEAAmE;AACnE,8EAA6E;AAC7E,2EAKqC;AAGrC;;GAEG;AACH,SAAgB,aAAa,CACzB,MAAe,EACf,QAAuB,EACvB,iBAA0B;
|
|
1
|
+
{"version":3,"file":"keyboardEnter.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/keyboardEnter.ts"],"names":[],"mappings":";;;AAAA,mEAAkE;AAClE,8DAA6D;AAC7D,oEAAmE;AACnE,8EAA6E;AAC7E,2EAKqC;AAGrC;;GAEG;AACH,SAAgB,aAAa,CACzB,MAAe,EACf,QAAuB,EACvB,iBAA0B,EAC1B,wBAAuC;IAAvC,yCAAA,EAAA,6BAAuC;IAEvC,IAAM,SAAS,GAAG,MAAM,CAAC,eAAe,EAAE,CAAC;IAE3C,MAAM,CAAC,kBAAkB,CACrB,UAAC,KAAK,EAAE,OAAO;;QACX,gEAAgE;QAChE,IAAM,MAAM,GAAG,IAAA,6CAAe,EAAC,KAAK,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;QAEnD,oBAAoB;QACpB,IAAI,SAAS,IAAI,SAAS,CAAC,IAAI,IAAI,OAAO,EAAE;YACxC,iIAAiI;YACjI,2CAA2C;YAC3C,MAAM,CAAC,YAAY,GAAG,YAAY,CAAC;YAEnC,IAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ;gBAC3B,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,CAAC,+BAAc,EAAE,qCAAiB,EAAE,mCAAgB,CAAC,CAAC;YAE5D,IAAI,iBAAiB,IAAI,oBAAoB,CAAC,MAAA,MAAM,CAAC,WAAW,0CAAE,SAAS,CAAC,EAAE;gBAC1E,KAAK,CAAC,IAAI,CAAC,IAAA,+CAAsB,EAAC,wBAAwB,CAAC,CAAC,CAAC;aAChE;YAED,IAAA,0CAAY,EAAC,KAAK,EAAE,MAAM,CAAC,CAAC;SAC/B;QAED,IAAI,MAAM,CAAC,YAAY,IAAI,OAAO,EAAE;YAChC,2HAA2H;YAC3H,OAAO,CAAC,gBAAgB,GAAG,MAAA,MAAM,CAAC,WAAW,0CAAE,MAAM,CAAC,MAAM,CAAC;YAE7D,IAAA,mDAAqB,EAAC,KAAK,CAAC,CAAC;YAE7B,QAAQ,CAAC,cAAc,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC;SACf;aAAM;YACH,OAAO,KAAK,CAAC;SAChB;IACL,CAAC,EACD;QACI,QAAQ,UAAA;QACR,mBAAmB,EAAE,IAAI;QACzB,YAAY,EAAE,0CAAY,CAAC,QAAQ;QACnC,aAAa,EAAE,cAAM,OAAA,QAAQ,CAAC,KAAK,EAAd,CAAc;QACnC,OAAO,EAAE,gBAAgB;KAC5B,CACJ,CAAC;AACN,CAAC;AAlDD,sCAkDC;AAED,SAAS,oBAAoB,CAAC,SAAoD;IAC9E,OAAO,CACH,SAAS;QACT,CAAC,SAAS,CAAC,UAAU,IAAI,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAA,CAAC,IAAI,OAAA,CAAC,CAAC,WAAW,IAAI,QAAQ,EAAzB,CAAyB,CAAC,CAAC,CACpF,CAAC;AACN,CAAC","sourcesContent":["import { deleteEmptyQuote } from './deleteSteps/deleteEmptyQuote';\nimport { handleAutoLink } from './inputSteps/handleAutoLink';\nimport { handleEnterOnList } from './inputSteps/handleEnterOnList';\nimport { handleEnterOnParagraph } from './inputSteps/handleEnterOnParagraph';\nimport {\n ChangeSource,\n deleteSelection,\n normalizeContentModel,\n runEditSteps,\n} from 'roosterjs-content-model-dom';\nimport type { IEditor, ReadonlyContentModelParagraph } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport function keyboardEnter(\n editor: IEditor,\n rawEvent: KeyboardEvent,\n handleNormalEnter: boolean,\n formatsToPreserveOnMerge: string[] = []\n) {\n const selection = editor.getDOMSelection();\n\n editor.formatContentModel(\n (model, context) => {\n // 1. delete the expanded selection if any, then merge paragraph\n const result = deleteSelection(model, [], context);\n\n // 2. Add line break\n if (selection && selection.type != 'table') {\n // For ENTER key, although we may have deleted something, since we still need to split the line, we always treat it as not delete\n // so further delete steps can keep working\n result.deleteResult = 'notDeleted';\n\n const steps = rawEvent.shiftKey\n ? []\n : [handleAutoLink, handleEnterOnList, deleteEmptyQuote];\n\n if (handleNormalEnter || handleEnterForEntity(result.insertPoint?.paragraph)) {\n steps.push(handleEnterOnParagraph(formatsToPreserveOnMerge));\n }\n\n runEditSteps(steps, result);\n }\n\n if (result.deleteResult == 'range') {\n // We have deleted something, next input should inherit the segment format from deleted content, so set pending format here\n context.newPendingFormat = result.insertPoint?.marker.format;\n\n normalizeContentModel(model);\n\n rawEvent.preventDefault();\n return true;\n } else {\n return false;\n }\n },\n {\n rawEvent,\n scrollCaretIntoView: true,\n changeSource: ChangeSource.Keyboard,\n getChangeData: () => rawEvent.which,\n apiName: 'handleEnterKey',\n }\n );\n}\n\nfunction handleEnterForEntity(paragraph: ReadonlyContentModelParagraph | undefined) {\n return (\n paragraph &&\n (paragraph.isImplicit || paragraph.segments.some(x => x.segmentType == 'Entity'))\n );\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ShallowMutableContentModelParagraph } from 'roosterjs-content-model-types';
|
|
2
|
+
/**
|
|
3
|
+
* @internal
|
|
4
|
+
* Preserve specific paragraph format properties from source paragraph to target paragraph
|
|
5
|
+
* @param formatsToPreserveOnMerge Array of format property names to preserve
|
|
6
|
+
* @param paragraph Source paragraph to copy format from
|
|
7
|
+
* @param newParagraph Target paragraph to copy format to
|
|
8
|
+
*/
|
|
9
|
+
export declare function preserveParagraphFormat(formatsToPreserveOnMerge: string[] | undefined, paragraph: ShallowMutableContentModelParagraph, newParagraph: ShallowMutableContentModelParagraph): void;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.preserveParagraphFormat = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* @internal
|
|
6
|
+
* Preserve specific paragraph format properties from source paragraph to target paragraph
|
|
7
|
+
* @param formatsToPreserveOnMerge Array of format property names to preserve
|
|
8
|
+
* @param paragraph Source paragraph to copy format from
|
|
9
|
+
* @param newParagraph Target paragraph to copy format to
|
|
10
|
+
*/
|
|
11
|
+
function preserveParagraphFormat(formatsToPreserveOnMerge, paragraph, newParagraph) {
|
|
12
|
+
if (formatsToPreserveOnMerge && formatsToPreserveOnMerge.length) {
|
|
13
|
+
var format_1 = paragraph.format;
|
|
14
|
+
var newFormat_1 = newParagraph.format;
|
|
15
|
+
formatsToPreserveOnMerge.forEach(function (key) {
|
|
16
|
+
var formatValue = format_1[key];
|
|
17
|
+
if (formatValue !== undefined) {
|
|
18
|
+
newFormat_1[key] = formatValue;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.preserveParagraphFormat = preserveParagraphFormat;
|
|
24
|
+
//# sourceMappingURL=preserveParagraphFormat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preserveParagraphFormat.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/edit/utils/preserveParagraphFormat.ts"],"names":[],"mappings":";;;AAEA;;;;;;GAMG;AACH,SAAgB,uBAAuB,CACnC,wBAA8C,EAC9C,SAA8C,EAC9C,YAAiD;IAEjD,IAAI,wBAAwB,IAAI,wBAAwB,CAAC,MAAM,EAAE;QAC7D,IAAM,QAAM,GAAG,SAAS,CAAC,MAAmC,CAAC;QAC7D,IAAM,WAAS,GAAG,YAAY,CAAC,MAAmC,CAAC;QACnE,wBAAwB,CAAC,OAAO,CAAC,UAAA,GAAG;YAChC,IAAM,WAAW,GAAG,QAAM,CAAC,GAAG,CAAC,CAAC;YAEhC,IAAI,WAAW,KAAK,SAAS,EAAE;gBAC3B,WAAS,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC;aAChC;QACL,CAAC,CAAC,CAAC;KACN;AACL,CAAC;AAhBD,0DAgBC","sourcesContent":["import type { ShallowMutableContentModelParagraph } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * Preserve specific paragraph format properties from source paragraph to target paragraph\n * @param formatsToPreserveOnMerge Array of format property names to preserve\n * @param paragraph Source paragraph to copy format from\n * @param newParagraph Target paragraph to copy format to\n */\nexport function preserveParagraphFormat(\n formatsToPreserveOnMerge: string[] | undefined,\n paragraph: ShallowMutableContentModelParagraph,\n newParagraph: ShallowMutableContentModelParagraph\n) {\n if (formatsToPreserveOnMerge && formatsToPreserveOnMerge.length) {\n const format = paragraph.format as { [key: string]: string };\n const newFormat = newParagraph.format as { [key: string]: string };\n formatsToPreserveOnMerge.forEach(key => {\n const formatValue = format[key];\n\n if (formatValue !== undefined) {\n newFormat[key] = formatValue;\n }\n });\n }\n}\n"]}
|