roosterjs-content-model-plugins 9.50.1 → 9.51.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 +1 -0
- package/lib/edit/EditOptions.js.map +1 -1
- package/lib/edit/EditPlugin.d.ts +0 -3
- package/lib/edit/EditPlugin.js +1 -16
- package/lib/edit/EditPlugin.js.map +1 -1
- package/lib/edit/keyboardEnter.d.ts +1 -1
- package/lib/edit/keyboardEnter.js +4 -10
- package/lib/edit/keyboardEnter.js.map +1 -1
- package/lib-amd/edit/EditOptions.d.ts +1 -0
- package/lib-amd/edit/EditOptions.js.map +1 -1
- package/lib-amd/edit/EditPlugin.d.ts +0 -3
- package/lib-amd/edit/EditPlugin.js +1 -16
- package/lib-amd/edit/EditPlugin.js.map +1 -1
- package/lib-amd/edit/keyboardEnter.d.ts +1 -1
- package/lib-amd/edit/keyboardEnter.js +4 -10
- package/lib-amd/edit/keyboardEnter.js.map +1 -1
- package/lib-mjs/edit/EditOptions.d.ts +1 -0
- package/lib-mjs/edit/EditOptions.js.map +1 -1
- package/lib-mjs/edit/EditPlugin.d.ts +0 -3
- package/lib-mjs/edit/EditPlugin.js +1 -16
- package/lib-mjs/edit/EditPlugin.js.map +1 -1
- package/lib-mjs/edit/keyboardEnter.d.ts +1 -1
- package/lib-mjs/edit/keyboardEnter.js +4 -10
- package/lib-mjs/edit/keyboardEnter.js.map +1 -1
- package/package.json +5 -5
|
@@ -46,6 +46,7 @@ export declare type EditOptions = {
|
|
|
46
46
|
*/
|
|
47
47
|
handleExpandedSelectionOnDelete?: boolean;
|
|
48
48
|
/**
|
|
49
|
+
* @deprecated This is always treated as true now
|
|
49
50
|
* Callback function to determine whether the Rooster should handle the Enter key press.
|
|
50
51
|
* If the function returns true, the Rooster will handle the Enter key press instead of the browser.
|
|
51
52
|
* @param editor - The editor instance.
|
|
@@ -1 +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 for handling Tab key in Edit plugin\n */\nexport interface HandleTabOptions {\n /**\n * Whether to indent/outdent multiple selected blocks when Tab/Shift+Tab is pressed and multiple blocks are selected.\n * @default true\n */\n indentMultipleBlocks?: boolean;\n\n /**\n * Whether to indent/outdent table cells when Tab key is pressed and a table is selected\n * @default true\n */\n indentTable?: boolean;\n\n /**\n * Whether to append a new row when Tab key is pressed in the last cell of a table\n * @default true\n */\n appendTableRow?: boolean;\n\n /**\n * Whether to indent/outdent list items when Tab key is pressed\n * @default true\n */\n indentList?: boolean;\n\n /**\n * Whether to indent/outdent paragraph when Tab key is pressed\n * @default true\n */\n indentParagraph?: boolean;\n}\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, or an object to control specific Tab key behaviors.\n * When true, all Tab features are enabled. When false, all are disabled.\n * When an object, individual features can be controlled via HandleTabOptions.\n * @default true\n */\n handleTabKey?: HandleTabOptions | 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"]}
|
|
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 for handling Tab key in Edit plugin\n */\nexport interface HandleTabOptions {\n /**\n * Whether to indent/outdent multiple selected blocks when Tab/Shift+Tab is pressed and multiple blocks are selected.\n * @default true\n */\n indentMultipleBlocks?: boolean;\n\n /**\n * Whether to indent/outdent table cells when Tab key is pressed and a table is selected\n * @default true\n */\n indentTable?: boolean;\n\n /**\n * Whether to append a new row when Tab key is pressed in the last cell of a table\n * @default true\n */\n appendTableRow?: boolean;\n\n /**\n * Whether to indent/outdent list items when Tab key is pressed\n * @default true\n */\n indentList?: boolean;\n\n /**\n * Whether to indent/outdent paragraph when Tab key is pressed\n * @default true\n */\n indentParagraph?: boolean;\n}\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, or an object to control specific Tab key behaviors.\n * When true, all Tab features are enabled. When false, all are disabled.\n * When an object, individual features can be controlled via HandleTabOptions.\n * @default true\n */\n handleTabKey?: HandleTabOptions | 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 * @deprecated This is always treated as true now\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
|
@@ -12,15 +12,12 @@ export declare class EditPlugin implements EditorPlugin {
|
|
|
12
12
|
private disposer;
|
|
13
13
|
private shouldHandleNextInputEvent;
|
|
14
14
|
private selectionAfterDelete;
|
|
15
|
-
private handleNormalEnter;
|
|
16
15
|
private options;
|
|
17
16
|
/**
|
|
18
17
|
* @param options An optional parameter that takes in an object of type EditOptions, which includes the following properties:
|
|
19
18
|
* handleTabKey: A boolean or HandleTabOptions object that controls Tab key handling. When a boolean, true enables all features and false disables all. When an object, individual features can be controlled. Defaults to all enabled.
|
|
20
19
|
*/
|
|
21
20
|
constructor(options?: EditOptions);
|
|
22
|
-
private createNormalEnterChecker;
|
|
23
|
-
private getHandleNormalEnter;
|
|
24
21
|
/**
|
|
25
22
|
* Get name of this plugin
|
|
26
23
|
*/
|
package/lib/edit/EditPlugin.js
CHANGED
|
@@ -52,7 +52,6 @@ var EditPlugin = /** @class */ (function () {
|
|
|
52
52
|
this.disposer = null;
|
|
53
53
|
this.shouldHandleNextInputEvent = false;
|
|
54
54
|
this.selectionAfterDelete = null;
|
|
55
|
-
this.handleNormalEnter = function () { return false; };
|
|
56
55
|
var tabOptions = options.handleTabKey === false
|
|
57
56
|
? DisabledHandleTabOptions
|
|
58
57
|
: options.handleTabKey === true || !options.handleTabKey
|
|
@@ -60,19 +59,6 @@ var EditPlugin = /** @class */ (function () {
|
|
|
60
59
|
: (0, tslib_1.__assign)((0, tslib_1.__assign)({}, DefaultHandleTabOptions), options.handleTabKey);
|
|
61
60
|
this.options = (0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)({}, DefaultOptions), options), { handleTabKey: tabOptions });
|
|
62
61
|
}
|
|
63
|
-
EditPlugin.prototype.createNormalEnterChecker = function (result) {
|
|
64
|
-
return result ? function () { return true; } : function () { return false; };
|
|
65
|
-
};
|
|
66
|
-
EditPlugin.prototype.getHandleNormalEnter = function (editor) {
|
|
67
|
-
switch (typeof this.options.shouldHandleEnterKey) {
|
|
68
|
-
case 'function':
|
|
69
|
-
return this.options.shouldHandleEnterKey;
|
|
70
|
-
case 'boolean':
|
|
71
|
-
return this.createNormalEnterChecker(this.options.shouldHandleEnterKey);
|
|
72
|
-
default:
|
|
73
|
-
return this.createNormalEnterChecker(editor.isExperimentalFeatureEnabled('HandleEnterKey'));
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
62
|
/**
|
|
77
63
|
* Get name of this plugin
|
|
78
64
|
*/
|
|
@@ -88,7 +74,6 @@ var EditPlugin = /** @class */ (function () {
|
|
|
88
74
|
EditPlugin.prototype.initialize = function (editor) {
|
|
89
75
|
var _this = this;
|
|
90
76
|
this.editor = editor;
|
|
91
|
-
this.handleNormalEnter = this.getHandleNormalEnter(editor);
|
|
92
77
|
if (editor.getEnvironment().isAndroid) {
|
|
93
78
|
this.disposer = this.editor.attachDomEvent({
|
|
94
79
|
beforeinput: {
|
|
@@ -192,7 +177,7 @@ var EditPlugin = /** @class */ (function () {
|
|
|
192
177
|
if (!hasCtrlOrMetaKey &&
|
|
193
178
|
!event.rawEvent.isComposing &&
|
|
194
179
|
event.rawEvent.keyCode !== DEAD_KEY) {
|
|
195
|
-
(0, keyboardEnter_1.keyboardEnter)(editor, rawEvent, this.
|
|
180
|
+
(0, keyboardEnter_1.keyboardEnter)(editor, rawEvent, this.options.formatsToPreserveOnMerge);
|
|
196
181
|
}
|
|
197
182
|
break;
|
|
198
183
|
default:
|
|
@@ -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 { EditOptions, HandleTabOptions } 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 DefaultHandleTabOptions: Required<HandleTabOptions> = {\n indentMultipleBlocks: true,\n indentTable: true,\n appendTableRow: true,\n indentList: true,\n indentParagraph: true,\n};\n\nconst DisabledHandleTabOptions: Required<HandleTabOptions> = {\n indentMultipleBlocks: false,\n indentTable: false,\n appendTableRow: false,\n indentList: false,\n indentParagraph: false,\n};\n\nconst DefaultOptions: Partial<EditOptions> & { handleTabKey: Required<HandleTabOptions> } = {\n handleTabKey: DefaultHandleTabOptions,\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 private options: EditOptions & { handleTabKey: Required<HandleTabOptions> };\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 or HandleTabOptions object that controls Tab key handling. When a boolean, true enables all features and false disables all. When an object, individual features can be controlled. Defaults to all enabled.\n */\n constructor(options: EditOptions = DefaultOptions) {\n const tabOptions =\n options.handleTabKey === false\n ? DisabledHandleTabOptions\n : options.handleTabKey === true || !options.handleTabKey\n ? DefaultHandleTabOptions\n : { ...DefaultHandleTabOptions, ...options.handleTabKey };\n this.options = { ...DefaultOptions, ...options, handleTabKey: tabOptions };\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.appendTableRow &&\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 keyboardDelete(editor, rawEvent, this.options);\n break;\n\n case 'Tab':\n if (!hasCtrlOrMetaKey) {\n keyboardTab(editor, rawEvent, this.options.handleTabKey);\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
|
+
{"version":3,"file":"EditPlugin.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/EditPlugin.ts"],"names":[],"mappings":";;;;AAAA,mDAAkD;AAClD,iDAAgD;AAChD,iDAAgD;AAChD,6CAA4C;AAC5C,2EAA8D;AAU9D,IAAM,aAAa,GAAG,CAAC,CAAC;AACxB,IAAM,UAAU,GAAG,EAAE,CAAC;AACtB;;;;;GAKG;AACH,IAAM,QAAQ,GAAG,GAAG,CAAC;AAErB,IAAM,uBAAuB,GAA+B;IACxD,oBAAoB,EAAE,IAAI;IAC1B,WAAW,EAAE,IAAI;IACjB,cAAc,EAAE,IAAI;IACpB,UAAU,EAAE,IAAI;IAChB,eAAe,EAAE,IAAI;CACxB,CAAC;AAEF,IAAM,wBAAwB,GAA+B;IACzD,oBAAoB,EAAE,KAAK;IAC3B,WAAW,EAAE,KAAK;IAClB,cAAc,EAAE,KAAK;IACrB,UAAU,EAAE,KAAK;IACjB,eAAe,EAAE,KAAK;CACzB,CAAC;AAEF,IAAM,cAAc,GAAwE;IACxF,YAAY,EAAE,uBAAuB;IACrC,+BAA+B,EAAE,IAAI;CACxC,CAAC;AAEF;;;;;;GAMG;AACH;IAOI;;;OAGG;IACH,oBAAY,OAAqC;QAArC,wBAAA,EAAA,wBAAqC;QAVzC,WAAM,GAAmB,IAAI,CAAC;QAC9B,aAAQ,GAAwB,IAAI,CAAC;QACrC,+BAA0B,GAAG,KAAK,CAAC;QACnC,yBAAoB,GAAwB,IAAI,CAAC;QAQrD,IAAM,UAAU,GACZ,OAAO,CAAC,YAAY,KAAK,KAAK;YAC1B,CAAC,CAAC,wBAAwB;YAC1B,CAAC,CAAC,OAAO,CAAC,YAAY,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,YAAY;gBACxD,CAAC,CAAC,uBAAuB;gBACzB,CAAC,iDAAM,uBAAuB,GAAK,OAAO,CAAC,YAAY,CAAE,CAAC;QAClE,IAAI,CAAC,OAAO,yEAAQ,cAAc,GAAK,OAAO,KAAE,YAAY,EAAE,UAAU,GAAE,CAAC;IAC/E,CAAC;IAED;;OAEG;IACH,4BAAO,GAAP;QACI,OAAO,MAAM,CAAC;IAClB,CAAC;IAED;;;;;OAKG;IACH,+BAAU,GAAV,UAAW,MAAe;QAA1B,iBAUC;QATG,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC,SAAS,EAAE;YACnC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC;gBACvC,WAAW,EAAE;oBACT,cAAc,EAAE,UAAA,CAAC,IAAI,OAAA,KAAI,CAAC,sBAAsB,CAAC,MAAM,EAAE,CAAC,CAAC,EAAtC,CAAsC;iBAC9D;aACJ,CAAC,CAAC;SACN;IACL,CAAC;IAED;;;;OAIG;IACH,4BAAO,GAAP;;QACI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,MAAA,IAAI,CAAC,QAAQ,+CAAb,IAAI,CAAa,CAAC;QAClB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACzB,CAAC;IAED;;;;;OAKG;IACH,kCAAa,GAAb,UAAc,KAAkB;QAC5B,IAAI,IAAI,CAAC,MAAM,EAAE;YACb,QAAQ,KAAK,CAAC,SAAS,EAAE;gBACrB,KAAK,SAAS;oBACV,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;oBAC5C,MAAM;gBACV,KAAK,OAAO;oBACR,IAAI,IAAI,CAAC,oBAAoB,EAAE;wBAC3B,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;wBACvD,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC;qBACpC;oBACD,MAAM;aACb;SACJ;IACL,CAAC;IAED;;;;;;;OAOG;IACH,+CAA0B,GAA1B,UAA2B,KAAkB;QACzC,IACI,IAAI,CAAC,MAAM;YACX,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,cAAc;YACxC,KAAK,CAAC,SAAS,IAAI,SAAS;YAC5B,KAAK,CAAC,QAAQ,CAAC,GAAG,IAAI,KAAK;YAC3B,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAC1B;YACE,IAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;YAChD,IAAM,cAAc,GAChB,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,IAAI,KAAI,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;YACvE,IAAM,KAAK,GAAG,cAAc;gBACxB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,0BAA0B,CAAC,cAAc,EAAE,OAAO,CAAC;gBAChF,CAAC,CAAC,IAAI,CAAC;YACX,IAAM,WAAW,GAAG,KAAK,IAAI,IAAA,6CAAe,EAAC,KAAK,CAAC,CAAC;YAEpD,IAAI,WAAW,EAAE;gBACb,IAAM,OAAO,GAAG,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBACpD,IAAM,QAAQ,GAAG,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBAExD,IAAI,OAAO,QAAQ,IAAI,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE;oBAClE,qHAAqH;oBACrH,8FAA8F;oBAC9F,OAAO,IAAI,CAAC;iBACf;aACJ;SACJ;QAED,OAAO,KAAK,CAAC;IACjB,CAAC;IAEO,uCAAkB,GAA1B,UAA2B,MAAe,EAAE,KAAmB;QAC3D,IAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;QAChC,IAAM,gBAAgB,GAAG,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC;QAE9D,IAAI,CAAC,QAAQ,CAAC,gBAAgB,IAAI,CAAC,KAAK,CAAC,oBAAoB,EAAE;YAC3D,QAAQ,QAAQ,CAAC,GAAG,EAAE;gBAClB,KAAK,WAAW;oBACZ,8CAA8C;oBAC9C,qIAAqI;oBACrI,IAAI,CAAC,IAAI,CAAC,4BAA4B,CAAC,MAAM,CAAC,EAAE;wBAC5C,IAAA,+BAAc,EAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;qBAClD;oBACD,MAAM;gBAEV,KAAK,QAAQ;oBACT,8CAA8C;oBAC9C,qIAAqI;oBACrI,IAAA,+BAAc,EAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;oBAC/C,MAAM;gBAEV,KAAK,KAAK;oBACN,IAAI,CAAC,gBAAgB,EAAE;wBACnB,IAAA,yBAAW,EAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;qBAC5D;oBACD,MAAM;gBACV,KAAK,cAAc;oBACf,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC,SAAS,EAAE;wBACnC,IAAI,CAAC,0BAA0B,GAAG,IAAI,CAAC;qBAC1C;oBACD,MAAM;gBAEV,KAAK,OAAO;oBACR,IACI,CAAC,gBAAgB;wBACjB,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW;wBAC3B,KAAK,CAAC,QAAQ,CAAC,OAAO,KAAK,QAAQ,EACrC;wBACE,IAAA,6BAAa,EAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC;qBAC1E;oBACD,MAAM;gBAEV;oBACI,IAAA,6BAAa,EAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;oBAChC,MAAM;aACb;SACJ;IACL,CAAC;IAEO,2CAAsB,GAA9B,UAA+B,MAAe,EAAE,QAAe;QAC3D,gFAAgF;QAChF,uGAAuG;QACvG,IACI,CAAC,IAAI,CAAC,0BAA0B;YAChC,CAAC,CAAC,QAAQ,YAAY,UAAU,CAAC;YACjC,QAAQ,CAAC,gBAAgB,EAC3B;YACE,OAAO;SACV;QACD,IAAI,CAAC,0BAA0B,GAAG,KAAK,CAAC;QAExC,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,QAAQ,QAAQ,CAAC,SAAS,EAAE;YACxB,KAAK,uBAAuB;gBACxB,IAAI,CAAC,IAAI,CAAC,4BAA4B,CAAC,MAAM,CAAC,EAAE;oBAC5C,yLAAyL;oBACzL,OAAO,GAAG,IAAA,+BAAc,EACpB,MAAM,EACN,IAAI,aAAa,CAAC,SAAS,EAAE;wBACzB,GAAG,EAAE,WAAW;wBAChB,OAAO,EAAE,aAAa;wBACtB,KAAK,EAAE,aAAa;qBACvB,CAAC,EACF,IAAI,CAAC,OAAO,CACf,CAAC;iBACL;gBACD,MAAM;YACV,KAAK,sBAAsB;gBACvB,OAAO,GAAG,IAAA,+BAAc,EACpB,MAAM,EACN,IAAI,aAAa,CAAC,SAAS,EAAE;oBACzB,GAAG,EAAE,QAAQ;oBACb,OAAO,EAAE,UAAU;oBACnB,KAAK,EAAE,UAAU;iBACpB,CAAC,EACF,IAAI,CAAC,OAAO,CACf,CAAC;gBACF,MAAM;SACb;QAED,IAAI,OAAO,EAAE;YACT,QAAQ,CAAC,cAAc,EAAE,CAAC;YAE1B,sEAAsE;YACtE,oDAAoD;YACpD,IAAI,CAAC,oBAAoB,GAAG,MAAM,CAAC,eAAe,EAAE,CAAC;SACxD;IACL,CAAC;IAEO,iDAA4B,GAApC,UAAqC,MAAe;QAChD,IAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,wBAAwB,CAAC;QAClD,QAAQ,OAAO,GAAG,EAAE;YAChB,KAAK,UAAU;gBACX,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC;YACvB,KAAK,SAAS;gBACV,OAAO,GAAG,CAAC;YACf;gBACI,OAAO,KAAK,CAAC;SACpB;IACL,CAAC;IACL,iBAAC;AAAD,CAAC,AAnOD,IAmOC;AAnOY,gCAAU","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, HandleTabOptions } 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 DefaultHandleTabOptions: Required<HandleTabOptions> = {\n indentMultipleBlocks: true,\n indentTable: true,\n appendTableRow: true,\n indentList: true,\n indentParagraph: true,\n};\n\nconst DisabledHandleTabOptions: Required<HandleTabOptions> = {\n indentMultipleBlocks: false,\n indentTable: false,\n appendTableRow: false,\n indentList: false,\n indentParagraph: false,\n};\n\nconst DefaultOptions: Partial<EditOptions> & { handleTabKey: Required<HandleTabOptions> } = {\n handleTabKey: DefaultHandleTabOptions,\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 options: EditOptions & { handleTabKey: Required<HandleTabOptions> };\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 or HandleTabOptions object that controls Tab key handling. When a boolean, true enables all features and false disables all. When an object, individual features can be controlled. Defaults to all enabled.\n */\n constructor(options: EditOptions = DefaultOptions) {\n const tabOptions =\n options.handleTabKey === false\n ? DisabledHandleTabOptions\n : options.handleTabKey === true || !options.handleTabKey\n ? DefaultHandleTabOptions\n : { ...DefaultHandleTabOptions, ...options.handleTabKey };\n this.options = { ...DefaultOptions, ...options, handleTabKey: tabOptions };\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\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.appendTableRow &&\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 keyboardDelete(editor, rawEvent, this.options);\n break;\n\n case 'Tab':\n if (!hasCtrlOrMetaKey) {\n keyboardTab(editor, rawEvent, this.options.handleTabKey);\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.options.formatsToPreserveOnMerge);\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"]}
|
|
@@ -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,
|
|
5
|
+
export declare function keyboardEnter(editor: IEditor, rawEvent: KeyboardEvent, formatsToPreserveOnMerge?: string[]): void;
|
|
@@ -9,11 +9,11 @@ var roosterjs_content_model_dom_1 = require("roosterjs-content-model-dom");
|
|
|
9
9
|
/**
|
|
10
10
|
* @internal
|
|
11
11
|
*/
|
|
12
|
-
function keyboardEnter(editor, rawEvent,
|
|
12
|
+
function keyboardEnter(editor, rawEvent, formatsToPreserveOnMerge) {
|
|
13
13
|
if (formatsToPreserveOnMerge === void 0) { formatsToPreserveOnMerge = []; }
|
|
14
14
|
var selection = editor.getDOMSelection();
|
|
15
15
|
editor.formatContentModel(function (model, context) {
|
|
16
|
-
var _a
|
|
16
|
+
var _a;
|
|
17
17
|
// 1. delete the expanded selection if any, then merge paragraph
|
|
18
18
|
var result = (0, roosterjs_content_model_dom_1.deleteSelection)(model, [], context);
|
|
19
19
|
// 2. Add line break
|
|
@@ -24,14 +24,12 @@ function keyboardEnter(editor, rawEvent, handleNormalEnter, formatsToPreserveOnM
|
|
|
24
24
|
var steps = rawEvent.shiftKey
|
|
25
25
|
? []
|
|
26
26
|
: [handleAutoLink_1.handleAutoLink, handleEnterOnList_1.handleEnterOnList, deleteEmptyQuote_1.deleteEmptyQuote];
|
|
27
|
-
|
|
28
|
-
steps.push((0, handleEnterOnParagraph_1.handleEnterOnParagraph)(formatsToPreserveOnMerge));
|
|
29
|
-
}
|
|
27
|
+
steps.push((0, handleEnterOnParagraph_1.handleEnterOnParagraph)(formatsToPreserveOnMerge));
|
|
30
28
|
(0, roosterjs_content_model_dom_1.runEditSteps)(steps, result);
|
|
31
29
|
}
|
|
32
30
|
if (result.deleteResult == 'range') {
|
|
33
31
|
// We have deleted something, next input should inherit the segment format from deleted content, so set pending format here
|
|
34
|
-
context.newPendingFormat = (
|
|
32
|
+
context.newPendingFormat = (_a = result.insertPoint) === null || _a === void 0 ? void 0 : _a.marker.format;
|
|
35
33
|
(0, roosterjs_content_model_dom_1.normalizeContentModel)(model);
|
|
36
34
|
rawEvent.preventDefault();
|
|
37
35
|
return true;
|
|
@@ -48,8 +46,4 @@ function keyboardEnter(editor, rawEvent, handleNormalEnter, formatsToPreserveOnM
|
|
|
48
46
|
});
|
|
49
47
|
}
|
|
50
48
|
exports.keyboardEnter = keyboardEnter;
|
|
51
|
-
function handleEnterForEntity(paragraph) {
|
|
52
|
-
return (paragraph &&
|
|
53
|
-
(paragraph.isImplicit || paragraph.segments.some(function (x) { return x.segmentType == 'Entity'; })));
|
|
54
|
-
}
|
|
55
49
|
//# sourceMappingURL=keyboardEnter.js.map
|
|
@@ -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,
|
|
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,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,KAAK,CAAC,IAAI,CAAC,IAAA,+CAAsB,EAAC,wBAAwB,CAAC,CAAC,CAAC;YAE7D,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;AA/CD,sCA+CC","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 } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport function keyboardEnter(\n editor: IEditor,\n rawEvent: KeyboardEvent,\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 steps.push(handleEnterOnParagraph(formatsToPreserveOnMerge));\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"]}
|
|
@@ -46,6 +46,7 @@ export declare type EditOptions = {
|
|
|
46
46
|
*/
|
|
47
47
|
handleExpandedSelectionOnDelete?: boolean;
|
|
48
48
|
/**
|
|
49
|
+
* @deprecated This is always treated as true now
|
|
49
50
|
* Callback function to determine whether the Rooster should handle the Enter key press.
|
|
50
51
|
* If the function returns true, the Rooster will handle the Enter key press instead of the browser.
|
|
51
52
|
* @param editor - The editor instance.
|
|
@@ -1 +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 for handling Tab key in Edit plugin\n */\nexport interface HandleTabOptions {\n /**\n * Whether to indent/outdent multiple selected blocks when Tab/Shift+Tab is pressed and multiple blocks are selected.\n * @default true\n */\n indentMultipleBlocks?: boolean;\n\n /**\n * Whether to indent/outdent table cells when Tab key is pressed and a table is selected\n * @default true\n */\n indentTable?: boolean;\n\n /**\n * Whether to append a new row when Tab key is pressed in the last cell of a table\n * @default true\n */\n appendTableRow?: boolean;\n\n /**\n * Whether to indent/outdent list items when Tab key is pressed\n * @default true\n */\n indentList?: boolean;\n\n /**\n * Whether to indent/outdent paragraph when Tab key is pressed\n * @default true\n */\n indentParagraph?: boolean;\n}\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, or an object to control specific Tab key behaviors.\n * When true, all Tab features are enabled. When false, all are disabled.\n * When an object, individual features can be controlled via HandleTabOptions.\n * @default true\n */\n handleTabKey?: HandleTabOptions | 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"]}
|
|
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 for handling Tab key in Edit plugin\n */\nexport interface HandleTabOptions {\n /**\n * Whether to indent/outdent multiple selected blocks when Tab/Shift+Tab is pressed and multiple blocks are selected.\n * @default true\n */\n indentMultipleBlocks?: boolean;\n\n /**\n * Whether to indent/outdent table cells when Tab key is pressed and a table is selected\n * @default true\n */\n indentTable?: boolean;\n\n /**\n * Whether to append a new row when Tab key is pressed in the last cell of a table\n * @default true\n */\n appendTableRow?: boolean;\n\n /**\n * Whether to indent/outdent list items when Tab key is pressed\n * @default true\n */\n indentList?: boolean;\n\n /**\n * Whether to indent/outdent paragraph when Tab key is pressed\n * @default true\n */\n indentParagraph?: boolean;\n}\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, or an object to control specific Tab key behaviors.\n * When true, all Tab features are enabled. When false, all are disabled.\n * When an object, individual features can be controlled via HandleTabOptions.\n * @default true\n */\n handleTabKey?: HandleTabOptions | 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 * @deprecated This is always treated as true now\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"]}
|
|
@@ -12,15 +12,12 @@ export declare class EditPlugin implements EditorPlugin {
|
|
|
12
12
|
private disposer;
|
|
13
13
|
private shouldHandleNextInputEvent;
|
|
14
14
|
private selectionAfterDelete;
|
|
15
|
-
private handleNormalEnter;
|
|
16
15
|
private options;
|
|
17
16
|
/**
|
|
18
17
|
* @param options An optional parameter that takes in an object of type EditOptions, which includes the following properties:
|
|
19
18
|
* handleTabKey: A boolean or HandleTabOptions object that controls Tab key handling. When a boolean, true enables all features and false disables all. When an object, individual features can be controlled. Defaults to all enabled.
|
|
20
19
|
*/
|
|
21
20
|
constructor(options?: EditOptions);
|
|
22
|
-
private createNormalEnterChecker;
|
|
23
|
-
private getHandleNormalEnter;
|
|
24
21
|
/**
|
|
25
22
|
* Get name of this plugin
|
|
26
23
|
*/
|
|
@@ -47,7 +47,6 @@ define(["require", "exports", "tslib", "./keyboardDelete", "./keyboardEnter", ".
|
|
|
47
47
|
this.disposer = null;
|
|
48
48
|
this.shouldHandleNextInputEvent = false;
|
|
49
49
|
this.selectionAfterDelete = null;
|
|
50
|
-
this.handleNormalEnter = function () { return false; };
|
|
51
50
|
var tabOptions = options.handleTabKey === false
|
|
52
51
|
? DisabledHandleTabOptions
|
|
53
52
|
: options.handleTabKey === true || !options.handleTabKey
|
|
@@ -55,19 +54,6 @@ define(["require", "exports", "tslib", "./keyboardDelete", "./keyboardEnter", ".
|
|
|
55
54
|
: (0, tslib_1.__assign)((0, tslib_1.__assign)({}, DefaultHandleTabOptions), options.handleTabKey);
|
|
56
55
|
this.options = (0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)({}, DefaultOptions), options), { handleTabKey: tabOptions });
|
|
57
56
|
}
|
|
58
|
-
EditPlugin.prototype.createNormalEnterChecker = function (result) {
|
|
59
|
-
return result ? function () { return true; } : function () { return false; };
|
|
60
|
-
};
|
|
61
|
-
EditPlugin.prototype.getHandleNormalEnter = function (editor) {
|
|
62
|
-
switch (typeof this.options.shouldHandleEnterKey) {
|
|
63
|
-
case 'function':
|
|
64
|
-
return this.options.shouldHandleEnterKey;
|
|
65
|
-
case 'boolean':
|
|
66
|
-
return this.createNormalEnterChecker(this.options.shouldHandleEnterKey);
|
|
67
|
-
default:
|
|
68
|
-
return this.createNormalEnterChecker(editor.isExperimentalFeatureEnabled('HandleEnterKey'));
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
57
|
/**
|
|
72
58
|
* Get name of this plugin
|
|
73
59
|
*/
|
|
@@ -83,7 +69,6 @@ define(["require", "exports", "tslib", "./keyboardDelete", "./keyboardEnter", ".
|
|
|
83
69
|
EditPlugin.prototype.initialize = function (editor) {
|
|
84
70
|
var _this = this;
|
|
85
71
|
this.editor = editor;
|
|
86
|
-
this.handleNormalEnter = this.getHandleNormalEnter(editor);
|
|
87
72
|
if (editor.getEnvironment().isAndroid) {
|
|
88
73
|
this.disposer = this.editor.attachDomEvent({
|
|
89
74
|
beforeinput: {
|
|
@@ -187,7 +172,7 @@ define(["require", "exports", "tslib", "./keyboardDelete", "./keyboardEnter", ".
|
|
|
187
172
|
if (!hasCtrlOrMetaKey &&
|
|
188
173
|
!event.rawEvent.isComposing &&
|
|
189
174
|
event.rawEvent.keyCode !== DEAD_KEY) {
|
|
190
|
-
(0, keyboardEnter_1.keyboardEnter)(editor, rawEvent, this.
|
|
175
|
+
(0, keyboardEnter_1.keyboardEnter)(editor, rawEvent, this.options.formatsToPreserveOnMerge);
|
|
191
176
|
}
|
|
192
177
|
break;
|
|
193
178
|
default:
|
|
@@ -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 { EditOptions, HandleTabOptions } 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 DefaultHandleTabOptions: Required<HandleTabOptions> = {\n indentMultipleBlocks: true,\n indentTable: true,\n appendTableRow: true,\n indentList: true,\n indentParagraph: true,\n};\n\nconst DisabledHandleTabOptions: Required<HandleTabOptions> = {\n indentMultipleBlocks: false,\n indentTable: false,\n appendTableRow: false,\n indentList: false,\n indentParagraph: false,\n};\n\nconst DefaultOptions: Partial<EditOptions> & { handleTabKey: Required<HandleTabOptions> } = {\n handleTabKey: DefaultHandleTabOptions,\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 private options: EditOptions & { handleTabKey: Required<HandleTabOptions> };\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 or HandleTabOptions object that controls Tab key handling. When a boolean, true enables all features and false disables all. When an object, individual features can be controlled. Defaults to all enabled.\n */\n constructor(options: EditOptions = DefaultOptions) {\n const tabOptions =\n options.handleTabKey === false\n ? DisabledHandleTabOptions\n : options.handleTabKey === true || !options.handleTabKey\n ? DefaultHandleTabOptions\n : { ...DefaultHandleTabOptions, ...options.handleTabKey };\n this.options = { ...DefaultOptions, ...options, handleTabKey: tabOptions };\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.appendTableRow &&\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 keyboardDelete(editor, rawEvent, this.options);\n break;\n\n case 'Tab':\n if (!hasCtrlOrMetaKey) {\n keyboardTab(editor, rawEvent, this.options.handleTabKey);\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
|
+
{"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, HandleTabOptions } 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 DefaultHandleTabOptions: Required<HandleTabOptions> = {\n indentMultipleBlocks: true,\n indentTable: true,\n appendTableRow: true,\n indentList: true,\n indentParagraph: true,\n};\n\nconst DisabledHandleTabOptions: Required<HandleTabOptions> = {\n indentMultipleBlocks: false,\n indentTable: false,\n appendTableRow: false,\n indentList: false,\n indentParagraph: false,\n};\n\nconst DefaultOptions: Partial<EditOptions> & { handleTabKey: Required<HandleTabOptions> } = {\n handleTabKey: DefaultHandleTabOptions,\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 options: EditOptions & { handleTabKey: Required<HandleTabOptions> };\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 or HandleTabOptions object that controls Tab key handling. When a boolean, true enables all features and false disables all. When an object, individual features can be controlled. Defaults to all enabled.\n */\n constructor(options: EditOptions = DefaultOptions) {\n const tabOptions =\n options.handleTabKey === false\n ? DisabledHandleTabOptions\n : options.handleTabKey === true || !options.handleTabKey\n ? DefaultHandleTabOptions\n : { ...DefaultHandleTabOptions, ...options.handleTabKey };\n this.options = { ...DefaultOptions, ...options, handleTabKey: tabOptions };\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\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.appendTableRow &&\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 keyboardDelete(editor, rawEvent, this.options);\n break;\n\n case 'Tab':\n if (!hasCtrlOrMetaKey) {\n keyboardTab(editor, rawEvent, this.options.handleTabKey);\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.options.formatsToPreserveOnMerge);\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"]}
|
|
@@ -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,
|
|
5
|
+
export declare function keyboardEnter(editor: IEditor, rawEvent: KeyboardEvent, formatsToPreserveOnMerge?: string[]): void;
|
|
@@ -5,11 +5,11 @@ define(["require", "exports", "./deleteSteps/deleteEmptyQuote", "./inputSteps/ha
|
|
|
5
5
|
/**
|
|
6
6
|
* @internal
|
|
7
7
|
*/
|
|
8
|
-
function keyboardEnter(editor, rawEvent,
|
|
8
|
+
function keyboardEnter(editor, rawEvent, formatsToPreserveOnMerge) {
|
|
9
9
|
if (formatsToPreserveOnMerge === void 0) { formatsToPreserveOnMerge = []; }
|
|
10
10
|
var selection = editor.getDOMSelection();
|
|
11
11
|
editor.formatContentModel(function (model, context) {
|
|
12
|
-
var _a
|
|
12
|
+
var _a;
|
|
13
13
|
// 1. delete the expanded selection if any, then merge paragraph
|
|
14
14
|
var result = (0, roosterjs_content_model_dom_1.deleteSelection)(model, [], context);
|
|
15
15
|
// 2. Add line break
|
|
@@ -20,14 +20,12 @@ define(["require", "exports", "./deleteSteps/deleteEmptyQuote", "./inputSteps/ha
|
|
|
20
20
|
var steps = rawEvent.shiftKey
|
|
21
21
|
? []
|
|
22
22
|
: [handleAutoLink_1.handleAutoLink, handleEnterOnList_1.handleEnterOnList, deleteEmptyQuote_1.deleteEmptyQuote];
|
|
23
|
-
|
|
24
|
-
steps.push((0, handleEnterOnParagraph_1.handleEnterOnParagraph)(formatsToPreserveOnMerge));
|
|
25
|
-
}
|
|
23
|
+
steps.push((0, handleEnterOnParagraph_1.handleEnterOnParagraph)(formatsToPreserveOnMerge));
|
|
26
24
|
(0, roosterjs_content_model_dom_1.runEditSteps)(steps, result);
|
|
27
25
|
}
|
|
28
26
|
if (result.deleteResult == 'range') {
|
|
29
27
|
// We have deleted something, next input should inherit the segment format from deleted content, so set pending format here
|
|
30
|
-
context.newPendingFormat = (
|
|
28
|
+
context.newPendingFormat = (_a = result.insertPoint) === null || _a === void 0 ? void 0 : _a.marker.format;
|
|
31
29
|
(0, roosterjs_content_model_dom_1.normalizeContentModel)(model);
|
|
32
30
|
rawEvent.preventDefault();
|
|
33
31
|
return true;
|
|
@@ -44,9 +42,5 @@ define(["require", "exports", "./deleteSteps/deleteEmptyQuote", "./inputSteps/ha
|
|
|
44
42
|
});
|
|
45
43
|
}
|
|
46
44
|
exports.keyboardEnter = keyboardEnter;
|
|
47
|
-
function handleEnterForEntity(paragraph) {
|
|
48
|
-
return (paragraph &&
|
|
49
|
-
(paragraph.isImplicit || paragraph.segments.some(function (x) { return x.segmentType == 'Entity'; })));
|
|
50
|
-
}
|
|
51
45
|
});
|
|
52
46
|
//# sourceMappingURL=keyboardEnter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyboardEnter.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/keyboardEnter.ts"],"names":[],"mappings":";;;;IAYA;;OAEG;IACH,SAAgB,aAAa,CACzB,MAAe,EACf,QAAuB,EACvB,
|
|
1
|
+
{"version":3,"file":"keyboardEnter.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/keyboardEnter.ts"],"names":[],"mappings":";;;;IAYA;;OAEG;IACH,SAAgB,aAAa,CACzB,MAAe,EACf,QAAuB,EACvB,wBAAuC;QAAvC,yCAAA,EAAA,6BAAuC;QAEvC,IAAM,SAAS,GAAG,MAAM,CAAC,eAAe,EAAE,CAAC;QAE3C,MAAM,CAAC,kBAAkB,CACrB,UAAC,KAAK,EAAE,OAAO;;YACX,gEAAgE;YAChE,IAAM,MAAM,GAAG,IAAA,6CAAe,EAAC,KAAK,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;YAEnD,oBAAoB;YACpB,IAAI,SAAS,IAAI,SAAS,CAAC,IAAI,IAAI,OAAO,EAAE;gBACxC,iIAAiI;gBACjI,2CAA2C;gBAC3C,MAAM,CAAC,YAAY,GAAG,YAAY,CAAC;gBAEnC,IAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ;oBAC3B,CAAC,CAAC,EAAE;oBACJ,CAAC,CAAC,CAAC,+BAAc,EAAE,qCAAiB,EAAE,mCAAgB,CAAC,CAAC;gBAE5D,KAAK,CAAC,IAAI,CAAC,IAAA,+CAAsB,EAAC,wBAAwB,CAAC,CAAC,CAAC;gBAE7D,IAAA,0CAAY,EAAC,KAAK,EAAE,MAAM,CAAC,CAAC;aAC/B;YAED,IAAI,MAAM,CAAC,YAAY,IAAI,OAAO,EAAE;gBAChC,2HAA2H;gBAC3H,OAAO,CAAC,gBAAgB,GAAG,MAAA,MAAM,CAAC,WAAW,0CAAE,MAAM,CAAC,MAAM,CAAC;gBAE7D,IAAA,mDAAqB,EAAC,KAAK,CAAC,CAAC;gBAE7B,QAAQ,CAAC,cAAc,EAAE,CAAC;gBAC1B,OAAO,IAAI,CAAC;aACf;iBAAM;gBACH,OAAO,KAAK,CAAC;aAChB;QACL,CAAC,EACD;YACI,QAAQ,UAAA;YACR,mBAAmB,EAAE,IAAI;YACzB,YAAY,EAAE,0CAAY,CAAC,QAAQ;YACnC,aAAa,EAAE,cAAM,OAAA,QAAQ,CAAC,KAAK,EAAd,CAAc;YACnC,OAAO,EAAE,gBAAgB;SAC5B,CACJ,CAAC;IACN,CAAC;IA/CD,sCA+CC","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 } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport function keyboardEnter(\n editor: IEditor,\n rawEvent: KeyboardEvent,\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 steps.push(handleEnterOnParagraph(formatsToPreserveOnMerge));\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"]}
|
|
@@ -46,6 +46,7 @@ export declare type EditOptions = {
|
|
|
46
46
|
*/
|
|
47
47
|
handleExpandedSelectionOnDelete?: boolean;
|
|
48
48
|
/**
|
|
49
|
+
* @deprecated This is always treated as true now
|
|
49
50
|
* Callback function to determine whether the Rooster should handle the Enter key press.
|
|
50
51
|
* If the function returns true, the Rooster will handle the Enter key press instead of the browser.
|
|
51
52
|
* @param editor - The editor instance.
|
|
@@ -1 +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 for handling Tab key in Edit plugin\n */\nexport interface HandleTabOptions {\n /**\n * Whether to indent/outdent multiple selected blocks when Tab/Shift+Tab is pressed and multiple blocks are selected.\n * @default true\n */\n indentMultipleBlocks?: boolean;\n\n /**\n * Whether to indent/outdent table cells when Tab key is pressed and a table is selected\n * @default true\n */\n indentTable?: boolean;\n\n /**\n * Whether to append a new row when Tab key is pressed in the last cell of a table\n * @default true\n */\n appendTableRow?: boolean;\n\n /**\n * Whether to indent/outdent list items when Tab key is pressed\n * @default true\n */\n indentList?: boolean;\n\n /**\n * Whether to indent/outdent paragraph when Tab key is pressed\n * @default true\n */\n indentParagraph?: boolean;\n}\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, or an object to control specific Tab key behaviors.\n * When true, all Tab features are enabled. When false, all are disabled.\n * When an object, individual features can be controlled via HandleTabOptions.\n * @default true\n */\n handleTabKey?: HandleTabOptions | 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"]}
|
|
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 for handling Tab key in Edit plugin\n */\nexport interface HandleTabOptions {\n /**\n * Whether to indent/outdent multiple selected blocks when Tab/Shift+Tab is pressed and multiple blocks are selected.\n * @default true\n */\n indentMultipleBlocks?: boolean;\n\n /**\n * Whether to indent/outdent table cells when Tab key is pressed and a table is selected\n * @default true\n */\n indentTable?: boolean;\n\n /**\n * Whether to append a new row when Tab key is pressed in the last cell of a table\n * @default true\n */\n appendTableRow?: boolean;\n\n /**\n * Whether to indent/outdent list items when Tab key is pressed\n * @default true\n */\n indentList?: boolean;\n\n /**\n * Whether to indent/outdent paragraph when Tab key is pressed\n * @default true\n */\n indentParagraph?: boolean;\n}\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, or an object to control specific Tab key behaviors.\n * When true, all Tab features are enabled. When false, all are disabled.\n * When an object, individual features can be controlled via HandleTabOptions.\n * @default true\n */\n handleTabKey?: HandleTabOptions | 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 * @deprecated This is always treated as true now\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"]}
|
|
@@ -12,15 +12,12 @@ export declare class EditPlugin implements EditorPlugin {
|
|
|
12
12
|
private disposer;
|
|
13
13
|
private shouldHandleNextInputEvent;
|
|
14
14
|
private selectionAfterDelete;
|
|
15
|
-
private handleNormalEnter;
|
|
16
15
|
private options;
|
|
17
16
|
/**
|
|
18
17
|
* @param options An optional parameter that takes in an object of type EditOptions, which includes the following properties:
|
|
19
18
|
* handleTabKey: A boolean or HandleTabOptions object that controls Tab key handling. When a boolean, true enables all features and false disables all. When an object, individual features can be controlled. Defaults to all enabled.
|
|
20
19
|
*/
|
|
21
20
|
constructor(options?: EditOptions);
|
|
22
|
-
private createNormalEnterChecker;
|
|
23
|
-
private getHandleNormalEnter;
|
|
24
21
|
/**
|
|
25
22
|
* Get name of this plugin
|
|
26
23
|
*/
|
|
@@ -49,7 +49,6 @@ var EditPlugin = /** @class */ (function () {
|
|
|
49
49
|
this.disposer = null;
|
|
50
50
|
this.shouldHandleNextInputEvent = false;
|
|
51
51
|
this.selectionAfterDelete = null;
|
|
52
|
-
this.handleNormalEnter = function () { return false; };
|
|
53
52
|
var tabOptions = options.handleTabKey === false
|
|
54
53
|
? DisabledHandleTabOptions
|
|
55
54
|
: options.handleTabKey === true || !options.handleTabKey
|
|
@@ -57,19 +56,6 @@ var EditPlugin = /** @class */ (function () {
|
|
|
57
56
|
: __assign(__assign({}, DefaultHandleTabOptions), options.handleTabKey);
|
|
58
57
|
this.options = __assign(__assign(__assign({}, DefaultOptions), options), { handleTabKey: tabOptions });
|
|
59
58
|
}
|
|
60
|
-
EditPlugin.prototype.createNormalEnterChecker = function (result) {
|
|
61
|
-
return result ? function () { return true; } : function () { return false; };
|
|
62
|
-
};
|
|
63
|
-
EditPlugin.prototype.getHandleNormalEnter = function (editor) {
|
|
64
|
-
switch (typeof this.options.shouldHandleEnterKey) {
|
|
65
|
-
case 'function':
|
|
66
|
-
return this.options.shouldHandleEnterKey;
|
|
67
|
-
case 'boolean':
|
|
68
|
-
return this.createNormalEnterChecker(this.options.shouldHandleEnterKey);
|
|
69
|
-
default:
|
|
70
|
-
return this.createNormalEnterChecker(editor.isExperimentalFeatureEnabled('HandleEnterKey'));
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
59
|
/**
|
|
74
60
|
* Get name of this plugin
|
|
75
61
|
*/
|
|
@@ -85,7 +71,6 @@ var EditPlugin = /** @class */ (function () {
|
|
|
85
71
|
EditPlugin.prototype.initialize = function (editor) {
|
|
86
72
|
var _this = this;
|
|
87
73
|
this.editor = editor;
|
|
88
|
-
this.handleNormalEnter = this.getHandleNormalEnter(editor);
|
|
89
74
|
if (editor.getEnvironment().isAndroid) {
|
|
90
75
|
this.disposer = this.editor.attachDomEvent({
|
|
91
76
|
beforeinput: {
|
|
@@ -189,7 +174,7 @@ var EditPlugin = /** @class */ (function () {
|
|
|
189
174
|
if (!hasCtrlOrMetaKey &&
|
|
190
175
|
!event.rawEvent.isComposing &&
|
|
191
176
|
event.rawEvent.keyCode !== DEAD_KEY) {
|
|
192
|
-
keyboardEnter(editor, rawEvent, this.
|
|
177
|
+
keyboardEnter(editor, rawEvent, this.options.formatsToPreserveOnMerge);
|
|
193
178
|
}
|
|
194
179
|
break;
|
|
195
180
|
default:
|
|
@@ -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 { EditOptions, HandleTabOptions } 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 DefaultHandleTabOptions: Required<HandleTabOptions> = {\n indentMultipleBlocks: true,\n indentTable: true,\n appendTableRow: true,\n indentList: true,\n indentParagraph: true,\n};\n\nconst DisabledHandleTabOptions: Required<HandleTabOptions> = {\n indentMultipleBlocks: false,\n indentTable: false,\n appendTableRow: false,\n indentList: false,\n indentParagraph: false,\n};\n\nconst DefaultOptions: Partial<EditOptions> & { handleTabKey: Required<HandleTabOptions> } = {\n handleTabKey: DefaultHandleTabOptions,\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 private options: EditOptions & { handleTabKey: Required<HandleTabOptions> };\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 or HandleTabOptions object that controls Tab key handling. When a boolean, true enables all features and false disables all. When an object, individual features can be controlled. Defaults to all enabled.\n */\n constructor(options: EditOptions = DefaultOptions) {\n const tabOptions =\n options.handleTabKey === false\n ? DisabledHandleTabOptions\n : options.handleTabKey === true || !options.handleTabKey\n ? DefaultHandleTabOptions\n : { ...DefaultHandleTabOptions, ...options.handleTabKey };\n this.options = { ...DefaultOptions, ...options, handleTabKey: tabOptions };\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.appendTableRow &&\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 keyboardDelete(editor, rawEvent, this.options);\n break;\n\n case 'Tab':\n if (!hasCtrlOrMetaKey) {\n keyboardTab(editor, rawEvent, this.options.handleTabKey);\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
|
+
{"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, HandleTabOptions } 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 DefaultHandleTabOptions: Required<HandleTabOptions> = {\n indentMultipleBlocks: true,\n indentTable: true,\n appendTableRow: true,\n indentList: true,\n indentParagraph: true,\n};\n\nconst DisabledHandleTabOptions: Required<HandleTabOptions> = {\n indentMultipleBlocks: false,\n indentTable: false,\n appendTableRow: false,\n indentList: false,\n indentParagraph: false,\n};\n\nconst DefaultOptions: Partial<EditOptions> & { handleTabKey: Required<HandleTabOptions> } = {\n handleTabKey: DefaultHandleTabOptions,\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 options: EditOptions & { handleTabKey: Required<HandleTabOptions> };\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 or HandleTabOptions object that controls Tab key handling. When a boolean, true enables all features and false disables all. When an object, individual features can be controlled. Defaults to all enabled.\n */\n constructor(options: EditOptions = DefaultOptions) {\n const tabOptions =\n options.handleTabKey === false\n ? DisabledHandleTabOptions\n : options.handleTabKey === true || !options.handleTabKey\n ? DefaultHandleTabOptions\n : { ...DefaultHandleTabOptions, ...options.handleTabKey };\n this.options = { ...DefaultOptions, ...options, handleTabKey: tabOptions };\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\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.appendTableRow &&\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 keyboardDelete(editor, rawEvent, this.options);\n break;\n\n case 'Tab':\n if (!hasCtrlOrMetaKey) {\n keyboardTab(editor, rawEvent, this.options.handleTabKey);\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.options.formatsToPreserveOnMerge);\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"]}
|
|
@@ -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,
|
|
5
|
+
export declare function keyboardEnter(editor: IEditor, rawEvent: KeyboardEvent, formatsToPreserveOnMerge?: string[]): void;
|
|
@@ -6,11 +6,11 @@ import { ChangeSource, deleteSelection, normalizeContentModel, runEditSteps, } f
|
|
|
6
6
|
/**
|
|
7
7
|
* @internal
|
|
8
8
|
*/
|
|
9
|
-
export function keyboardEnter(editor, rawEvent,
|
|
9
|
+
export function keyboardEnter(editor, rawEvent, formatsToPreserveOnMerge) {
|
|
10
10
|
if (formatsToPreserveOnMerge === void 0) { formatsToPreserveOnMerge = []; }
|
|
11
11
|
var selection = editor.getDOMSelection();
|
|
12
12
|
editor.formatContentModel(function (model, context) {
|
|
13
|
-
var _a
|
|
13
|
+
var _a;
|
|
14
14
|
// 1. delete the expanded selection if any, then merge paragraph
|
|
15
15
|
var result = deleteSelection(model, [], context);
|
|
16
16
|
// 2. Add line break
|
|
@@ -21,14 +21,12 @@ export function keyboardEnter(editor, rawEvent, handleNormalEnter, formatsToPres
|
|
|
21
21
|
var steps = rawEvent.shiftKey
|
|
22
22
|
? []
|
|
23
23
|
: [handleAutoLink, handleEnterOnList, deleteEmptyQuote];
|
|
24
|
-
|
|
25
|
-
steps.push(handleEnterOnParagraph(formatsToPreserveOnMerge));
|
|
26
|
-
}
|
|
24
|
+
steps.push(handleEnterOnParagraph(formatsToPreserveOnMerge));
|
|
27
25
|
runEditSteps(steps, result);
|
|
28
26
|
}
|
|
29
27
|
if (result.deleteResult == 'range') {
|
|
30
28
|
// We have deleted something, next input should inherit the segment format from deleted content, so set pending format here
|
|
31
|
-
context.newPendingFormat = (
|
|
29
|
+
context.newPendingFormat = (_a = result.insertPoint) === null || _a === void 0 ? void 0 : _a.marker.format;
|
|
32
30
|
normalizeContentModel(model);
|
|
33
31
|
rawEvent.preventDefault();
|
|
34
32
|
return true;
|
|
@@ -44,8 +42,4 @@ export function keyboardEnter(editor, rawEvent, handleNormalEnter, formatsToPres
|
|
|
44
42
|
apiName: 'handleEnterKey',
|
|
45
43
|
});
|
|
46
44
|
}
|
|
47
|
-
function handleEnterForEntity(paragraph) {
|
|
48
|
-
return (paragraph &&
|
|
49
|
-
(paragraph.isImplicit || paragraph.segments.some(function (x) { return x.segmentType == 'Entity'; })));
|
|
50
|
-
}
|
|
51
45
|
//# sourceMappingURL=keyboardEnter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyboardEnter.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/keyboardEnter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EACH,YAAY,EACZ,eAAe,EACf,qBAAqB,EACrB,YAAY,GACf,MAAM,6BAA6B,CAAC;AAGrC;;GAEG;AACH,MAAM,UAAU,aAAa,CACzB,MAAe,EACf,QAAuB,EACvB,
|
|
1
|
+
{"version":3,"file":"keyboardEnter.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/keyboardEnter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EACH,YAAY,EACZ,eAAe,EACf,qBAAqB,EACrB,YAAY,GACf,MAAM,6BAA6B,CAAC;AAGrC;;GAEG;AACH,MAAM,UAAU,aAAa,CACzB,MAAe,EACf,QAAuB,EACvB,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,eAAe,CAAC,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,cAAc,EAAE,iBAAiB,EAAE,gBAAgB,CAAC,CAAC;YAE5D,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,wBAAwB,CAAC,CAAC,CAAC;YAE7D,YAAY,CAAC,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,qBAAqB,CAAC,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,YAAY,CAAC,QAAQ;QACnC,aAAa,EAAE,cAAM,OAAA,QAAQ,CAAC,KAAK,EAAd,CAAc;QACnC,OAAO,EAAE,gBAAgB;KAC5B,CACJ,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 } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport function keyboardEnter(\n editor: IEditor,\n rawEvent: KeyboardEvent,\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 steps.push(handleEnterOnParagraph(formatsToPreserveOnMerge));\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"]}
|
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.
|
|
7
|
-
"roosterjs-content-model-dom": "^9.
|
|
8
|
-
"roosterjs-content-model-types": "^9.
|
|
9
|
-
"roosterjs-content-model-api": "^9.
|
|
6
|
+
"roosterjs-content-model-core": "^9.51.0",
|
|
7
|
+
"roosterjs-content-model-dom": "^9.51.0",
|
|
8
|
+
"roosterjs-content-model-types": "^9.51.0",
|
|
9
|
+
"roosterjs-content-model-api": "^9.51.0"
|
|
10
10
|
},
|
|
11
|
-
"version": "9.
|
|
11
|
+
"version": "9.51.0",
|
|
12
12
|
"main": "./lib/index.js",
|
|
13
13
|
"typings": "./lib/index.d.ts",
|
|
14
14
|
"module": "./lib-mjs/index.js",
|