roosterjs-content-model-plugins 9.43.0 → 9.44.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 +35 -2
- package/lib/edit/EditOptions.js.map +1 -1
- package/lib/edit/EditPlugin.d.ts +2 -2
- package/lib/edit/EditPlugin.js +25 -7
- package/lib/edit/EditPlugin.js.map +1 -1
- package/lib/edit/keyboardTab.d.ts +2 -1
- package/lib/edit/keyboardTab.js +29 -19
- package/lib/edit/keyboardTab.js.map +1 -1
- package/lib/edit/tabUtils/handleTabOnList.js.map +1 -1
- package/lib/imageEdit/ImageEditPlugin.js +4 -5
- package/lib/imageEdit/ImageEditPlugin.js.map +1 -1
- package/lib/imageEdit/utils/generateDataURL.js +12 -7
- package/lib/imageEdit/utils/generateDataURL.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js.map +1 -1
- package/lib/paste/PastePlugin.js +11 -3
- package/lib/paste/PastePlugin.js.map +1 -1
- package/lib/paste/WordDesktop/getStyleMetadata.d.ts +1 -2
- package/lib/paste/WordDesktop/getStyleMetadata.js +5 -2
- package/lib/paste/WordDesktop/getStyleMetadata.js.map +1 -1
- package/lib/paste/WordDesktop/processPastedContentFromWordDesktop.d.ts +5 -4
- package/lib/paste/WordDesktop/processPastedContentFromWordDesktop.js +13 -10
- package/lib/paste/WordDesktop/processPastedContentFromWordDesktop.js.map +1 -1
- package/lib/paste/parsers/removeNegativeTextIndentParser.js +1 -1
- package/lib/paste/parsers/removeNegativeTextIndentParser.js.map +1 -1
- package/lib/paste/parsers/wordContainerParser.d.ts +8 -0
- package/lib/paste/parsers/wordContainerParser.js +17 -0
- package/lib/paste/parsers/wordContainerParser.js.map +1 -0
- package/lib/paste/pasteSourceValidations/documentContainWacElements.d.ts +1 -1
- package/lib/paste/pasteSourceValidations/documentContainWacElements.js.map +1 -1
- package/lib/paste/pasteSourceValidations/getDocumentSource.d.ts +52 -0
- package/lib/paste/pasteSourceValidations/{getPasteSource.js → getDocumentSource.js} +4 -12
- package/lib/paste/pasteSourceValidations/getDocumentSource.js.map +1 -0
- package/lib/paste/pasteSourceValidations/isExcelDesktopDocument.d.ts +1 -1
- package/lib/paste/pasteSourceValidations/isExcelDesktopDocument.js.map +1 -1
- package/lib/paste/pasteSourceValidations/isExcelNonNativeEvent.d.ts +1 -1
- package/lib/paste/pasteSourceValidations/isExcelNonNativeEvent.js +5 -5
- package/lib/paste/pasteSourceValidations/isExcelNonNativeEvent.js.map +1 -1
- package/lib/paste/pasteSourceValidations/isExcelOnlineDocument.d.ts +1 -1
- package/lib/paste/pasteSourceValidations/isExcelOnlineDocument.js.map +1 -1
- package/lib/paste/pasteSourceValidations/isGoogleSheetDocument.d.ts +1 -1
- package/lib/paste/pasteSourceValidations/isGoogleSheetDocument.js.map +1 -1
- package/lib/paste/pasteSourceValidations/isOneNoteDocument.d.ts +1 -1
- package/lib/paste/pasteSourceValidations/isOneNoteDocument.js.map +1 -1
- package/lib/paste/pasteSourceValidations/isPowerPointDesktopDocument.d.ts +1 -1
- package/lib/paste/pasteSourceValidations/isPowerPointDesktopDocument.js.map +1 -1
- package/lib/paste/pasteSourceValidations/isWordDesktopDocument.d.ts +1 -1
- package/lib/paste/pasteSourceValidations/isWordDesktopDocument.js +4 -4
- package/lib/paste/pasteSourceValidations/isWordDesktopDocument.js.map +1 -1
- package/lib/paste/pasteSourceValidations/shouldConvertToSingleImage.d.ts +1 -1
- package/lib/paste/pasteSourceValidations/shouldConvertToSingleImage.js +4 -5
- package/lib/paste/pasteSourceValidations/shouldConvertToSingleImage.js.map +1 -1
- package/lib-amd/edit/EditOptions.d.ts +35 -2
- package/lib-amd/edit/EditOptions.js.map +1 -1
- package/lib-amd/edit/EditPlugin.d.ts +2 -2
- package/lib-amd/edit/EditPlugin.js +25 -7
- package/lib-amd/edit/EditPlugin.js.map +1 -1
- package/lib-amd/edit/keyboardTab.d.ts +2 -1
- package/lib-amd/edit/keyboardTab.js +29 -19
- package/lib-amd/edit/keyboardTab.js.map +1 -1
- package/lib-amd/edit/tabUtils/handleTabOnList.js.map +1 -1
- package/lib-amd/imageEdit/ImageEditPlugin.js +4 -5
- package/lib-amd/imageEdit/ImageEditPlugin.js.map +1 -1
- package/lib-amd/imageEdit/utils/generateDataURL.js +12 -7
- package/lib-amd/imageEdit/utils/generateDataURL.js.map +1 -1
- package/lib-amd/index.d.ts +1 -1
- package/lib-amd/index.js.map +1 -1
- package/lib-amd/paste/PastePlugin.js +11 -3
- package/lib-amd/paste/PastePlugin.js.map +1 -1
- package/lib-amd/paste/WordDesktop/getStyleMetadata.d.ts +1 -2
- package/lib-amd/paste/WordDesktop/getStyleMetadata.js +5 -2
- package/lib-amd/paste/WordDesktop/getStyleMetadata.js.map +1 -1
- package/lib-amd/paste/WordDesktop/processPastedContentFromWordDesktop.d.ts +5 -4
- package/lib-amd/paste/WordDesktop/processPastedContentFromWordDesktop.js +13 -11
- package/lib-amd/paste/WordDesktop/processPastedContentFromWordDesktop.js.map +1 -1
- package/lib-amd/paste/parsers/removeNegativeTextIndentParser.js +1 -1
- package/lib-amd/paste/parsers/removeNegativeTextIndentParser.js.map +1 -1
- package/lib-amd/paste/parsers/wordContainerParser.d.ts +8 -0
- package/lib-amd/paste/parsers/wordContainerParser.js +19 -0
- package/lib-amd/paste/parsers/wordContainerParser.js.map +1 -0
- package/lib-amd/paste/pasteSourceValidations/documentContainWacElements.d.ts +1 -1
- package/lib-amd/paste/pasteSourceValidations/documentContainWacElements.js.map +1 -1
- package/lib-amd/paste/pasteSourceValidations/getDocumentSource.d.ts +52 -0
- package/lib-amd/paste/pasteSourceValidations/{getPasteSource.js → getDocumentSource.js} +4 -12
- package/lib-amd/paste/pasteSourceValidations/getDocumentSource.js.map +1 -0
- package/lib-amd/paste/pasteSourceValidations/isExcelDesktopDocument.d.ts +1 -1
- package/lib-amd/paste/pasteSourceValidations/isExcelDesktopDocument.js.map +1 -1
- package/lib-amd/paste/pasteSourceValidations/isExcelNonNativeEvent.d.ts +1 -1
- package/lib-amd/paste/pasteSourceValidations/isExcelNonNativeEvent.js +5 -5
- package/lib-amd/paste/pasteSourceValidations/isExcelNonNativeEvent.js.map +1 -1
- package/lib-amd/paste/pasteSourceValidations/isExcelOnlineDocument.d.ts +1 -1
- package/lib-amd/paste/pasteSourceValidations/isExcelOnlineDocument.js.map +1 -1
- package/lib-amd/paste/pasteSourceValidations/isGoogleSheetDocument.d.ts +1 -1
- package/lib-amd/paste/pasteSourceValidations/isGoogleSheetDocument.js.map +1 -1
- package/lib-amd/paste/pasteSourceValidations/isOneNoteDocument.d.ts +1 -1
- package/lib-amd/paste/pasteSourceValidations/isOneNoteDocument.js.map +1 -1
- package/lib-amd/paste/pasteSourceValidations/isPowerPointDesktopDocument.d.ts +1 -1
- package/lib-amd/paste/pasteSourceValidations/isPowerPointDesktopDocument.js.map +1 -1
- package/lib-amd/paste/pasteSourceValidations/isWordDesktopDocument.d.ts +1 -1
- package/lib-amd/paste/pasteSourceValidations/isWordDesktopDocument.js +4 -4
- package/lib-amd/paste/pasteSourceValidations/isWordDesktopDocument.js.map +1 -1
- package/lib-amd/paste/pasteSourceValidations/shouldConvertToSingleImage.d.ts +1 -1
- package/lib-amd/paste/pasteSourceValidations/shouldConvertToSingleImage.js +4 -5
- package/lib-amd/paste/pasteSourceValidations/shouldConvertToSingleImage.js.map +1 -1
- package/lib-mjs/edit/EditOptions.d.ts +35 -2
- package/lib-mjs/edit/EditOptions.js.map +1 -1
- package/lib-mjs/edit/EditPlugin.d.ts +2 -2
- package/lib-mjs/edit/EditPlugin.js +25 -7
- package/lib-mjs/edit/EditPlugin.js.map +1 -1
- package/lib-mjs/edit/keyboardTab.d.ts +2 -1
- package/lib-mjs/edit/keyboardTab.js +29 -19
- package/lib-mjs/edit/keyboardTab.js.map +1 -1
- package/lib-mjs/edit/tabUtils/handleTabOnList.js.map +1 -1
- package/lib-mjs/imageEdit/ImageEditPlugin.js +4 -5
- package/lib-mjs/imageEdit/ImageEditPlugin.js.map +1 -1
- package/lib-mjs/imageEdit/utils/generateDataURL.js +12 -7
- package/lib-mjs/imageEdit/utils/generateDataURL.js.map +1 -1
- package/lib-mjs/index.d.ts +1 -1
- package/lib-mjs/index.js.map +1 -1
- package/lib-mjs/paste/PastePlugin.js +11 -3
- package/lib-mjs/paste/PastePlugin.js.map +1 -1
- package/lib-mjs/paste/WordDesktop/getStyleMetadata.d.ts +1 -2
- package/lib-mjs/paste/WordDesktop/getStyleMetadata.js +5 -2
- package/lib-mjs/paste/WordDesktop/getStyleMetadata.js.map +1 -1
- package/lib-mjs/paste/WordDesktop/processPastedContentFromWordDesktop.d.ts +5 -4
- package/lib-mjs/paste/WordDesktop/processPastedContentFromWordDesktop.js +13 -10
- package/lib-mjs/paste/WordDesktop/processPastedContentFromWordDesktop.js.map +1 -1
- package/lib-mjs/paste/parsers/removeNegativeTextIndentParser.js +1 -1
- package/lib-mjs/paste/parsers/removeNegativeTextIndentParser.js.map +1 -1
- package/lib-mjs/paste/parsers/wordContainerParser.d.ts +8 -0
- package/lib-mjs/paste/parsers/wordContainerParser.js +13 -0
- package/lib-mjs/paste/parsers/wordContainerParser.js.map +1 -0
- package/lib-mjs/paste/pasteSourceValidations/documentContainWacElements.d.ts +1 -1
- package/lib-mjs/paste/pasteSourceValidations/documentContainWacElements.js.map +1 -1
- package/lib-mjs/paste/pasteSourceValidations/getDocumentSource.d.ts +52 -0
- package/lib-mjs/paste/pasteSourceValidations/{getPasteSource.js → getDocumentSource.js} +2 -10
- package/lib-mjs/paste/pasteSourceValidations/getDocumentSource.js.map +1 -0
- package/lib-mjs/paste/pasteSourceValidations/isExcelDesktopDocument.d.ts +1 -1
- package/lib-mjs/paste/pasteSourceValidations/isExcelDesktopDocument.js.map +1 -1
- package/lib-mjs/paste/pasteSourceValidations/isExcelNonNativeEvent.d.ts +1 -1
- package/lib-mjs/paste/pasteSourceValidations/isExcelNonNativeEvent.js +5 -5
- package/lib-mjs/paste/pasteSourceValidations/isExcelNonNativeEvent.js.map +1 -1
- package/lib-mjs/paste/pasteSourceValidations/isExcelOnlineDocument.d.ts +1 -1
- package/lib-mjs/paste/pasteSourceValidations/isExcelOnlineDocument.js.map +1 -1
- package/lib-mjs/paste/pasteSourceValidations/isGoogleSheetDocument.d.ts +1 -1
- package/lib-mjs/paste/pasteSourceValidations/isGoogleSheetDocument.js.map +1 -1
- package/lib-mjs/paste/pasteSourceValidations/isOneNoteDocument.d.ts +1 -1
- package/lib-mjs/paste/pasteSourceValidations/isOneNoteDocument.js.map +1 -1
- package/lib-mjs/paste/pasteSourceValidations/isPowerPointDesktopDocument.d.ts +1 -1
- package/lib-mjs/paste/pasteSourceValidations/isPowerPointDesktopDocument.js.map +1 -1
- package/lib-mjs/paste/pasteSourceValidations/isWordDesktopDocument.d.ts +1 -1
- package/lib-mjs/paste/pasteSourceValidations/isWordDesktopDocument.js +4 -4
- package/lib-mjs/paste/pasteSourceValidations/isWordDesktopDocument.js.map +1 -1
- package/lib-mjs/paste/pasteSourceValidations/shouldConvertToSingleImage.d.ts +1 -1
- package/lib-mjs/paste/pasteSourceValidations/shouldConvertToSingleImage.js +4 -5
- package/lib-mjs/paste/pasteSourceValidations/shouldConvertToSingleImage.js.map +1 -1
- package/package.json +5 -5
- package/lib/paste/pasteSourceValidations/getPasteSource.d.ts +0 -28
- package/lib/paste/pasteSourceValidations/getPasteSource.js.map +0 -1
- package/lib-amd/paste/pasteSourceValidations/getPasteSource.d.ts +0 -28
- package/lib-amd/paste/pasteSourceValidations/getPasteSource.js.map +0 -1
- package/lib-mjs/paste/pasteSourceValidations/getPasteSource.d.ts +0 -28
- package/lib-mjs/paste/pasteSourceValidations/getPasteSource.js.map +0 -1
|
@@ -1,12 +1,45 @@
|
|
|
1
1
|
import type { IEditor } from 'roosterjs-content-model-types';
|
|
2
|
+
/**
|
|
3
|
+
* Options for handling Tab key in Edit plugin
|
|
4
|
+
*/
|
|
5
|
+
export interface HandleTabOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Whether to indent/outdent multiple selected blocks when Tab/Shift+Tab is pressed and multiple blocks are selected.
|
|
8
|
+
* @default true
|
|
9
|
+
*/
|
|
10
|
+
indentMultipleBlocks?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Whether to indent/outdent table cells when Tab key is pressed and a table is selected
|
|
13
|
+
* @default true
|
|
14
|
+
*/
|
|
15
|
+
indentTable?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Whether to append a new row when Tab key is pressed in the last cell of a table
|
|
18
|
+
* @default true
|
|
19
|
+
*/
|
|
20
|
+
appendTableRow?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Whether to indent/outdent list items when Tab key is pressed
|
|
23
|
+
* @default true
|
|
24
|
+
*/
|
|
25
|
+
indentList?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Whether to indent/outdent paragraph when Tab key is pressed
|
|
28
|
+
* @default true
|
|
29
|
+
*/
|
|
30
|
+
indentParagraph?: boolean;
|
|
31
|
+
}
|
|
2
32
|
/**
|
|
3
33
|
* Options to customize the keyboard handling behavior of Edit plugin
|
|
4
34
|
*/
|
|
5
35
|
export declare type EditOptions = {
|
|
6
36
|
/**
|
|
7
|
-
* Whether to handle Tab key in keyboard
|
|
37
|
+
* Whether to handle Tab key in keyboard, or an object to control specific Tab key behaviors.
|
|
38
|
+
* When true, all Tab features are enabled. When false, all are disabled.
|
|
39
|
+
* When an object, individual features can be controlled via HandleTabOptions.
|
|
40
|
+
* @default true
|
|
8
41
|
*/
|
|
9
|
-
handleTabKey?: boolean;
|
|
42
|
+
handleTabKey?: HandleTabOptions | boolean;
|
|
10
43
|
/**
|
|
11
44
|
* Whether expanded selection within a text node should be handled by CM when pressing Backspace/Delete key.
|
|
12
45
|
* @default true
|
|
@@ -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 to customize the keyboard handling behavior of Edit plugin\n */\n\nexport type EditOptions = {\n /**\n * Whether to handle Tab key in keyboard. @default true\n */\n handleTabKey?: boolean;\n\n /**\n * Whether expanded selection within a text node should be handled by CM when pressing Backspace/Delete key.\n * @default true\n */\n handleExpandedSelectionOnDelete?: boolean;\n\n /**\n * Callback function to determine whether the Rooster should handle the Enter key press.\n * If the function returns true, the Rooster will handle the Enter key press instead of the browser.\n * @param editor - The editor instance.\n * @returns A boolean\n */\n shouldHandleEnterKey?: ((editor: IEditor) => boolean) | boolean;\n\n /**\n * Callback or boolean to determine whether the browser (not Content Model) should handle the Backspace key press.\n * If the value/callback returns true, Rooster will NOT handle Backspace and will defer to the browser's native behavior.\n * @param editor - The editor instance (when using callback).\n * @returns A boolean\n */\n shouldHandleBackspaceKey?: ((editor: IEditor) => boolean) | boolean;\n\n /**\n * An array of format property names that should be preserved when merging paragraphs\n * during editing operations such as pressing Enter, Backspace, or Delete keys.\n * This ensures consistent formatting is maintained across paragraph operations.\n *\n * @example\n * // Preserve font family and class name during paragraph operations\n * formatsToPreserveOnMerge: ['fontFamily', 'className']\n *\n * // When pressing Enter in a paragraph with fontFamily='Arial' and className='highlight',\n * // the new paragraph will inherit both properties: fontFamily='Arial' and className='highlight'\n *\n * // When pressing Backspace to merge two paragraphs, the preserved formats from the first\n * // paragraph will be applied to the merged result\n */\n formatsToPreserveOnMerge?: string[];\n};\n"]}
|
|
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"]}
|
package/lib/edit/EditPlugin.d.ts
CHANGED
|
@@ -8,15 +8,15 @@ import type { EditorPlugin, IEditor, PluginEvent } from 'roosterjs-content-model
|
|
|
8
8
|
* 3. Tab Key
|
|
9
9
|
*/
|
|
10
10
|
export declare class EditPlugin implements EditorPlugin {
|
|
11
|
-
private options;
|
|
12
11
|
private editor;
|
|
13
12
|
private disposer;
|
|
14
13
|
private shouldHandleNextInputEvent;
|
|
15
14
|
private selectionAfterDelete;
|
|
16
15
|
private handleNormalEnter;
|
|
16
|
+
private options;
|
|
17
17
|
/**
|
|
18
18
|
* @param options An optional parameter that takes in an object of type EditOptions, which includes the following properties:
|
|
19
|
-
* handleTabKey: A boolean
|
|
19
|
+
* 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
20
|
*/
|
|
21
21
|
constructor(options?: EditOptions);
|
|
22
22
|
private createNormalEnterChecker;
|
package/lib/edit/EditPlugin.js
CHANGED
|
@@ -16,8 +16,22 @@ var DELETE_KEY = 46;
|
|
|
16
16
|
* Other cases: https://stackoverflow.com/questions/25043934/is-it-ok-to-ignore-keydown-events-with-keycode-229
|
|
17
17
|
*/
|
|
18
18
|
var DEAD_KEY = 229;
|
|
19
|
+
var DefaultHandleTabOptions = {
|
|
20
|
+
indentMultipleBlocks: true,
|
|
21
|
+
indentTable: true,
|
|
22
|
+
appendTableRow: true,
|
|
23
|
+
indentList: true,
|
|
24
|
+
indentParagraph: true,
|
|
25
|
+
};
|
|
26
|
+
var DisabledHandleTabOptions = {
|
|
27
|
+
indentMultipleBlocks: false,
|
|
28
|
+
indentTable: false,
|
|
29
|
+
appendTableRow: false,
|
|
30
|
+
indentList: false,
|
|
31
|
+
indentParagraph: false,
|
|
32
|
+
};
|
|
19
33
|
var DefaultOptions = {
|
|
20
|
-
handleTabKey:
|
|
34
|
+
handleTabKey: DefaultHandleTabOptions,
|
|
21
35
|
handleExpandedSelectionOnDelete: true,
|
|
22
36
|
};
|
|
23
37
|
/**
|
|
@@ -30,17 +44,21 @@ var DefaultOptions = {
|
|
|
30
44
|
var EditPlugin = /** @class */ (function () {
|
|
31
45
|
/**
|
|
32
46
|
* @param options An optional parameter that takes in an object of type EditOptions, which includes the following properties:
|
|
33
|
-
* handleTabKey: A boolean
|
|
47
|
+
* 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.
|
|
34
48
|
*/
|
|
35
49
|
function EditPlugin(options) {
|
|
36
50
|
if (options === void 0) { options = DefaultOptions; }
|
|
37
|
-
this.options = options;
|
|
38
51
|
this.editor = null;
|
|
39
52
|
this.disposer = null;
|
|
40
53
|
this.shouldHandleNextInputEvent = false;
|
|
41
54
|
this.selectionAfterDelete = null;
|
|
42
55
|
this.handleNormalEnter = function () { return false; };
|
|
43
|
-
|
|
56
|
+
var tabOptions = options.handleTabKey === false
|
|
57
|
+
? DisabledHandleTabOptions
|
|
58
|
+
: options.handleTabKey === true || !options.handleTabKey
|
|
59
|
+
? DefaultHandleTabOptions
|
|
60
|
+
: (0, tslib_1.__assign)((0, tslib_1.__assign)({}, DefaultHandleTabOptions), options.handleTabKey);
|
|
61
|
+
this.options = (0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)({}, DefaultOptions), options), { handleTabKey: tabOptions });
|
|
44
62
|
}
|
|
45
63
|
EditPlugin.prototype.createNormalEnterChecker = function (result) {
|
|
46
64
|
return result ? function () { return true; } : function () { return false; };
|
|
@@ -121,7 +139,7 @@ var EditPlugin = /** @class */ (function () {
|
|
|
121
139
|
*/
|
|
122
140
|
EditPlugin.prototype.willHandleEventExclusively = function (event) {
|
|
123
141
|
if (this.editor &&
|
|
124
|
-
this.options.handleTabKey &&
|
|
142
|
+
this.options.handleTabKey.appendTableRow &&
|
|
125
143
|
event.eventType == 'keyDown' &&
|
|
126
144
|
event.rawEvent.key == 'Tab' &&
|
|
127
145
|
!event.rawEvent.shiftKey) {
|
|
@@ -164,8 +182,8 @@ var EditPlugin = /** @class */ (function () {
|
|
|
164
182
|
}
|
|
165
183
|
break;
|
|
166
184
|
case 'Tab':
|
|
167
|
-
if (
|
|
168
|
-
(0, keyboardTab_1.keyboardTab)(editor, rawEvent);
|
|
185
|
+
if (!hasCtrlOrMetaKey) {
|
|
186
|
+
(0, keyboardTab_1.keyboardTab)(editor, rawEvent, this.options.handleTabKey);
|
|
169
187
|
}
|
|
170
188
|
break;
|
|
171
189
|
case 'Unidentified':
|
|
@@ -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 } from './EditOptions';\nimport type {\n DOMSelection,\n EditorPlugin,\n IEditor,\n KeyDownEvent,\n PluginEvent,\n} from 'roosterjs-content-model-types';\n\nconst BACKSPACE_KEY = 8;\nconst DELETE_KEY = 46;\n/**\n * According to https://lists.w3.org/Archives/Public/www-dom/2010JulSep/att-0182/keyCode-spec.html\n * 229 can be sent in variants generated when Long press (iOS) or using IM.\n *\n * Other cases: https://stackoverflow.com/questions/25043934/is-it-ok-to-ignore-keydown-events-with-keycode-229\n */\nconst DEAD_KEY = 229;\n\nconst DefaultOptions: Partial<EditOptions> = {\n handleTabKey: true,\n handleExpandedSelectionOnDelete: true,\n};\n\n/**\n * Edit plugins helps editor to do editing operation on top of content model.\n * This includes:\n * 1. Delete Key\n * 2. Backspace Key\n * 3. Tab Key\n */\nexport class EditPlugin implements EditorPlugin {\n private editor: IEditor | null = null;\n private disposer: (() => void) | null = null;\n private shouldHandleNextInputEvent = false;\n private selectionAfterDelete: DOMSelection | null = null;\n private handleNormalEnter: (editor: IEditor) => boolean = () => false;\n\n /**\n * @param options An optional parameter that takes in an object of type EditOptions, which includes the following properties:\n * handleTabKey: A boolean that enables or disables Tab key handling. Defaults to true.\n */\n constructor(private options: EditOptions = DefaultOptions) {\n this.options = { ...DefaultOptions, ...options };\n }\n\n private createNormalEnterChecker(result: boolean) {\n return result ? () => true : () => false;\n }\n\n private getHandleNormalEnter(editor: IEditor) {\n switch (typeof this.options.shouldHandleEnterKey) {\n case 'function':\n return this.options.shouldHandleEnterKey;\n case 'boolean':\n return this.createNormalEnterChecker(this.options.shouldHandleEnterKey);\n default:\n return this.createNormalEnterChecker(\n editor.isExperimentalFeatureEnabled('HandleEnterKey')\n );\n }\n }\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'Edit';\n }\n\n /**\n * The first method that editor will call to a plugin when editor is initializing.\n * It will pass in the editor instance, plugin should take this chance to save the\n * editor reference so that it can call to any editor method or format API later.\n * @param editor The editor object\n */\n initialize(editor: IEditor) {\n this.editor = editor;\n this.handleNormalEnter = this.getHandleNormalEnter(editor);\n\n if (editor.getEnvironment().isAndroid) {\n this.disposer = this.editor.attachDomEvent({\n beforeinput: {\n beforeDispatch: e => this.handleBeforeInputEvent(editor, e),\n },\n });\n }\n }\n\n /**\n * The last method that editor will call to a plugin before it is disposed.\n * Plugin can take this chance to clear the reference to editor. After this method is\n * called, plugin should not call to any editor method since it will result in error.\n */\n dispose() {\n this.editor = null;\n this.disposer?.();\n this.disposer = null;\n }\n\n /**\n * Core method for a plugin. Once an event happens in editor, editor will call this\n * method of each plugin to handle the event as long as the event is not handled\n * exclusively by another plugin.\n * @param event The event to handle:\n */\n onPluginEvent(event: PluginEvent) {\n if (this.editor) {\n switch (event.eventType) {\n case 'keyDown':\n this.handleKeyDownEvent(this.editor, event);\n break;\n case 'keyUp':\n if (this.selectionAfterDelete) {\n this.editor.setDOMSelection(this.selectionAfterDelete);\n this.selectionAfterDelete = null;\n }\n break;\n }\n }\n }\n\n /**\n * Check if the plugin should handle the given event exclusively.\n * Handle an event exclusively means other plugin will not receive this event in\n * onPluginEvent method.\n * If two plugins will return true in willHandleEventExclusively() for the same event,\n * the final result depends on the order of the plugins are added into editor\n * @param event The event to check:\n */\n willHandleEventExclusively(event: PluginEvent) {\n if (\n this.editor &&\n this.options.handleTabKey &&\n event.eventType == 'keyDown' &&\n event.rawEvent.key == 'Tab' &&\n !event.rawEvent.shiftKey\n ) {\n const selection = this.editor.getDOMSelection();\n const startContainer =\n selection?.type == 'range' ? selection.range.startContainer : null;\n const table = startContainer\n ? this.editor.getDOMHelper().findClosestElementAncestor(startContainer, 'table')\n : null;\n const parsedTable = table && parseTableCells(table);\n\n if (parsedTable) {\n const lastRow = parsedTable[parsedTable.length - 1];\n const lastCell = lastRow && lastRow[lastRow.length - 1];\n\n if (typeof lastCell == 'object' && lastCell.contains(startContainer)) {\n // When TAB in the last cell of a table, we will generate new table row, so prevent other plugins handling this event\n // e.g. SelectionPlugin will move the focus out of table, which is conflict with this behavior\n return true;\n }\n }\n }\n\n return false;\n }\n\n private handleKeyDownEvent(editor: IEditor, event: KeyDownEvent) {\n const rawEvent = event.rawEvent;\n const hasCtrlOrMetaKey = rawEvent.ctrlKey || rawEvent.metaKey;\n\n if (!rawEvent.defaultPrevented && !event.handledByEditFeature) {\n switch (rawEvent.key) {\n case 'Backspace':\n // Use our API to handle BACKSPACE/DELETE key.\n // No need to clear cache here since if we rely on browser's behavior, there will be Input event and its handler will reconcile cache\n if (!this.shouldBrowserHandleBackspace(editor)) {\n keyboardDelete(editor, rawEvent, this.options);\n }\n break;\n\n case 'Delete':\n // Use our API to handle BACKSPACE/DELETE key.\n // No need to clear cache here since if we rely on browser's behavior, there will be Input event and its handler will reconcile cache\n // And leave it to browser when shift key is pressed so that browser will trigger cut event\n if (!event.rawEvent.shiftKey) {\n keyboardDelete(editor, rawEvent, this.options);\n }\n break;\n\n case 'Tab':\n if (this.options.handleTabKey && !hasCtrlOrMetaKey) {\n keyboardTab(editor, rawEvent);\n }\n break;\n case 'Unidentified':\n if (editor.getEnvironment().isAndroid) {\n this.shouldHandleNextInputEvent = true;\n }\n break;\n\n case 'Enter':\n if (\n !hasCtrlOrMetaKey &&\n !event.rawEvent.isComposing &&\n event.rawEvent.keyCode !== DEAD_KEY\n ) {\n keyboardEnter(\n editor,\n rawEvent,\n this.handleNormalEnter(editor),\n this.options.formatsToPreserveOnMerge\n );\n }\n break;\n\n default:\n keyboardInput(editor, rawEvent);\n break;\n }\n }\n }\n\n private handleBeforeInputEvent(editor: IEditor, rawEvent: Event) {\n // Some Android IMEs doesn't fire correct keydown event for BACKSPACE/DELETE key\n // Here we translate input event to BACKSPACE/DELETE keydown event to be compatible with existing logic\n if (\n !this.shouldHandleNextInputEvent ||\n !(rawEvent instanceof InputEvent) ||\n rawEvent.defaultPrevented\n ) {\n return;\n }\n this.shouldHandleNextInputEvent = false;\n\n let handled = false;\n switch (rawEvent.inputType) {\n case 'deleteContentBackward':\n if (!this.shouldBrowserHandleBackspace(editor)) {\n // This logic is Android specific. It's because some Android keyboard doesn't support key and keycode, the value of them is always Unidentified, so we have to manually create a new one.\n handled = keyboardDelete(\n editor,\n new KeyboardEvent('keydown', {\n key: 'Backspace',\n keyCode: BACKSPACE_KEY,\n which: BACKSPACE_KEY,\n }),\n this.options\n );\n }\n break;\n case 'deleteContentForward':\n handled = keyboardDelete(\n editor,\n new KeyboardEvent('keydown', {\n key: 'Delete',\n keyCode: DELETE_KEY,\n which: DELETE_KEY,\n }),\n this.options\n );\n break;\n }\n\n if (handled) {\n rawEvent.preventDefault();\n\n // Restore the selection on keyup event to avoid the cursor jump issue\n // See: https://issues.chromium.org/issues/330596261\n this.selectionAfterDelete = editor.getDOMSelection();\n }\n }\n\n private shouldBrowserHandleBackspace(editor: IEditor): boolean {\n const opt = this.options.shouldHandleBackspaceKey;\n switch (typeof opt) {\n case 'function':\n return opt(editor);\n case 'boolean':\n return opt;\n default:\n return false;\n }\n }\n}\n"]}
|
|
1
|
+
{"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 // And leave it to browser when shift key is pressed so that browser will trigger cut event\n if (!event.rawEvent.shiftKey) {\n keyboardDelete(editor, rawEvent, this.options);\n }\n break;\n\n case 'Tab':\n if (!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,5 +1,6 @@
|
|
|
1
|
+
import type { HandleTabOptions } from './EditOptions';
|
|
1
2
|
import type { IEditor } from 'roosterjs-content-model-types';
|
|
2
3
|
/**
|
|
3
4
|
* @internal
|
|
4
5
|
*/
|
|
5
|
-
export declare function keyboardTab(editor: IEditor, rawEvent: KeyboardEvent):
|
|
6
|
+
export declare function keyboardTab(editor: IEditor, rawEvent: KeyboardEvent, options: Required<HandleTabOptions>): void;
|
package/lib/edit/keyboardTab.js
CHANGED
|
@@ -10,29 +10,31 @@ var roosterjs_content_model_dom_1 = require("roosterjs-content-model-dom");
|
|
|
10
10
|
/**
|
|
11
11
|
* @internal
|
|
12
12
|
*/
|
|
13
|
-
function keyboardTab(editor, rawEvent) {
|
|
13
|
+
function keyboardTab(editor, rawEvent, options) {
|
|
14
14
|
var selection = editor.getDOMSelection();
|
|
15
15
|
switch (selection === null || selection === void 0 ? void 0 : selection.type) {
|
|
16
16
|
case 'range':
|
|
17
17
|
editor.formatContentModel(function (model, context) {
|
|
18
|
-
return handleTab(model, rawEvent, context);
|
|
18
|
+
return handleTab(model, rawEvent, context, options);
|
|
19
19
|
}, {
|
|
20
20
|
apiName: 'handleTabKey',
|
|
21
21
|
rawEvent: rawEvent,
|
|
22
22
|
changeSource: roosterjs_content_model_dom_1.ChangeSource.Keyboard,
|
|
23
23
|
getChangeData: function () { return rawEvent.which; },
|
|
24
24
|
});
|
|
25
|
-
|
|
25
|
+
break;
|
|
26
26
|
case 'table':
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
if (options.indentTable) {
|
|
28
|
+
editor.formatContentModel(function (model) {
|
|
29
|
+
return (0, handleTabOnTable_1.handleTabOnTable)(model, rawEvent);
|
|
30
|
+
}, {
|
|
31
|
+
apiName: 'handleTabKey',
|
|
32
|
+
rawEvent: rawEvent,
|
|
33
|
+
changeSource: roosterjs_content_model_dom_1.ChangeSource.Keyboard,
|
|
34
|
+
getChangeData: function () { return rawEvent.which; },
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
break;
|
|
36
38
|
}
|
|
37
39
|
}
|
|
38
40
|
exports.keyboardTab = keyboardTab;
|
|
@@ -43,22 +45,30 @@ exports.keyboardTab = keyboardTab;
|
|
|
43
45
|
* - If it is a paragraph, call handleTabOnParagraph to handle the tab key.
|
|
44
46
|
* - If it is a list item, call handleTabOnList to handle the tab key.
|
|
45
47
|
*/
|
|
46
|
-
function handleTab(model, rawEvent, context) {
|
|
48
|
+
function handleTab(model, rawEvent, context, options) {
|
|
47
49
|
var blocks = (0, roosterjs_content_model_dom_1.getOperationalBlocks)(model, ['ListItem', 'TableCell'], []);
|
|
48
50
|
var block = blocks.length > 0 ? blocks[0].block : undefined;
|
|
49
51
|
if (blocks.length > 1) {
|
|
50
|
-
(
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
if (options.indentMultipleBlocks) {
|
|
53
|
+
(0, roosterjs_content_model_api_1.setModelIndentation)(model, rawEvent.shiftKey ? 'outdent' : 'indent');
|
|
54
|
+
rawEvent.preventDefault();
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
53
57
|
}
|
|
54
58
|
else if ((0, roosterjs_content_model_dom_1.isBlockGroupOfType)(block, 'TableCell')) {
|
|
55
|
-
|
|
59
|
+
if (options.appendTableRow) {
|
|
60
|
+
return (0, handleTabOnTableCell_1.handleTabOnTableCell)(model, block, rawEvent);
|
|
61
|
+
}
|
|
56
62
|
}
|
|
57
63
|
else if ((block === null || block === void 0 ? void 0 : block.blockType) === 'Paragraph') {
|
|
58
|
-
|
|
64
|
+
if (options.indentParagraph) {
|
|
65
|
+
return (0, handleTabOnParagraph_1.handleTabOnParagraph)(model, block, rawEvent, context);
|
|
66
|
+
}
|
|
59
67
|
}
|
|
60
68
|
else if ((0, roosterjs_content_model_dom_1.isBlockGroupOfType)(block, 'ListItem')) {
|
|
61
|
-
|
|
69
|
+
if (options.indentList) {
|
|
70
|
+
return (0, handleTabOnList_1.handleTabOnList)(model, block, rawEvent, context);
|
|
71
|
+
}
|
|
62
72
|
}
|
|
63
73
|
return false;
|
|
64
74
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyboardTab.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/keyboardTab.ts"],"names":[],"mappings":";;;AAAA,8DAA6D;AAC7D,wEAAuE;AACvE,gEAA+D;AAC/D,wEAAuE;AACvE,2EAAkE;
|
|
1
|
+
{"version":3,"file":"keyboardTab.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/keyboardTab.ts"],"names":[],"mappings":";;;AAAA,8DAA6D;AAC7D,wEAAuE;AACvE,gEAA+D;AAC/D,wEAAuE;AACvE,2EAAkE;AAElE,2EAIqC;AASrC;;GAEG;AACH,SAAgB,WAAW,CACvB,MAAe,EACf,QAAuB,EACvB,OAAmC;IAEnC,IAAM,SAAS,GAAG,MAAM,CAAC,eAAe,EAAE,CAAC;IAE3C,QAAQ,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,IAAI,EAAE;QACrB,KAAK,OAAO;YACR,MAAM,CAAC,kBAAkB,CACrB,UAAC,KAAK,EAAE,OAAO;gBACX,OAAO,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;YACxD,CAAC,EACD;gBACI,OAAO,EAAE,cAAc;gBACvB,QAAQ,UAAA;gBACR,YAAY,EAAE,0CAAY,CAAC,QAAQ;gBACnC,aAAa,EAAE,cAAM,OAAA,QAAQ,CAAC,KAAK,EAAd,CAAc;aACtC,CACJ,CAAC;YACF,MAAM;QAEV,KAAK,OAAO;YACR,IAAI,OAAO,CAAC,WAAW,EAAE;gBACrB,MAAM,CAAC,kBAAkB,CACrB,UAAA,KAAK;oBACD,OAAO,IAAA,mCAAgB,EAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;gBAC7C,CAAC,EACD;oBACI,OAAO,EAAE,cAAc;oBACvB,QAAQ,UAAA;oBACR,YAAY,EAAE,0CAAY,CAAC,QAAQ;oBACnC,aAAa,EAAE,cAAM,OAAA,QAAQ,CAAC,KAAK,EAAd,CAAc;iBACtC,CACJ,CAAC;aACL;YACD,MAAM;KACb;AACL,CAAC;AAtCD,kCAsCC;AAED;;;;;;GAMG;AACH,SAAS,SAAS,CACd,KAAmC,EACnC,QAAuB,EACvB,OAAkC,EAClC,OAAmC;IAEnC,IAAM,MAAM,GAAG,IAAA,kDAAoB,EAC/B,KAAK,EACL,CAAC,UAAU,EAAE,WAAW,CAAC,EACzB,EAAE,CACL,CAAC;IACF,IAAM,KAAK,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAE9D,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE;QACnB,IAAI,OAAO,CAAC,oBAAoB,EAAE;YAC9B,IAAA,iDAAmB,EAAC,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YACrE,QAAQ,CAAC,cAAc,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC;SACf;KACJ;SAAM,IAAI,IAAA,gDAAkB,EAAwB,KAAK,EAAE,WAAW,CAAC,EAAE;QACtE,IAAI,OAAO,CAAC,cAAc,EAAE;YACxB,OAAO,IAAA,2CAAoB,EAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;SACvD;KACJ;SAAM,IAAI,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,SAAS,MAAK,WAAW,EAAE;QACzC,IAAI,OAAO,CAAC,eAAe,EAAE;YACzB,OAAO,IAAA,2CAAoB,EAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;SAChE;KACJ;SAAM,IAAI,IAAA,gDAAkB,EAAuB,KAAK,EAAE,UAAU,CAAC,EAAE;QACpE,IAAI,OAAO,CAAC,UAAU,EAAE;YACpB,OAAO,IAAA,iCAAe,EAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;SAC3D;KACJ;IACD,OAAO,KAAK,CAAC;AACjB,CAAC","sourcesContent":["import { handleTabOnList } from './tabUtils/handleTabOnList';\nimport { handleTabOnParagraph } from './tabUtils/handleTabOnParagraph';\nimport { handleTabOnTable } from './tabUtils/handleTabOnTable';\nimport { handleTabOnTableCell } from './tabUtils/handleTabOnTableCell';\nimport { setModelIndentation } from 'roosterjs-content-model-api';\nimport type { HandleTabOptions } from './EditOptions';\nimport {\n ChangeSource,\n getOperationalBlocks,\n isBlockGroupOfType,\n} from 'roosterjs-content-model-dom';\nimport type {\n ContentModelListItem,\n ContentModelTableCell,\n FormatContentModelContext,\n IEditor,\n ReadonlyContentModelDocument,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport function keyboardTab(\n editor: IEditor,\n rawEvent: KeyboardEvent,\n options: Required<HandleTabOptions>\n) {\n const selection = editor.getDOMSelection();\n\n switch (selection?.type) {\n case 'range':\n editor.formatContentModel(\n (model, context) => {\n return handleTab(model, rawEvent, context, options);\n },\n {\n apiName: 'handleTabKey',\n rawEvent,\n changeSource: ChangeSource.Keyboard,\n getChangeData: () => rawEvent.which,\n }\n );\n break;\n\n case 'table':\n if (options.indentTable) {\n editor.formatContentModel(\n model => {\n return handleTabOnTable(model, rawEvent);\n },\n {\n apiName: 'handleTabKey',\n rawEvent,\n changeSource: ChangeSource.Keyboard,\n getChangeData: () => rawEvent.which,\n }\n );\n }\n break;\n }\n}\n\n/**\n * If multiple blocks are selected, indent or outdent the selected blocks with setModelIndentation.\n * If only one block is selected:\n * - If it is a table cell, call handleTabOnTableCell to handle the tab key.\n * - If it is a paragraph, call handleTabOnParagraph to handle the tab key.\n * - If it is a list item, call handleTabOnList to handle the tab key.\n */\nfunction handleTab(\n model: ReadonlyContentModelDocument,\n rawEvent: KeyboardEvent,\n context: FormatContentModelContext,\n options: Required<HandleTabOptions>\n) {\n const blocks = getOperationalBlocks<ContentModelListItem | ContentModelTableCell>(\n model,\n ['ListItem', 'TableCell'],\n []\n );\n const block = blocks.length > 0 ? blocks[0].block : undefined;\n\n if (blocks.length > 1) {\n if (options.indentMultipleBlocks) {\n setModelIndentation(model, rawEvent.shiftKey ? 'outdent' : 'indent');\n rawEvent.preventDefault();\n return true;\n }\n } else if (isBlockGroupOfType<ContentModelTableCell>(block, 'TableCell')) {\n if (options.appendTableRow) {\n return handleTabOnTableCell(model, block, rawEvent);\n }\n } else if (block?.blockType === 'Paragraph') {\n if (options.indentParagraph) {\n return handleTabOnParagraph(model, block, rawEvent, context);\n }\n } else if (isBlockGroupOfType<ContentModelListItem>(block, 'ListItem')) {\n if (options.indentList) {\n return handleTabOnList(model, block, rawEvent, context);\n }\n }\n return false;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handleTabOnList.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/edit/tabUtils/handleTabOnList.ts"],"names":[],"mappings":";;;AAAA,+DAA8D;AAC9D,2EAAkE;AAOlE;;;;GAIG;AACH,SAAgB,eAAe,CAC3B,KAAmC,EACnC,QAAsC,EACtC,QAAuB,EACvB,OAAmC;IAEnC,IAAM,iBAAiB,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IAC1D,IACI,CAAC,sBAAsB,CAAC,QAAQ,CAAC;QACjC,iBAAiB,CAAC,MAAM,IAAI,CAAC;QAC7B,iBAAiB,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,WAAW,EAChD;QACE,OAAO,IAAA,2CAAoB,EAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;KAC/E;SAAM;QACH,IAAA,iDAAmB,EACf,KAAK,EACL,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EACxC,SAAS,CAAC,UAAU,EACpB,OAAO,CACV,CAAC;QACF,QAAQ,CAAC,cAAc,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"handleTabOnList.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/edit/tabUtils/handleTabOnList.ts"],"names":[],"mappings":";;;AAAA,+DAA8D;AAC9D,2EAAkE;AAOlE;;;;GAIG;AACH,SAAgB,eAAe,CAC3B,KAAmC,EACnC,QAAsC,EACtC,QAAuB,EACvB,OAAmC;IAEnC,IAAM,iBAAiB,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IAC1D,IACI,CAAC,sBAAsB,CAAC,QAAQ,CAAC;QACjC,iBAAiB,CAAC,MAAM,IAAI,CAAC;QAC7B,iBAAiB,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,WAAW,EAChD;QACE,OAAO,IAAA,2CAAoB,EAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;KAC/E;SAAM;QACH,IAAA,iDAAmB,EACf,KAAK,EACL,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EACxC,SAAS,CAAC,UAAU,EACpB,OAAO,CACV,CAAC;QACF,QAAQ,CAAC,cAAc,EAAE,CAAC;QAE1B,OAAO,IAAI,CAAC;KACf;AACL,CAAC;AAxBD,0CAwBC;AAED,SAAS,sBAAsB,CAAC,QAAsC;IAClE,OAAO,CACH,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,WAAW;QAC3C,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,IAAI,iBAAiB,CAClE,CAAC;AACN,CAAC;AAED,SAAS,qBAAqB,CAAC,QAAsC;IACjE,OAAO,QAAQ,CAAC,MAAM,CAAC,MAAM,CACzB,UAAA,KAAK;QACD,OAAA,KAAK,CAAC,SAAS,IAAI,WAAW,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAA,OAAO,IAAI,OAAA,OAAO,CAAC,UAAU,EAAlB,CAAkB,CAAC;IAApF,CAAoF,CAC3F,CAAC;AACN,CAAC","sourcesContent":["import { handleTabOnParagraph } from './handleTabOnParagraph';\nimport { setModelIndentation } from 'roosterjs-content-model-api';\nimport type {\n FormatContentModelContext,\n ReadonlyContentModelDocument,\n ReadonlyContentModelListItem,\n} from 'roosterjs-content-model-types';\n\n/**\n * 1. When the selection is collapsed and the cursor is at start of a list item, call setModelIndentation.\n * 2. Otherwise call handleTabOnParagraph.\n * @internal\n */\nexport function handleTabOnList(\n model: ReadonlyContentModelDocument,\n listItem: ReadonlyContentModelListItem,\n rawEvent: KeyboardEvent,\n context?: FormatContentModelContext\n) {\n const selectedParagraph = findSelectedParagraph(listItem);\n if (\n !isMarkerAtStartOfBlock(listItem) &&\n selectedParagraph.length == 1 &&\n selectedParagraph[0].blockType === 'Paragraph'\n ) {\n return handleTabOnParagraph(model, selectedParagraph[0], rawEvent, context);\n } else {\n setModelIndentation(\n model,\n rawEvent.shiftKey ? 'outdent' : 'indent',\n undefined /*length*/,\n context\n );\n rawEvent.preventDefault();\n\n return true;\n }\n}\n\nfunction isMarkerAtStartOfBlock(listItem: ReadonlyContentModelListItem) {\n return (\n listItem.blocks[0].blockType == 'Paragraph' &&\n listItem.blocks[0].segments[0].segmentType == 'SelectionMarker'\n );\n}\n\nfunction findSelectedParagraph(listItem: ReadonlyContentModelListItem) {\n return listItem.blocks.filter(\n block =>\n block.blockType == 'Paragraph' && block.segments.some(segment => segment.isSelected)\n );\n}\n"]}
|
|
@@ -231,11 +231,10 @@ var ImageEditPlugin = /** @class */ (function () {
|
|
|
231
231
|
}
|
|
232
232
|
}
|
|
233
233
|
};
|
|
234
|
-
ImageEditPlugin.prototype.setContentHandler = function (
|
|
235
|
-
|
|
236
|
-
if ((selection === null || selection === void 0 ? void 0 : selection.type) == 'image') {
|
|
234
|
+
ImageEditPlugin.prototype.setContentHandler = function () {
|
|
235
|
+
if (this.selectedImage) {
|
|
237
236
|
this.cleanInfo();
|
|
238
|
-
(0, roosterjs_content_model_dom_1.setImageState)(
|
|
237
|
+
(0, roosterjs_content_model_dom_1.setImageState)(this.selectedImage, '');
|
|
239
238
|
this.isEditing = false;
|
|
240
239
|
this.isCropMode = false;
|
|
241
240
|
}
|
|
@@ -250,7 +249,7 @@ var ImageEditPlugin = /** @class */ (function () {
|
|
|
250
249
|
ImageEditPlugin.prototype.contentChangedHandler = function (editor, event) {
|
|
251
250
|
switch (event.source) {
|
|
252
251
|
case roosterjs_content_model_dom_1.ChangeSource.SetContent:
|
|
253
|
-
this.setContentHandler(
|
|
252
|
+
this.setContentHandler();
|
|
254
253
|
break;
|
|
255
254
|
case roosterjs_content_model_dom_1.ChangeSource.Format:
|
|
256
255
|
this.formatEventHandler(event);
|