-
Notifications
You must be signed in to change notification settings - Fork 166
Hello plugin
Go back to Create your own plugin
In this page I will introduce how to create a new plugin.
Here is a quick sample of what is a simple editor plugin looks like (You can get the source code of this sample here)
import { Editor, EditorPlugin } from 'roosterjs-editor-core';
import { PluginEvent, PluginEventType, PluginDomEvent } from 'roosterjs-editor-types';
import { createEditor } from 'roosterjs';
const NUMBERS = [
'zero',
'one',
'two',
'three',
'four',
'five',
'six',
'seven',
'eight',
'nine',
];
const KEY_0 = 0x30;
const KEY_9 = 0x39;
// This plugin will insert an English word when user is inputting numbers
class MyPlugin implements EditorPlugin {
private editor: Editor;
getName() {
return 'MyPlugin';
}
initialize(editor: Editor) {
this.editor = editor;
}
dispose() {
this.editor = null;
}
onPluginEvent(event: PluginEvent) {
if (event.eventType == PluginEventType.KeyPress) {
let domEvent = <PluginDomEvent>event;
let keyboardEvent = <KeyboardEvent>domEvent.rawEvent;
if (keyboardEvent.which >= KEY_0 && keyboardEvent.which <= KEY_9) {
let text = NUMBERS[keyboardEvent.which - KEY_0] + ' ';
this.editor.insertContent(text);
keyboardEvent.preventDefault();
}
}
}
}
let contentDiv = document.getElementById("contentDiv") as HTMLDivElement;
let myPlugin = new MyPlugin();
let editor = createEditor(contentDiv, [ myPlugin ]);
In the code it creates a plugin and adds into an editor. This plugin will handle keypress event in editor, when user inputs a number, the plugin will insert an English word instead of the number into editor. You can download the full source code and follow the instruction in the HTML page to run this sample.
As a plugin, the first thing is to implement EditorPlugin interface:
interface EditorPlugin {
initialize: (editor: Editor) => void;
dispose: () => void;
willHandleEventExclusively?: (event: PluginEvent) => boolean;
onPluginEvent?: (event: PluginEvent) => void;
}
There are 2 required methods to implement:
This is the first method that editor will call to a plugin when editor is initializing. It will pass in the editor instance, plugin should take this chance to save the editor reference so that it can call to any editor method or format API later.
Plugin can also do any other kind of initialization work here. Once this method is finished, it means the plugin is ready to handle any events from editor now.
This is the last method that editor will call to a plugin before it is disposed. Plugin can take this chance to clear the reference to editor. After this method is called, plugin should not call to any editor method since it will result in error.
It is a best practice to clear the editor reference here. Because inside a plugin it is possible to have some async functions, and when the async callback invoked it is possible that the editor is already disposed. Once editor reference is cleared in dispose method, async callback can check null for editor reference to determine if the async callback is still needed.
There are 2 more optional methods in EditorPlugin interface:
This is the core method for a plugin. Once an event happens in editor, editor will call this method of each plugin to handle the event as long as the event is not handled exclusively by another plugin (See willHandleEventExclusively method below). The methods will pass in an event object as parameter:
interface PluginEvent {
eventType: PluginEventType;
eventDataCache?: {
[key: string]: any;
};
}
And there are several sub type of this interface, such as PluginDomEvent
, ContentChangedEvent
, ... . Please see Plugin events for more information about events.
You can check the value of eventType property to know the type of this event, then cast it into related type then get more information from the sub type properties. In the example, it checks whether the event is a KeyPress
event, then cast it into PluginDomEvent
, which contains a rawEvent property -- the browser event object, and according to the type of event, it then cast the rawEvent object into a specific event type.
Sometimes a plugin wants to handle an event and don't allow other plugin to handle it. For example, some plugin would like to show some UI such as a picker when user types some special charactor. Once the picker is shown, the plugin will handle further keyboard events exclusively so that another plugin can't show another picker at the same time. To archieve this goal, plugin can inherit willHandleEventExclusively()
method, check the event whether it should be handled exclusively, then returns true. Once any plugin is returning true from willHandleEventExclusively()
, only this plugin will receive this event in onPluginEvent()
method and all other plugins will be ignored.
If two plugins will return true in willHandleEventExclusively()
for the same event, the final result depends on the order of the plugins are added into editor. For example:
let plugins = [ plugin1, plugin2 ];
let editor = createEditor(div, plugins);
If both plugin1 and plugin2 wants to handle a same event exclusively, only plugin1 will receive the event in onPluginEvent() method and plugin2 will be ignored since it is declared after plugin1.