mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	refactor(client): fix type errors related to CKEditor
This commit is contained in:
		| @@ -3,6 +3,7 @@ import appContext from "../components/app_context.js"; | |||||||
| import noteCreateService from "./note_create.js"; | import noteCreateService from "./note_create.js"; | ||||||
| import froca from "./froca.js"; | import froca from "./froca.js"; | ||||||
| import { t } from "./i18n.js"; | import { t } from "./i18n.js"; | ||||||
|  | import type { MentionFeedObjectItem } from "@triliumnext/ckeditor5"; | ||||||
|  |  | ||||||
| // this key needs to have this value, so it's hit by the tooltip | // this key needs to have this value, so it's hit by the tooltip | ||||||
| const SELECTED_NOTE_PATH_KEY = "data-note-path"; | const SELECTED_NOTE_PATH_KEY = "data-note-path"; | ||||||
| @@ -43,7 +44,7 @@ interface Options { | |||||||
| } | } | ||||||
|  |  | ||||||
| async function autocompleteSourceForCKEditor(queryText: string) { | async function autocompleteSourceForCKEditor(queryText: string) { | ||||||
|     return await new Promise<MentionItem[]>((res, rej) => { |     return await new Promise<MentionFeedObjectItem[]>((res, rej) => { | ||||||
|         autocompleteSource( |         autocompleteSource( | ||||||
|             queryText, |             queryText, | ||||||
|             (rows) => { |             (rows) => { | ||||||
|   | |||||||
							
								
								
									
										113
									
								
								apps/client/src/types.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										113
									
								
								apps/client/src/types.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -209,119 +209,6 @@ declare global { | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     interface Range { |  | ||||||
|         toJSON(): object; |  | ||||||
|         getItems(): TextNode[]; |  | ||||||
|     } |  | ||||||
|     interface Writer { |  | ||||||
|         setAttribute(name: string, value: string, el: CKNode); |  | ||||||
|         createPositionAt(el: CKNode, opt?: "end" | number); |  | ||||||
|         setSelection(pos: number, pos2?: number); |  | ||||||
|         insertText(text: string, opts: Record<string, unknown> | undefined | TextPosition, position?: TextPosition); |  | ||||||
|         addMarker(name: string, opts: { |  | ||||||
|             range: Range; |  | ||||||
|             usingOperation: boolean; |  | ||||||
|         }); |  | ||||||
|         removeMarker(name: string); |  | ||||||
|         createRange(start: number, end: number): Range; |  | ||||||
|         createElement(type: string, opts: Record<string, string | null | undefined>); |  | ||||||
|     } |  | ||||||
|     interface TextNode { |  | ||||||
|         previousSibling?: TextNode; |  | ||||||
|         name: string; |  | ||||||
|         data: string; |  | ||||||
|         startOffset: number; |  | ||||||
|         _attrs: { |  | ||||||
|             get(key: string): { |  | ||||||
|                 length: number |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     interface TextPosition { |  | ||||||
|         textNode: TextNode; |  | ||||||
|         offset: number; |  | ||||||
|         compareWith(pos: TextPosition): string; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     interface TextRange { |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     interface Marker { |  | ||||||
|         name: string; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     interface CKNode { |  | ||||||
|         _children: CKNode[]; |  | ||||||
|         name: string; |  | ||||||
|         childCount: number; |  | ||||||
|         isEmpty: boolean; |  | ||||||
|         toJSON(): object; |  | ||||||
|         is(type: string, name?: string); |  | ||||||
|         getAttribute(name: string): string; |  | ||||||
|         getChild(index: number): CKNode; |  | ||||||
|         data: string; |  | ||||||
|         startOffset: number; |  | ||||||
|         root: { |  | ||||||
|             document: { |  | ||||||
|                 model: { |  | ||||||
|                     createRangeIn(el: CKNode): TextRange; |  | ||||||
|                     markers: { |  | ||||||
|                         getMarkersIntersectingRange(range: TextRange): Marker[]; |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     interface CKEvent { |  | ||||||
|         stop(): void; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     interface PluginEventData { |  | ||||||
|         title: string; |  | ||||||
|         message: { |  | ||||||
|             message: string; |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     interface EditingState { |  | ||||||
|         highlightedResult: string; |  | ||||||
|         results: unknown[]; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     interface CKFindResult { |  | ||||||
|         results: { |  | ||||||
|             get(number): { |  | ||||||
|                 marker: { |  | ||||||
|                     getStart(): TextPosition; |  | ||||||
|                     getRange(): number; |  | ||||||
|                 }; |  | ||||||
|             } |  | ||||||
|         } & []; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     interface MentionItem { |  | ||||||
|         action?: string; |  | ||||||
|         noteTitle?: string; |  | ||||||
|         id: string; |  | ||||||
|         name: string; |  | ||||||
|         link?: string; |  | ||||||
|         notePath?: string; |  | ||||||
|         highlightedNotePathTitle?: string; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     interface MentionConfig { |  | ||||||
|         feeds: { |  | ||||||
|             marker: string; |  | ||||||
|             feed: (queryText: string) => MentionItem[] | Promise<MentionItem[]>; |  | ||||||
|             itemRenderer?: (item: { |  | ||||||
|                 highlightedNotePathTitle: string |  | ||||||
|             }) => void; |  | ||||||
|             minimumCharacters: number; |  | ||||||
|         }[]; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /* |     /* | ||||||
|      * Panzoom |      * Panzoom | ||||||
|      */ |      */ | ||||||
|   | |||||||
| @@ -1,10 +1,10 @@ | |||||||
| import { t } from "../../services/i18n.js"; | import { t } from "../../services/i18n.js"; | ||||||
| import NoteContextAwareWidget from "../note_context_aware_widget.js"; | import NoteContextAwareWidget from "../note_context_aware_widget.js"; | ||||||
| import noteAutocompleteService from "../../services/note_autocomplete.js"; | import noteAutocompleteService, { type Suggestion } from "../../services/note_autocomplete.js"; | ||||||
| import server from "../../services/server.js"; | import server from "../../services/server.js"; | ||||||
| import contextMenuService from "../../menus/context_menu.js"; | import contextMenuService from "../../menus/context_menu.js"; | ||||||
| import attributeParser, { type Attribute } from "../../services/attribute_parser.js"; | import attributeParser, { type Attribute } from "../../services/attribute_parser.js"; | ||||||
| import { AttributeEditor } from "@triliumnext/ckeditor5"; | import { AttributeEditor, type EditorConfig, type Element, type MentionFeed, type Node, type Position } from "@triliumnext/ckeditor5"; | ||||||
| import froca from "../../services/froca.js"; | import froca from "../../services/froca.js"; | ||||||
| import attributeRenderer from "../../services/attribute_renderer.js"; | import attributeRenderer from "../../services/attribute_renderer.js"; | ||||||
| import noteCreateService from "../../services/note_create.js"; | import noteCreateService from "../../services/note_create.js"; | ||||||
| @@ -84,57 +84,58 @@ const TPL = /*html*/` | |||||||
| </div> | </div> | ||||||
| `; | `; | ||||||
|  |  | ||||||
| const mentionSetup: MentionConfig = { | const mentionSetup: MentionFeed[] = [ | ||||||
|     feeds: [ |     { | ||||||
|         { |         marker: "@", | ||||||
|             marker: "@", |         feed: (queryText) => noteAutocompleteService.autocompleteSourceForCKEditor(queryText), | ||||||
|             feed: (queryText) => noteAutocompleteService.autocompleteSourceForCKEditor(queryText), |         itemRenderer: (_item) => { | ||||||
|             itemRenderer: (item) => { |             const item = _item as Suggestion; | ||||||
|                 const itemElement = document.createElement("button"); |             const itemElement = document.createElement("button"); | ||||||
|  |  | ||||||
|                 itemElement.innerHTML = `${item.highlightedNotePathTitle} `; |             itemElement.innerHTML = `${item.highlightedNotePathTitle} `; | ||||||
|  |  | ||||||
|                 return itemElement; |             return itemElement; | ||||||
|             }, |  | ||||||
|             minimumCharacters: 0 |  | ||||||
|         }, |         }, | ||||||
|         { |         minimumCharacters: 0 | ||||||
|             marker: "#", |     }, | ||||||
|             feed: async (queryText) => { |     { | ||||||
|                 const names = await server.get<string[]>(`attribute-names/?type=label&query=${encodeURIComponent(queryText)}`); |         marker: "#", | ||||||
|  |         feed: async (queryText) => { | ||||||
|  |             const names = await server.get<string[]>(`attribute-names/?type=label&query=${encodeURIComponent(queryText)}`); | ||||||
|  |  | ||||||
|                 return names.map((name) => { |             return names.map((name) => { | ||||||
|                     return { |                 return { | ||||||
|                         id: `#${name}`, |                     id: `#${name}`, | ||||||
|                         name: name |                     name: name | ||||||
|                     }; |                 }; | ||||||
|                 }); |             }); | ||||||
|             }, |  | ||||||
|             minimumCharacters: 0 |  | ||||||
|         }, |         }, | ||||||
|         { |         minimumCharacters: 0 | ||||||
|             marker: "~", |     }, | ||||||
|             feed: async (queryText) => { |     { | ||||||
|                 const names = await server.get<string[]>(`attribute-names/?type=relation&query=${encodeURIComponent(queryText)}`); |         marker: "~", | ||||||
|  |         feed: async (queryText) => { | ||||||
|  |             const names = await server.get<string[]>(`attribute-names/?type=relation&query=${encodeURIComponent(queryText)}`); | ||||||
|  |  | ||||||
|                 return names.map((name) => { |             return names.map((name) => { | ||||||
|                     return { |                 return { | ||||||
|                         id: `~${name}`, |                     id: `~${name}`, | ||||||
|                         name: name |                     name: name | ||||||
|                     }; |                 }; | ||||||
|                 }); |             }); | ||||||
|             }, |         }, | ||||||
|             minimumCharacters: 0 |         minimumCharacters: 0 | ||||||
|         } |     } | ||||||
|     ] | ]; | ||||||
| }; |  | ||||||
|  |  | ||||||
| const editorConfig = { | const editorConfig: EditorConfig = { | ||||||
|     toolbar: { |     toolbar: { | ||||||
|         items: [] |         items: [] | ||||||
|     }, |     }, | ||||||
|     placeholder: t("attribute_editor.placeholder"), |     placeholder: t("attribute_editor.placeholder"), | ||||||
|     mention: mentionSetup, |     mention: { | ||||||
|  |         feeds: mentionSetup | ||||||
|  |     }, | ||||||
|     licenseKey: "GPL" |     licenseKey: "GPL" | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -334,7 +335,10 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget implem | |||||||
|         ); |         ); | ||||||
|  |  | ||||||
|         // disable spellcheck for attribute editor |         // disable spellcheck for attribute editor | ||||||
|         this.textEditor.editing.view.change((writer) => writer.setAttribute("spellcheck", "false", this.textEditor.editing.view.document.getRoot())); |         const documentRoot = this.textEditor.editing.view.document.getRoot(); | ||||||
|  |         if (documentRoot) { | ||||||
|  |             this.textEditor.editing.view.change((writer) => writer.setAttribute("spellcheck", "false", documentRoot)); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     dataChanged() { |     dataChanged() { | ||||||
| @@ -411,18 +415,18 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget implem | |||||||
|         this.$editor.tooltip("show"); |         this.$editor.tooltip("show"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     getClickIndex(pos: TextPosition) { |     getClickIndex(pos: Position) { | ||||||
|         let clickIndex = pos.offset - pos.textNode.startOffset; |         let clickIndex = pos.offset - (pos.textNode?.startOffset ?? 0); | ||||||
|  |  | ||||||
|         let curNode = pos.textNode; |         let curNode: Node | Text | Element | null = pos.textNode; | ||||||
|  |  | ||||||
|         while (curNode.previousSibling) { |         while (curNode?.previousSibling) { | ||||||
|             curNode = curNode.previousSibling; |             curNode = curNode.previousSibling; | ||||||
|  |  | ||||||
|             if (curNode.name === "reference") { |             if ((curNode as Element).name === "reference") { | ||||||
|                 clickIndex += curNode._attrs.get("notePath").length + 1; |                 clickIndex += (curNode.getAttribute("notePath") as string).length + 1; | ||||||
|             } else { |             } else if ("data" in curNode) { | ||||||
|                 clickIndex += curNode.data.length; |                 clickIndex += (curNode.data as string).length; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -480,8 +484,12 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget implem | |||||||
|         this.$editor.trigger("focus"); |         this.$editor.trigger("focus"); | ||||||
|  |  | ||||||
|         this.textEditor.model.change((writer) => { |         this.textEditor.model.change((writer) => { | ||||||
|             const positionAt = writer.createPositionAt(this.textEditor.model.document.getRoot(), "end"); |             const documentRoot = this.textEditor.editing.model.document.getRoot(); | ||||||
|  |             if (!documentRoot) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             const positionAt = writer.createPositionAt(documentRoot, "end"); | ||||||
|             writer.setSelection(positionAt); |             writer.setSelection(positionAt); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | import type { FindAndReplaceState, FindCommandResult } from "@triliumnext/ckeditor5"; | ||||||
| import type { FindResult } from "./find.js"; | import type { FindResult } from "./find.js"; | ||||||
| import type FindWidget from "./find.js"; | import type FindWidget from "./find.js"; | ||||||
|  |  | ||||||
| @@ -14,8 +15,8 @@ interface Match { | |||||||
| export default class FindInText { | export default class FindInText { | ||||||
|  |  | ||||||
|     private parent: FindWidget; |     private parent: FindWidget; | ||||||
|     private findResult?: CKFindResult | null; |     private findResult?: FindCommandResult | null; | ||||||
|     private editingState?: EditingState; |     private editingState?: FindAndReplaceState; | ||||||
|  |  | ||||||
|     constructor(parent: FindWidget) { |     constructor(parent: FindWidget) { | ||||||
|         this.parent = parent; |         this.parent = parent; | ||||||
| @@ -40,7 +41,7 @@ export default class FindInText { | |||||||
|  |  | ||||||
|         // Clear |         // Clear | ||||||
|         const findAndReplaceEditing = textEditor.plugins.get("FindAndReplaceEditing"); |         const findAndReplaceEditing = textEditor.plugins.get("FindAndReplaceEditing"); | ||||||
|         findAndReplaceEditing.state.clear(model); |         findAndReplaceEditing.state?.clear(model); | ||||||
|         findAndReplaceEditing.stop(); |         findAndReplaceEditing.stop(); | ||||||
|         this.editingState = findAndReplaceEditing.state; |         this.editingState = findAndReplaceEditing.state; | ||||||
|         if (searchTerm !== "") { |         if (searchTerm !== "") { | ||||||
| @@ -52,14 +53,14 @@ export default class FindInText { | |||||||
|             // let m = text.match(re); |             // let m = text.match(re); | ||||||
|             // totalFound = m ? m.length : 0; |             // totalFound = m ? m.length : 0; | ||||||
|             const options = { matchCase: matchCase, wholeWords: wholeWord }; |             const options = { matchCase: matchCase, wholeWords: wholeWord }; | ||||||
|             findResult = textEditor.execute<CKFindResult>("find", searchTerm, options); |             findResult = textEditor.execute("find", searchTerm, options); | ||||||
|             totalFound = findResult.results.length; |             totalFound = findResult.results.length; | ||||||
|             // Find the result beyond the cursor |             // Find the result beyond the cursor | ||||||
|             const cursorPos = model.document.selection.getLastPosition(); |             const cursorPos = model.document.selection.getLastPosition(); | ||||||
|             for (let i = 0; i < findResult.results.length; ++i) { |             for (let i = 0; i < findResult.results.length; ++i) { | ||||||
|                 const marker = findResult.results.get(i).marker; |                 const marker = findResult.results.get(i)?.marker; | ||||||
|                 const fromPos = marker.getStart(); |                 const fromPos = marker?.getStart(); | ||||||
|                 if (cursorPos && fromPos.compareWith(cursorPos) !== "before") { |                 if (cursorPos && fromPos && fromPos.compareWith(cursorPos) !== "before") { | ||||||
|                     currentFound = i; |                     currentFound = i; | ||||||
|                     break; |                     break; | ||||||
|                 } |                 } | ||||||
| @@ -75,7 +76,7 @@ export default class FindInText { | |||||||
|             // XXX Do this accessing the private data? |             // XXX Do this accessing the private data? | ||||||
|             // See https://github.com/ckeditor/ckeditor5/blob/b95e2faf817262ac0e1e21993d9c0bde3f1be594/packages/ckeditor5-find-and-replace/src/findnextcommand.js |             // See https://github.com/ckeditor/ckeditor5/blob/b95e2faf817262ac0e1e21993d9c0bde3f1be594/packages/ckeditor5-find-and-replace/src/findnextcommand.js | ||||||
|             for (let i = 0; i < currentFound; ++i) { |             for (let i = 0; i < currentFound; ++i) { | ||||||
|                 textEditor?.execute("findNext", searchTerm); |                 textEditor?.execute("findNext"); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -109,17 +110,17 @@ export default class FindInText { | |||||||
|             // Clear the markers and set the caret to the |             // Clear the markers and set the caret to the | ||||||
|             // current occurrence |             // current occurrence | ||||||
|             const model = textEditor.model; |             const model = textEditor.model; | ||||||
|             const range = this.findResult?.results?.get(currentFound).marker.getRange(); |             const range = this.findResult?.results?.get(currentFound)?.marker?.getRange(); | ||||||
|             // From |             // From | ||||||
|             // https://github.com/ckeditor/ckeditor5/blob/b95e2faf817262ac0e1e21993d9c0bde3f1be594/packages/ckeditor5-find-and-replace/src/findandreplace.js#L92 |             // https://github.com/ckeditor/ckeditor5/blob/b95e2faf817262ac0e1e21993d9c0bde3f1be594/packages/ckeditor5-find-and-replace/src/findandreplace.js#L92 | ||||||
|             // XXX Roll our own since already done for codeEditor and |             // XXX Roll our own since already done for codeEditor and | ||||||
|             //     will probably allow more refactoring? |             //     will probably allow more refactoring? | ||||||
|             let findAndReplaceEditing = textEditor.plugins.get("FindAndReplaceEditing"); |             let findAndReplaceEditing = textEditor.plugins.get("FindAndReplaceEditing"); | ||||||
|             findAndReplaceEditing.state.clear(model); |             findAndReplaceEditing.state?.clear(model); | ||||||
|             findAndReplaceEditing.stop(); |             findAndReplaceEditing.stop(); | ||||||
|             if (range) { |             if (range) { | ||||||
|                 model.change((writer) => { |                 model.change((writer) => { | ||||||
|                     writer.setSelection(range, 0); |                     writer.setSelection(range); | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
|             textEditor.editing.view.scrollToTheSelection(); |             textEditor.editing.view.scrollToTheSelection(); | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| import { t } from "../../services/i18n.js"; | import { t } from "../../services/i18n.js"; | ||||||
| import libraryLoader from "../../services/library_loader.js"; | import libraryLoader from "../../services/library_loader.js"; | ||||||
| import noteAutocompleteService from "../../services/note_autocomplete.js"; | import noteAutocompleteService, { type Suggestion } from "../../services/note_autocomplete.js"; | ||||||
| import mimeTypesService from "../../services/mime_types.js"; | import mimeTypesService from "../../services/mime_types.js"; | ||||||
| import utils, { hasTouchBar } from "../../services/utils.js"; | import utils, { hasTouchBar } from "../../services/utils.js"; | ||||||
| import keyboardActionService from "../../services/keyboard_actions.js"; | import keyboardActionService from "../../services/keyboard_actions.js"; | ||||||
| @@ -17,27 +17,25 @@ import { buildSelectedBackgroundColor } from "../../components/touch_bar.js"; | |||||||
| import { buildConfig, buildToolbarConfig } from "./ckeditor/config.js"; | import { buildConfig, buildToolbarConfig } from "./ckeditor/config.js"; | ||||||
| import type FNote from "../../entities/fnote.js"; | import type FNote from "../../entities/fnote.js"; | ||||||
| import { getMermaidConfig } from "../../services/mermaid.js"; | import { getMermaidConfig } from "../../services/mermaid.js"; | ||||||
| import { PopupEditor, ClassicEditor, EditorWatchdog, type CKTextEditor } from "@triliumnext/ckeditor5"; | import { PopupEditor, ClassicEditor, EditorWatchdog, type CKTextEditor, type MentionFeed, type WatchdogConfig } from "@triliumnext/ckeditor5"; | ||||||
| import "@triliumnext/ckeditor5/index.css"; | import "@triliumnext/ckeditor5/index.css"; | ||||||
|  |  | ||||||
| const ENABLE_INSPECTOR = false; | const ENABLE_INSPECTOR = false; | ||||||
|  |  | ||||||
| const mentionSetup: MentionConfig = { | const mentionSetup: MentionFeed[] = [ | ||||||
|     feeds: [ |     { | ||||||
|         { |         marker: "@", | ||||||
|             marker: "@", |         feed: (queryText: string) => noteAutocompleteService.autocompleteSourceForCKEditor(queryText), | ||||||
|             feed: (queryText: string) => noteAutocompleteService.autocompleteSourceForCKEditor(queryText), |         itemRenderer: (item) => { | ||||||
|             itemRenderer: (item) => { |             const itemElement = document.createElement("button"); | ||||||
|                 const itemElement = document.createElement("button"); |  | ||||||
|  |  | ||||||
|                 itemElement.innerHTML = `${item.highlightedNotePathTitle} `; |             itemElement.innerHTML = `${(item as Suggestion).highlightedNotePathTitle} `; | ||||||
|  |  | ||||||
|                 return itemElement; |             return itemElement; | ||||||
|             }, |         }, | ||||||
|             minimumCharacters: 0 |         minimumCharacters: 0 | ||||||
|         } |     } | ||||||
|     ] | ]; | ||||||
| }; |  | ||||||
|  |  | ||||||
| const TPL = /*html*/` | const TPL = /*html*/` | ||||||
| <div class="note-detail-editable-text note-detail-printable"> | <div class="note-detail-editable-text note-detail-printable"> | ||||||
| @@ -128,7 +126,7 @@ function buildListOfLanguages() { | |||||||
| export default class EditableTextTypeWidget extends AbstractTextTypeWidget { | export default class EditableTextTypeWidget extends AbstractTextTypeWidget { | ||||||
|  |  | ||||||
|     private contentLanguage?: string | null; |     private contentLanguage?: string | null; | ||||||
|     private watchdog!: EditorWatchdog<CKTextEditor>; |     private watchdog!: EditorWatchdog<ClassicEditor | PopupEditor>; | ||||||
|  |  | ||||||
|     private $editor!: JQuery<HTMLElement>; |     private $editor!: JQuery<HTMLElement>; | ||||||
|  |  | ||||||
| @@ -158,7 +156,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { | |||||||
|         // display of $widget in both branches. |         // display of $widget in both branches. | ||||||
|         this.$widget.show(); |         this.$widget.show(); | ||||||
|  |  | ||||||
|         this.watchdog = new EditorWatchdog<CKTextEditor>(editorClass, { |         const config: WatchdogConfig = { | ||||||
|             // An average number of milliseconds between the last editor errors (defaults to 5000). |             // An average number of milliseconds between the last editor errors (defaults to 5000). | ||||||
|             // When the period of time between errors is lower than that and the crashNumberLimit |             // When the period of time between errors is lower than that and the crashNumberLimit | ||||||
|             // is also reached, the watchdog changes its state to crashedPermanently, and it stops |             // is also reached, the watchdog changes its state to crashedPermanently, and it stops | ||||||
| @@ -173,7 +171,8 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { | |||||||
|             // A minimum number of milliseconds between saving the editor data internally (defaults to 5000). |             // A minimum number of milliseconds between saving the editor data internally (defaults to 5000). | ||||||
|             // Note that for large documents, this might impact the editor performance. |             // Note that for large documents, this might impact the editor performance. | ||||||
|             saveInterval: 5000 |             saveInterval: 5000 | ||||||
|         }); |         }; | ||||||
|  |         this.watchdog = isClassicEditor ? new EditorWatchdog(ClassicEditor, config) : new EditorWatchdog(PopupEditor, config); | ||||||
|  |  | ||||||
|         this.watchdog.on("stateChange", () => { |         this.watchdog.on("stateChange", () => { | ||||||
|             const currentState = this.watchdog.state; |             const currentState = this.watchdog.state; | ||||||
| @@ -226,7 +225,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { | |||||||
|             const editor = await editorClass.create(elementOrData, finalConfig); |             const editor = await editorClass.create(elementOrData, finalConfig); | ||||||
|  |  | ||||||
|             const notificationsPlugin = editor.plugins.get("Notification"); |             const notificationsPlugin = editor.plugins.get("Notification"); | ||||||
|             notificationsPlugin.on("show:warning", (evt: CKEvent, data: PluginEventData) => { |             notificationsPlugin.on("show:warning", (evt, data) => { | ||||||
|                 const title = data.title; |                 const title = data.title; | ||||||
|                 const message = data.message.message; |                 const message = data.message.message; | ||||||
|  |  | ||||||
| @@ -447,10 +446,10 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (callback) { |         if (callback) { | ||||||
|             callback(this.watchdog.editor); |             callback(this.watchdog.editor as CKTextEditor); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         resolve(this.watchdog.editor); |         resolve(this.watchdog.editor as CKTextEditor); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     addLinkToTextCommand() { |     addLinkToTextCommand() { | ||||||
|   | |||||||
| @@ -1,7 +1,8 @@ | |||||||
| import "ckeditor5/ckeditor5.css"; | import "ckeditor5/ckeditor5.css"; | ||||||
| import { COMMON_PLUGINS, CORE_PLUGINS, POPUP_EDITOR_PLUGINS } from "./plugins"; | import { COMMON_PLUGINS, CORE_PLUGINS, POPUP_EDITOR_PLUGINS } from "./plugins"; | ||||||
| import { BalloonEditor, DecoupledEditor } from "ckeditor5"; | import { BalloonEditor, DecoupledEditor, FindAndReplaceEditing, FindCommand } from "ckeditor5"; | ||||||
| export { EditorWatchdog } from "ckeditor5"; | export { EditorWatchdog } from "ckeditor5"; | ||||||
|  | export type { EditorConfig, MentionFeed, MentionFeedObjectItem, Node, Position, Element, WatchdogConfig } from "ckeditor5"; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Short-hand for the CKEditor classes supported by Trilium for text editing. |  * Short-hand for the CKEditor classes supported by Trilium for text editing. | ||||||
| @@ -12,6 +13,9 @@ export type CKTextEditor = (ClassicEditor | PopupEditor) & { | |||||||
|     removeSelection(): Promise<void>; |     removeSelection(): Promise<void>; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | export type FindAndReplaceState = FindAndReplaceEditing["state"]; | ||||||
|  | export type FindCommandResult = ReturnType<FindCommand["execute"]>; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * The text editor that can be used for editing attributes and relations. |  * The text editor that can be used for editing attributes and relations. | ||||||
|  */ |  */ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user