import { Command, Mention, Plugin, Range, type Selectable } from "ckeditor5"; /** * Overrides the actions taken by the Mentions plugin (triggered by `@` in the text editor, or `~` & `#` in the attribute editor): * * - Auto-completes attributes and relations in the attribute editor. * - Triggers the modal to create notes. * - Inserts a reference link when a mention is selected. */ export default class MentionCustomization extends Plugin { static get requires() { return [ Mention ]; } afterInit() { const editor = this.editor; // override standard mention command (see https://github.com/ckeditor/ckeditor5/issues/6470) editor.commands.add('mention', new CustomMentionCommand(editor)); } } interface MentionOpts { mention: string | { id: string; [key: string]: unknown; }; marker: string; text?: string; range?: Range; } interface MentionAttribute { id: string; action?: "create-note"; noteTitle: string; notePath: string; } class CustomMentionCommand extends Command { override execute(options: MentionOpts) { const {model} = this.editor; const {document} = model; const {selection} = document; const mention = options.mention as unknown as MentionAttribute; const range = (options.range || selection.getFirstRange()) as Selectable; if (mention.id.startsWith('#') || mention.id.startsWith('~')) { model.change(writer => { // Replace a range with the text with a mention. model.insertContent( writer.createText( mention.id, {} ), range ); }); } else if (mention.action === 'create-note') { const editorEl = this.editor.editing.view.getDomRoot(); const component = glob.getComponentByEl(editorEl); component.createNoteForReferenceLink(mention.noteTitle).then(notePath => { this.insertReference(range, notePath); }); } else { this.insertReference(range, mention.notePath); } } insertReference(range: Selectable, notePath: string) { const {model} = this.editor; model.change(writer => { // override the selection or at least the beginning @ character model.insertContent(writer.createText('', {}), range); this.editor.execute('referenceLink', {href: '#' + notePath}); }); } }