All files / roosterjs-editor-adapter/lib/corePlugins EditPlugin.ts

63.89% Statements 23/36
10.71% Branches 3/28
87.5% Functions 7/8
62.86% Lines 22/35

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 1041x                         1x 3x               3x               1x               1x 3x           1x 1x           1x 3x             1x 4x 4x 4x 4x   4x                 4x       4x                             1x           1x 3x    
import { isCtrlOrMetaPressed } from 'roosterjs-editor-dom';
import { Keys, PluginEventType } from 'roosterjs-editor-types';
import type {
    EditPluginState,
    GenericContentEditFeature,
    IEditor,
    PluginEvent,
    PluginWithState,
} from 'roosterjs-editor-types';
 
/**
 * Edit Component helps handle Content edit features
 */
class EditPlugin implements PluginWithState<EditPluginState> {
    private editor: IEditor | null = null;
    private state: EditPluginState;
 
    /**
     * Construct a new instance of EditPlugin
     * @param options The editor options
     */
    constructor() {
        this.state = {
            features: {},
        };
    }
 
    /**
     * Get a friendly name of  this plugin
     */
    getName() {
        return 'Edit';
    }
 
    /**
     * Initialize this plugin. This should only be called from Editor
     * @param editor Editor instance
     */
    initialize(editor: IEditor) {
        this.editor = editor;
    }
 
    /**
     * Dispose this plugin
     */
    dispose() {
        this.editor = null;
    }
 
    /**
     * Get plugin state object
     */
    getState() {
        return this.state;
    }
 
    /**
     * Handle events triggered from editor
     * @param event PluginEvent object
     */
    onPluginEvent(event: PluginEvent) {
        let hasFunctionKey = false;
        let features: GenericContentEditFeature<PluginEvent>[] | null = null;
        let ctrlOrMeta = false;
        const isKeyDownEvent = event.eventType == PluginEventType.KeyDown;
 
        Iif (isKeyDownEvent) {
            const rawEvent = event.rawEvent;
            const range = this.editor?.getSelectionRange();
 
            ctrlOrMeta = isCtrlOrMetaPressed(rawEvent);
            hasFunctionKey = ctrlOrMeta || rawEvent.altKey;
            features =
                this.state.features[rawEvent.which] ||
                (range && !range.collapsed && this.state.features[Keys.RANGE]);
        } else Iif (event.eventType == PluginEventType.ContentChanged) {
            features = this.state.features[Keys.CONTENTCHANGED];
        }
 
        for (let i = 0; features && i < features?.length; i++) {
            const feature = features[i];
            if (
                (feature.allowFunctionKeys || !hasFunctionKey) &&
                this.editor &&
                feature.shouldHandleEvent(event, this.editor, ctrlOrMeta)
            ) {
                feature.handleEvent(event, this.editor);
                if (isKeyDownEvent) {
                    event.handledByEditFeature = true;
                }
                break;
            }
        }
    }
}
 
/**
 * @internal
 * Create a new instance of EditPlugin.
 */
export function createEditPlugin(): PluginWithState<EditPluginState> {
    return new EditPlugin();
}