mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 19:49:01 +01:00 
			
		
		
		
	Slash commands (#2336)
This commit is contained in:
		
						commit
						3b579a3b7b
					
				
							
								
								
									
										6
									
								
								apps/client/.env.development
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								apps/client/.env.development
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | VITE_CKEDITOR_ENABLE_INSPECTOR=false | ||||||
|  | 
 | ||||||
|  | # The development license key for premium CKEditor features. | ||||||
|  | # Note: This key is for development purposes only and should not be used in production. | ||||||
|  | # Expires on: 2025-09-13 | ||||||
|  | VITE_CKEDITOR_KEY=eyJhbGciOiJFUzI1NiJ9.eyJleHAiOjE3NTc3MjE1OTksImp0aSI6IjRmMjdkYmYxLTcwOTEtNDYwZi04ZDZmLTc0NzBiZjQwNjg2MCIsImRpc3RyaWJ1dGlvbkNoYW5uZWwiOlsic2giLCJkcnVwYWwiXSwid2hpdGVMYWJlbCI6dHJ1ZSwibGljZW5zZVR5cGUiOiJkZXZlbG9wbWVudCIsImZlYXR1cmVzIjpbIkRSVVAiLCJDTVQiLCJETyIsIkZQIiwiU0MiLCJUT0MiLCJUUEwiLCJQT0UiLCJDQyIsIk1GIiwiU0VFIiwiRUNIIiwiRUlTIl0sInZjIjoiMjMxYzMwNTEifQ.9Ct5lIKbioC3dM8EFatDTmimEIVOdItE3Uh_ICHlS_A_8ueqIfkZpsN3L4_EqprvteNki9yqbuZVGpZTaQ51xg | ||||||
							
								
								
									
										1
									
								
								apps/client/.env.production
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								apps/client/.env.production
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | VITE_CKEDITOR_ENABLE_INSPECTOR=false | ||||||
| @ -332,8 +332,6 @@ async function openDialog($dialog: JQuery<HTMLElement>, closeActDialog = true) { | |||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     // TODO: Fix once keyboard_actions is ported.
 |  | ||||||
|     // @ts-ignore
 |  | ||||||
|     const keyboardActionsService = (await import("./keyboard_actions.js")).default; |     const keyboardActionsService = (await import("./keyboard_actions.js")).default; | ||||||
|     keyboardActionsService.updateDisplayedShortcuts($dialog); |     keyboardActionsService.updateDisplayedShortcuts($dialog); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -25,6 +25,7 @@ | |||||||
|     --bs-body-font-weight: var(--main-font-weight) !important; |     --bs-body-font-weight: var(--main-font-weight) !important; | ||||||
|     --bs-body-color: var(--main-text-color) !important; |     --bs-body-color: var(--main-text-color) !important; | ||||||
|     --bs-body-bg: var(--main-background-color) !important;     |     --bs-body-bg: var(--main-background-color) !important;     | ||||||
|  |     --ck-mention-list-max-height: 500px; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .table { | .table { | ||||||
| @ -1273,6 +1274,26 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu { | |||||||
|     white-space: normal !important; |     white-space: normal !important; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /* Slash commands */ | ||||||
|  | 
 | ||||||
|  | .ck.ck-slash-command-button { | ||||||
|  |     padding: 0.5em 1em !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ck.ck-slash-command-button__text-part { | ||||||
|  |     margin-left: 0.5em; | ||||||
|  |     line-height: 1.2em !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ck.ck-slash-command-button__text-part > span { | ||||||
|  |     line-height: inherit !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .ck.ck-slash-command-button__text-part .ck.ck-slash-command-button__description { | ||||||
|  |     display: block; | ||||||
|  |     opacity: 0.8; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .area-expander { | .area-expander { | ||||||
|     display: flex; |     display: flex; | ||||||
|     flex-direction: row; |     flex-direction: row; | ||||||
|  | |||||||
| @ -201,6 +201,11 @@ | |||||||
|     color: var(--menu-item-icon-color); |     color: var(--menu-item-icon-color); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /* Slash commands */ | ||||||
|  | .ck.ck-slash-command-button__text-part .ck.ck-button__label { | ||||||
|  |     font-weight: bold; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* Separator */ | /* Separator */ | ||||||
| :root .ck .ck-list__separator { | :root .ck .ck-list__separator { | ||||||
|     margin: .5em 0; |     margin: .5em 0; | ||||||
|  | |||||||
							
								
								
									
										16
									
								
								apps/client/src/vite-env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								apps/client/src/vite-env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | /// <reference types="vite/client" />
 | ||||||
|  | 
 | ||||||
|  | interface ViteTypeOptions { | ||||||
|  |   strictImportMetaEnv: unknown | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | interface ImportMetaEnv { | ||||||
|  |     /** The license key for CKEditor premium features. */ | ||||||
|  |     readonly VITE_CKEDITOR_KEY?: string; | ||||||
|  |     /** Whether to enable the CKEditor inspector (see https://ckeditor.com/docs/ckeditor5/latest/framework/develpment-tools/inspector.html). */ | ||||||
|  |     readonly VITE_CKEDITOR_ENABLE_INSPECTOR?: "true" | "false"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | interface ImportMeta { | ||||||
|  |   readonly env: ImportMetaEnv | ||||||
|  | } | ||||||
| @ -111,7 +111,7 @@ export default class AddLinkDialog extends BasicWidget { | |||||||
| 
 | 
 | ||||||
|         this.updateTitleSettingsVisibility(); |         this.updateTitleSettingsVisibility(); | ||||||
| 
 | 
 | ||||||
|         utils.openDialog(this.$widget); |         await utils.openDialog(this.$widget); | ||||||
| 
 | 
 | ||||||
|         this.$autoComplete.val(""); |         this.$autoComplete.val(""); | ||||||
|         this.$linkTitle.val(""); |         this.$linkTitle.val(""); | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| import { ALLOWED_PROTOCOLS } from "../../../services/link.js"; | import { ALLOWED_PROTOCOLS } from "../../../services/link.js"; | ||||||
| import { MIME_TYPE_AUTO } from "@triliumnext/commons"; | import { MIME_TYPE_AUTO } from "@triliumnext/commons"; | ||||||
| import type { EditorConfig } from "@triliumnext/ckeditor5"; | import { buildExtraCommands, type EditorConfig } from "@triliumnext/ckeditor5"; | ||||||
| import { getHighlightJsNameForMime } from "../../../services/mime_types.js"; | import { getHighlightJsNameForMime } from "../../../services/mime_types.js"; | ||||||
| import options from "../../../services/options.js"; | import options from "../../../services/options.js"; | ||||||
| import { ensureMimeTypesForHighlighting, isSyntaxHighlightEnabled } from "../../../services/syntax_highlight.js"; | import { ensureMimeTypesForHighlighting, isSyntaxHighlightEnabled } from "../../../services/syntax_highlight.js"; | ||||||
| @ -121,6 +121,11 @@ export function buildConfig(): EditorConfig { | |||||||
|         clipboard: { |         clipboard: { | ||||||
|             copy: copyTextWithToast |             copy: copyTextWithToast | ||||||
|         }, |         }, | ||||||
|  |         slashCommand: { | ||||||
|  |             removeCommands: [], | ||||||
|  |             dropdownLimit: Number.MAX_SAFE_INTEGER, | ||||||
|  |             extraCommands: buildExtraCommands() | ||||||
|  |         }, | ||||||
|         // This value must be kept in sync with the language defined in webpack.config.js.
 |         // This value must be kept in sync with the language defined in webpack.config.js.
 | ||||||
|         language: "en" |         language: "en" | ||||||
|     }; |     }; | ||||||
|  | |||||||
| @ -19,8 +19,6 @@ import { PopupEditor, ClassicEditor, EditorWatchdog, type CKTextEditor, type Men | |||||||
| import "@triliumnext/ckeditor5/index.css"; | import "@triliumnext/ckeditor5/index.css"; | ||||||
| import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons"; | import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons"; | ||||||
| 
 | 
 | ||||||
| const ENABLE_INSPECTOR = false; |  | ||||||
| 
 |  | ||||||
| const mentionSetup: MentionFeed[] = [ | const mentionSetup: MentionFeed[] = [ | ||||||
|     { |     { | ||||||
|         marker: "@", |         marker: "@", | ||||||
| @ -203,7 +201,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { | |||||||
|                     classes: true, |                     classes: true, | ||||||
|                     attributes: true |                     attributes: true | ||||||
|                 }, |                 }, | ||||||
|                 licenseKey: "GPL" |                 licenseKey: getLicenseKey() | ||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|             const contentLanguage = this.note?.getLabelValue("language"); |             const contentLanguage = this.note?.getLabelValue("language"); | ||||||
| @ -278,7 +276,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { | |||||||
| 
 | 
 | ||||||
|             editor.model.document.on("change:data", () => this.spacedUpdate.scheduleUpdate()); |             editor.model.document.on("change:data", () => this.spacedUpdate.scheduleUpdate()); | ||||||
| 
 | 
 | ||||||
|             if (glob.isDev && ENABLE_INSPECTOR) { |             if (import.meta.env.VITE_CKEDITOR_ENABLE_INSPECTOR === "true") { | ||||||
|                 const CKEditorInspector = (await import("@ckeditor/ckeditor5-inspector")).default; |                 const CKEditorInspector = (await import("@ckeditor/ckeditor5-inspector")).default; | ||||||
|                 CKEditorInspector.attach(editor); |                 CKEditorInspector.attach(editor); | ||||||
|             } |             } | ||||||
| @ -640,3 +638,13 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | function getLicenseKey() { | ||||||
|  |     const premiumLicenseKey = import.meta.env.VITE_CKEDITOR_KEY; | ||||||
|  |     if (!premiumLicenseKey) { | ||||||
|  |         logError("CKEditor license key is not set, premium features will not be available."); | ||||||
|  |         return "GPL"; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return premiumLicenseKey; | ||||||
|  | } | ||||||
|  | |||||||
| @ -4,9 +4,9 @@ import "../theme/blockquote.css"; | |||||||
| 
 | 
 | ||||||
| export { default as Admonition } from './admonition.js'; | export { default as Admonition } from './admonition.js'; | ||||||
| export { default as AdmonitionEditing } from './admonitionediting.js'; | export { default as AdmonitionEditing } from './admonitionediting.js'; | ||||||
| export { default as AdmonitionUI } from './admonitionui.js'; | export { default as AdmonitionUI, ADMONITION_TYPES } from './admonitionui.js'; | ||||||
| export { default as AdmonitionAutoformat } from './admonitionautoformat.js'; | export { default as AdmonitionAutoformat } from './admonitionautoformat.js'; | ||||||
| export type { default as AdmonitionCommand } from './admonitioncommand.js'; | export type { default as AdmonitionCommand, AdmonitionType } from './admonitioncommand.js'; | ||||||
| 
 | 
 | ||||||
| export const icons = { | export const icons = { | ||||||
| 	admonitionIcon | 	admonitionIcon | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ import './augmentation.js'; | |||||||
| import "../theme/mathform.css"; | import "../theme/mathform.css"; | ||||||
| 
 | 
 | ||||||
| export { default as Math } from './math.js'; | export { default as Math } from './math.js'; | ||||||
|  | export { default as MathUI } from './mathui.js'; | ||||||
| export { default as AutoformatMath } from './autoformatmath.js'; | export { default as AutoformatMath } from './autoformatmath.js'; | ||||||
| 
 | 
 | ||||||
| export const icons = { | export const icons = { | ||||||
|  | |||||||
| @ -23,17 +23,20 @@ | |||||||
|     "name": "ckeditor5", |     "name": "ckeditor5", | ||||||
|     "targets": { |     "targets": { | ||||||
|       "typecheck": { |       "typecheck": { | ||||||
|         "dependsOn": [ "^build" ] |         "dependsOn": [ | ||||||
|  |           "^build" | ||||||
|  |         ] | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "ckeditor5": "45.2.0", |  | ||||||
|     "@triliumnext/ckeditor5-keyboard-marker": "workspace:*", |  | ||||||
|     "@triliumnext/ckeditor5-mermaid": "workspace:*", |  | ||||||
|     "@triliumnext/ckeditor5-admonition": "workspace:*", |     "@triliumnext/ckeditor5-admonition": "workspace:*", | ||||||
|     "@triliumnext/ckeditor5-footnotes": "workspace:*", |     "@triliumnext/ckeditor5-footnotes": "workspace:*", | ||||||
|     "@triliumnext/ckeditor5-math": "workspace:*" |     "@triliumnext/ckeditor5-keyboard-marker": "workspace:*", | ||||||
|  |     "@triliumnext/ckeditor5-math": "workspace:*", | ||||||
|  |     "@triliumnext/ckeditor5-mermaid": "workspace:*", | ||||||
|  |     "ckeditor5": "45.2.0", | ||||||
|  |     "ckeditor5-premium-features": "45.2.0" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@types/jquery": "3.5.32" |     "@types/jquery": "3.5.32" | ||||||
|  | |||||||
							
								
								
									
										139
									
								
								packages/ckeditor5/src/extra_slash_commands.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								packages/ckeditor5/src/extra_slash_commands.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,139 @@ | |||||||
|  | import type { Editor } from 'ckeditor5'; | ||||||
|  | import type { SlashCommandEditorConfig  } from 'ckeditor5-premium-features'; | ||||||
|  | import { icons as footnoteIcons } from '@triliumnext/ckeditor5-footnotes'; | ||||||
|  | import IconPageBreak from "@ckeditor/ckeditor5-icons/theme/icons/page-break.svg?raw"; | ||||||
|  | import IconAlignLeft from "@ckeditor/ckeditor5-icons/theme/icons/align-left.svg?raw"; | ||||||
|  | import IconAlignCenter from "@ckeditor/ckeditor5-icons/theme/icons/align-center.svg?raw"; | ||||||
|  | import IconAlignRight from "@ckeditor/ckeditor5-icons/theme/icons/align-right.svg?raw"; | ||||||
|  | import IconAlignJustify from "@ckeditor/ckeditor5-icons/theme/icons/align-justify.svg?raw"; | ||||||
|  | import bxInfoCircle from "boxicons/svg/regular/bx-info-circle.svg?raw"; | ||||||
|  | import bxBulb from "boxicons/svg/regular/bx-bulb.svg?raw"; | ||||||
|  | import bxCommentError from "boxicons/svg/regular/bx-comment-error.svg?raw"; | ||||||
|  | import bxErrorCircle from "boxicons/svg/regular/bx-error-circle.svg?raw"; | ||||||
|  | import bxError from "boxicons/svg/regular/bx-error.svg?raw"; | ||||||
|  | import { COMMAND_NAME as INSERT_DATE_TIME_COMMAND } from './plugins/insert_date_time.js'; | ||||||
|  | import { COMMAND_NAME as INTERNAL_LINK_COMMAND } from './plugins/internallink.js'; | ||||||
|  | import { COMMAND_NAME as INCLUDE_NOTE_COMMAND } from './plugins/includenote.js'; | ||||||
|  | import { COMMAND_NAME as MARKDOWN_IMPORT_COMMAND } from './plugins/markdownimport.js'; | ||||||
|  | import { ADMONITION_TYPES, type AdmonitionType } from '@triliumnext/ckeditor5-admonition'; | ||||||
|  | import dateTimeIcon from './icons/date-time.svg?raw'; | ||||||
|  | import internalLinkIcon from './icons/trilium.svg?raw'; | ||||||
|  | import noteIcon from './icons/note.svg?raw'; | ||||||
|  | import importMarkdownIcon from './icons/markdown-mark.svg?raw'; | ||||||
|  | import { icons as mathIcons, MathUI } from '@triliumnext/ckeditor5-math'; | ||||||
|  | 
 | ||||||
|  | type SlashCommandDefinition = SlashCommandEditorConfig["extraCommands"][number]; | ||||||
|  | 
 | ||||||
|  | export default function buildExtraCommands(): SlashCommandDefinition[] { | ||||||
|  |     return [ | ||||||
|  |         ...buildAlignmentExtraCommands(), | ||||||
|  |         ...buildAdmonitionExtraCommands(), | ||||||
|  |         { | ||||||
|  |             id: 'footnote', | ||||||
|  |             title: 'Footnote', | ||||||
|  |             description: 'Create a new footnote and reference it here', | ||||||
|  |             icon: footnoteIcons.insertFootnoteIcon, | ||||||
|  |             commandName: "InsertFootnote" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             id: "datetime", | ||||||
|  |             title: "Insert Date/Time", | ||||||
|  |             description: "Insert the current date and time", | ||||||
|  |             icon: dateTimeIcon, | ||||||
|  |             commandName: INSERT_DATE_TIME_COMMAND | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             id: "internal-link", | ||||||
|  |             title: "Internal Trilium link", | ||||||
|  |             description: "Insert a link to another Trilium note", | ||||||
|  |             aliases: [ "internal link", "trilium link", "reference link" ], | ||||||
|  |             icon: internalLinkIcon, | ||||||
|  |             commandName: INTERNAL_LINK_COMMAND | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             id: "math", | ||||||
|  |             title: "Math equation", | ||||||
|  |             description: "Insert a math equation", | ||||||
|  |             icon: mathIcons.ckeditor, | ||||||
|  |             execute: (editor: Editor) => editor.plugins.get(MathUI)._showUI() | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             id: "include-note", | ||||||
|  |             title: "Include note", | ||||||
|  |             description: "Display the content of another note in this note", | ||||||
|  |             icon: noteIcon, | ||||||
|  |             commandName: INCLUDE_NOTE_COMMAND | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             id: "page-break", | ||||||
|  |             title: "Page break", | ||||||
|  |             description: "Insert a page break (for printing)", | ||||||
|  |             icon: IconPageBreak, | ||||||
|  |             commandName: "pageBreak" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             id: "markdown-import", | ||||||
|  |             title: "Markdown import", | ||||||
|  |             description: "Import a markdown file into this note", | ||||||
|  |             icon: importMarkdownIcon, | ||||||
|  |             commandName: MARKDOWN_IMPORT_COMMAND | ||||||
|  |         } | ||||||
|  |     ]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function buildAlignmentExtraCommands(): SlashCommandDefinition[] { | ||||||
|  |     return [ | ||||||
|  |         { | ||||||
|  |             id: "align-left", | ||||||
|  |             title: "Align Left", | ||||||
|  |             description: "Align text to the left", | ||||||
|  |             icon: IconAlignLeft, | ||||||
|  |             execute: (editor: Editor) => editor.execute("alignment", { value: "left" }), | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             id: "align-center", | ||||||
|  |             title: "Align Center", | ||||||
|  |             description: "Align text to the center", | ||||||
|  |             icon: IconAlignCenter, | ||||||
|  |             execute: (editor: Editor) => editor.execute("alignment", { value: "center" }), | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             id: "align-right", | ||||||
|  |             title: "Align Right", | ||||||
|  |             description: "Align text to the right", | ||||||
|  |             icon: IconAlignRight, | ||||||
|  |             execute: (editor: Editor) => editor.execute("alignment", { value: "right" }), | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             id: "align-justify", | ||||||
|  |             title: "Justify", | ||||||
|  |             description: "Justify text alignment", | ||||||
|  |             icon: IconAlignJustify, | ||||||
|  |             execute: (editor: Editor) => editor.execute("alignment", { value: "justify" }), | ||||||
|  |         } | ||||||
|  |     ]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function buildAdmonitionExtraCommands(): SlashCommandDefinition[] { | ||||||
|  |     const commands: SlashCommandDefinition[] = []; | ||||||
|  |     const admonitionIcons: Record<AdmonitionType, string> = { | ||||||
|  |         note: bxInfoCircle, | ||||||
|  |         tip: bxBulb, | ||||||
|  |         important: bxCommentError, | ||||||
|  |         caution: bxErrorCircle, | ||||||
|  |         warning: bxError, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     for (const [ keyword, definition ] of Object.entries(ADMONITION_TYPES)) { | ||||||
|  |         commands.push({ | ||||||
|  |             id: keyword, | ||||||
|  |             title: definition.title, | ||||||
|  |             description: "Inserts a new admonition", | ||||||
|  |             icon: admonitionIcons[keyword as AdmonitionType], | ||||||
|  |             execute: (editor: Editor) => editor.execute("admonition", { forceValue: keyword as AdmonitionType }), | ||||||
|  |             aliases: [ "box" ] | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |     return commands; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @ -4,6 +4,7 @@ import { COMMON_PLUGINS, CORE_PLUGINS, POPUP_EDITOR_PLUGINS } from "./plugins"; | |||||||
| import { BalloonEditor, DecoupledEditor, FindAndReplaceEditing, FindCommand } 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"; | export type { EditorConfig, MentionFeed, MentionFeedObjectItem, Node, Position, Element, WatchdogConfig } from "ckeditor5"; | ||||||
|  | export { default as buildExtraCommands } from "./extra_slash_commands.js"; | ||||||
| 
 | 
 | ||||||
| // Import with sideffects to ensure that type augmentations are present.
 | // Import with sideffects to ensure that type augmentations are present.
 | ||||||
| import "@triliumnext/ckeditor5-math"; | import "@triliumnext/ckeditor5-math"; | ||||||
| @ -25,6 +26,7 @@ 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. | ||||||
|  */ |  */ | ||||||
| export class AttributeEditor extends BalloonEditor { | export class AttributeEditor extends BalloonEditor { | ||||||
|  | 
 | ||||||
|     static override get builtinPlugins() { |     static override get builtinPlugins() { | ||||||
|         return CORE_PLUGINS; |         return CORE_PLUGINS; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| import { Autoformat, AutoLink, BlockQuote, BlockToolbar, Bold, CKFinderUploadAdapter, Clipboard, Code, CodeBlock, Enter, FindAndReplace, Font, FontBackgroundColor, FontColor, GeneralHtmlSupport, Heading, HeadingButtonsUI, HorizontalLine, Image, ImageCaption, ImageInline, ImageResize, ImageStyle, ImageToolbar, ImageUpload, Alignment, Indent, IndentBlock, Italic, Link, List, ListProperties, Mention, PageBreak, Paragraph, ParagraphButtonUI, PasteFromOffice, PictureEditing, RemoveFormat, SelectAll, ShiftEnter, SpecialCharacters, SpecialCharactersEssentials, Strikethrough, Style, Subscript, Superscript, Table, TableCaption, TableCellProperties, TableColumnResize, TableProperties, TableSelection, TableToolbar, TextPartLanguage, TextTransformation, TodoList, Typing, Underline, Undo, Bookmark, Emoji } from "ckeditor5"; | import { Autoformat, AutoLink, BlockQuote, BlockToolbar, Bold, CKFinderUploadAdapter, Clipboard, Code, CodeBlock, Enter, FindAndReplace, Font, FontBackgroundColor, FontColor, GeneralHtmlSupport, Heading, HeadingButtonsUI, HorizontalLine, Image, ImageCaption, ImageInline, ImageResize, ImageStyle, ImageToolbar, ImageUpload, Alignment, Indent, IndentBlock, Italic, Link, List, ListProperties, Mention, PageBreak, Paragraph, ParagraphButtonUI, PasteFromOffice, PictureEditing, RemoveFormat, SelectAll, ShiftEnter, SpecialCharacters, SpecialCharactersEssentials, Strikethrough, Style, Subscript, Superscript, Table, TableCaption, TableCellProperties, TableColumnResize, TableProperties, TableSelection, TableToolbar, TextPartLanguage, TextTransformation, TodoList, Typing, Underline, Undo, Bookmark, Emoji } from "ckeditor5"; | ||||||
|  | import { SlashCommand } from "ckeditor5-premium-features"; | ||||||
| import type { Plugin } from "ckeditor5"; | import type { Plugin } from "ckeditor5"; | ||||||
| import CutToNotePlugin from "./plugins/cuttonote.js"; | import CutToNotePlugin from "./plugins/cuttonote.js"; | ||||||
| import UploadimagePlugin from "./plugins/uploadimage.js"; | import UploadimagePlugin from "./plugins/uploadimage.js"; | ||||||
| @ -77,6 +78,13 @@ export const CORE_PLUGINS: typeof Plugin[] = [ | |||||||
|     ReferenceLink |     ReferenceLink | ||||||
| ]; | ]; | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * Plugins that require a premium CKEditor license key to work. | ||||||
|  |  */ | ||||||
|  | export const PREMIUM_PLUGINS: typeof Plugin[] = [ | ||||||
|  |     SlashCommand | ||||||
|  | ]; | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * The set of plugins that are required for the editor to work. This is used in normal text editors (floating or fixed toolbar) but not in the attribute editor. |  * The set of plugins that are required for the editor to work. This is used in normal text editors (floating or fixed toolbar) but not in the attribute editor. | ||||||
|  */ |  */ | ||||||
| @ -139,7 +147,8 @@ export const COMMON_PLUGINS: typeof Plugin[] = [ | |||||||
|     Emoji, |     Emoji, | ||||||
| 
 | 
 | ||||||
|     ...TRILIUM_PLUGINS, |     ...TRILIUM_PLUGINS, | ||||||
|     ...EXTERNAL_PLUGINS |     ...EXTERNAL_PLUGINS, | ||||||
|  |     ...PREMIUM_PLUGINS | ||||||
| ]; | ]; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| import { ButtonView, Command, Plugin, toWidget, Widget, type Editor, type Observable } from 'ckeditor5'; | import { ButtonView, Command, Plugin, toWidget, Widget, type Editor, type Observable } from 'ckeditor5'; | ||||||
| import noteIcon from '../icons/note.svg?raw'; | import noteIcon from '../icons/note.svg?raw'; | ||||||
| 
 | 
 | ||||||
|  | export const COMMAND_NAME = 'insertIncludeNote'; | ||||||
|  | 
 | ||||||
| export default class IncludeNote extends Plugin { | export default class IncludeNote extends Plugin { | ||||||
| 	static get requires() { | 	static get requires() { | ||||||
| 		return [ IncludeNoteEditing, IncludeNoteUI ]; | 		return [ IncludeNoteEditing, IncludeNoteUI ]; | ||||||
| @ -16,7 +18,7 @@ class IncludeNoteUI extends Plugin { | |||||||
| 		// to be displayed in the toolbar.
 | 		// to be displayed in the toolbar.
 | ||||||
| 		editor.ui.componentFactory.add( 'includeNote', locale => { | 		editor.ui.componentFactory.add( 'includeNote', locale => { | ||||||
| 			// The state of the button will be bound to the widget command.
 | 			// The state of the button will be bound to the widget command.
 | ||||||
| 			const command = editor.commands.get( 'insertIncludeNote' ); | 			const command = editor.commands.get( COMMAND_NAME ); | ||||||
| 
 | 
 | ||||||
| 			// The button will be an instance of ButtonView.
 | 			// The button will be an instance of ButtonView.
 | ||||||
| 			const buttonView = new ButtonView( locale ); | 			const buttonView = new ButtonView( locale ); | ||||||
| @ -35,7 +37,7 @@ class IncludeNoteUI extends Plugin { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| 			// Execute the command when the button is clicked (executed).
 | 			// Execute the command when the button is clicked (executed).
 | ||||||
| 			this.listenTo( buttonView, 'execute', () => editor.execute( 'insertIncludeNote' ) ); | 			this.listenTo( buttonView, 'execute', () => editor.execute( COMMAND_NAME ) ); | ||||||
| 
 | 
 | ||||||
| 			return buttonView; | 			return buttonView; | ||||||
| 		} ); | 		} ); | ||||||
| @ -51,7 +53,7 @@ class IncludeNoteEditing extends Plugin { | |||||||
| 		this._defineSchema(); | 		this._defineSchema(); | ||||||
| 		this._defineConverters(); | 		this._defineConverters(); | ||||||
| 
 | 
 | ||||||
| 		this.editor.commands.add( 'insertIncludeNote', new InsertIncludeNoteCommand( this.editor ) ); | 		this.editor.commands.add( COMMAND_NAME, new InsertIncludeNoteCommand( this.editor ) ); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	_defineSchema() { | 	_defineSchema() { | ||||||
|  | |||||||
| @ -1,10 +1,14 @@ | |||||||
| import { ButtonView, Plugin } from 'ckeditor5'; | import { ButtonView, Command, Plugin } from 'ckeditor5'; | ||||||
| import dateTimeIcon from '../icons/date-time.svg?raw'; | import dateTimeIcon from '../icons/date-time.svg?raw'; | ||||||
| 
 | 
 | ||||||
|  | export const COMMAND_NAME = 'insertDateTimeToText'; | ||||||
|  | 
 | ||||||
| export default class InsertDateTimePlugin extends Plugin { | export default class InsertDateTimePlugin extends Plugin { | ||||||
|     init() { |     init() { | ||||||
|         const editor = this.editor; |         const editor = this.editor; | ||||||
| 
 | 
 | ||||||
|  |         editor.commands.add(COMMAND_NAME, new InsertDateTimeCommand(editor)); | ||||||
|  | 
 | ||||||
|         editor.ui.componentFactory.add('dateTime', locale => { |         editor.ui.componentFactory.add('dateTime', locale => { | ||||||
|             const view = new ButtonView( locale ); |             const view = new ButtonView( locale ); | ||||||
| 
 | 
 | ||||||
| @ -15,17 +19,30 @@ export default class InsertDateTimePlugin extends Plugin { | |||||||
|             } ); |             } ); | ||||||
| 
 | 
 | ||||||
|             // enable only if the editor is not read only
 |             // enable only if the editor is not read only
 | ||||||
|             view.bind('isEnabled').to(editor, 'isReadOnly', isReadOnly => !isReadOnly); |             const command = editor.commands.get(COMMAND_NAME)!; | ||||||
| 
 |             view.bind('isEnabled').to(command, 'isEnabled'); | ||||||
|             view.on('execute', () => { |             view.on('execute', () => { | ||||||
|                 const editorEl = editor.editing.view.getDomRoot(); |                 editor.execute(COMMAND_NAME); | ||||||
|                 const component = glob.getComponentByEl(editorEl); |  | ||||||
| 
 |  | ||||||
|                 component.triggerCommand('insertDateTimeToText'); |  | ||||||
|                 editor.editing.view.focus(); |                 editor.editing.view.focus(); | ||||||
|             } ); |             }); | ||||||
| 
 |  | ||||||
|             return view; |             return view; | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | class InsertDateTimeCommand extends Command { | ||||||
|  | 
 | ||||||
|  |     refresh() { | ||||||
|  |         this.isEnabled = !this.editor.isReadOnly; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     execute() { | ||||||
|  |         const editor = this.editor; | ||||||
|  |         const editorEl = editor.editing.view.getDomRoot(); | ||||||
|  |         const component = glob.getComponentByEl(editorEl); | ||||||
|  | 
 | ||||||
|  |         component.triggerCommand('insertDateTimeToText'); | ||||||
|  |         editor.editing.view.focus(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | |||||||
| @ -1,7 +1,9 @@ | |||||||
| import { ButtonView, Plugin } from 'ckeditor5'; | import { ButtonView, Command, Plugin } from 'ckeditor5'; | ||||||
| import internalLinkIcon from '../icons/trilium.svg?raw'; | import internalLinkIcon from '../icons/trilium.svg?raw'; | ||||||
| import ReferenceLink from './referencelink'; | import ReferenceLink from './referencelink'; | ||||||
| 
 | 
 | ||||||
|  | export const COMMAND_NAME = 'insertInternalLink'; | ||||||
|  | 
 | ||||||
| export default class InternalLinkPlugin extends Plugin { | export default class InternalLinkPlugin extends Plugin { | ||||||
| 
 | 
 | ||||||
|     static get requires() { |     static get requires() { | ||||||
| @ -11,6 +13,8 @@ export default class InternalLinkPlugin extends Plugin { | |||||||
| 	init() { | 	init() { | ||||||
| 		const editor = this.editor; | 		const editor = this.editor; | ||||||
| 
 | 
 | ||||||
|  |         editor.commands.add(COMMAND_NAME, new InsertInternalLinkCommand(editor)); | ||||||
|  | 
 | ||||||
| 		editor.ui.componentFactory.add('internalLink', locale => { | 		editor.ui.componentFactory.add('internalLink', locale => { | ||||||
| 			const view = new ButtonView( locale ); | 			const view = new ButtonView( locale ); | ||||||
| 
 | 
 | ||||||
| @ -21,16 +25,28 @@ export default class InternalLinkPlugin extends Plugin { | |||||||
| 			} ); | 			} ); | ||||||
| 
 | 
 | ||||||
|             // enable internal link only if the editor is not read only
 |             // enable internal link only if the editor is not read only
 | ||||||
| 			view.bind('isEnabled').to(editor, 'isReadOnly', isReadOnly => !isReadOnly); | 			const command = editor.commands.get(COMMAND_NAME)!; | ||||||
| 
 |             view.bind('isEnabled').to(command, 'isEnabled'); | ||||||
| 			view.on('execute', () => { | 			view.on('execute', () => { | ||||||
| 				const editorEl = editor.editing.view.getDomRoot(); |                 editor.execute(COMMAND_NAME); | ||||||
| 				const component = glob.getComponentByEl(editorEl); |  | ||||||
| 
 |  | ||||||
| 				component.triggerCommand('addLinkToText'); |  | ||||||
| 			} ); | 			} ); | ||||||
| 
 | 
 | ||||||
| 			return view; | 			return view; | ||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | class InsertInternalLinkCommand extends Command { | ||||||
|  | 
 | ||||||
|  |     refresh() { | ||||||
|  |         this.isEnabled = !this.editor.isReadOnly; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     execute() { | ||||||
|  |         const editor = this.editor; | ||||||
|  |         const editorEl = editor.editing.view.getDomRoot(); | ||||||
|  |         const component = glob.getComponentByEl(editorEl); | ||||||
|  | 
 | ||||||
|  |         component.triggerCommand('addLinkToText'); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
| @ -1,10 +1,14 @@ | |||||||
| import { ButtonView, Plugin } from 'ckeditor5'; | import { ButtonView, Command, Plugin } from 'ckeditor5'; | ||||||
| import markdownIcon from '../icons/markdown-mark.svg?raw'; | import markdownIcon from '../icons/markdown-mark.svg?raw'; | ||||||
| 
 | 
 | ||||||
|  | export const COMMAND_NAME = 'importMarkdownInline'; | ||||||
|  | 
 | ||||||
| export default class MarkdownImportPlugin extends Plugin { | export default class MarkdownImportPlugin extends Plugin { | ||||||
| 	init() { | 	init() { | ||||||
| 		const editor = this.editor; | 		const editor = this.editor; | ||||||
| 
 | 
 | ||||||
|  |         editor.commands.add(COMMAND_NAME, new ImportMarkdownCommand(editor)); | ||||||
|  | 
 | ||||||
| 		editor.ui.componentFactory.add( 'markdownImport', locale => { | 		editor.ui.componentFactory.add( 'markdownImport', locale => { | ||||||
| 			const view = new ButtonView( locale ); | 			const view = new ButtonView( locale ); | ||||||
| 
 | 
 | ||||||
| @ -15,11 +19,19 @@ export default class MarkdownImportPlugin extends Plugin { | |||||||
| 			} ); | 			} ); | ||||||
| 
 | 
 | ||||||
| 			// Callback executed once the image is clicked.
 | 			// Callback executed once the image is clicked.
 | ||||||
| 			view.on( 'execute', () => { |             const command = editor.commands.get(COMMAND_NAME)!; | ||||||
| 				glob.importMarkdownInline(); | 			view.bind('isEnabled').to(command, 'isEnabled'); | ||||||
| 			} ); |             view.on('execute', () => editor.execute(COMMAND_NAME)); | ||||||
| 
 | 
 | ||||||
| 			return view; | 			return view; | ||||||
| 		} ); | 		} ); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | class ImportMarkdownCommand extends Command { | ||||||
|  | 
 | ||||||
|  |     execute() { | ||||||
|  |         glob.importMarkdownInline(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | |||||||
							
								
								
									
										1711
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1711
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Elian Doran
						Elian Doran