@@ -4,25 +4,64 @@ import { buildExtraCommands, type EditorConfig } from "@triliumnext/ckeditor5";
44import { getHighlightJsNameForMime } from "../../../services/mime_types.js" ;
55import options from "../../../services/options.js" ;
66import { ensureMimeTypesForHighlighting , isSyntaxHighlightEnabled } from "../../../services/syntax_highlight.js" ;
7- import utils from "../../../services/utils.js" ;
87import emojiDefinitionsUrl from "@triliumnext/ckeditor5/emoji_definitions/en.json?url" ;
98import { copyTextWithToast } from "../../../services/clipboard_ext.js" ;
109import getTemplates from "./snippets.js" ;
1110import { PREMIUM_PLUGINS } from "../../../../../../packages/ckeditor5/src/plugins.js" ;
11+ import { t } from "../../../services/i18n.js" ;
12+ import { getMermaidConfig } from "../../../services/mermaid.js" ;
13+ import noteAutocompleteService , { type Suggestion } from "../../../services/note_autocomplete.js" ;
14+ import mimeTypesService from "../../../services/mime_types.js" ;
15+ import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons" ;
16+ import { buildToolbarConfig } from "./toolbar.js" ;
1217
13- const OPEN_SOURCE_LICENSE_KEY = "GPL" ;
18+ export const OPEN_SOURCE_LICENSE_KEY = "GPL" ;
1419
15- const TEXT_FORMATTING_GROUP = {
16- label : "Text formatting" ,
17- icon : "text"
18- } ;
20+ export interface BuildEditorOptions {
21+ forceGplLicense : boolean ;
22+ isClassicEditor : boolean ;
23+ contentLanguage : string | null ;
24+ }
1925
20- export async function buildConfig ( ) : Promise < EditorConfig > {
21- const licenseKey = getLicenseKey ( ) ;
26+ export async function buildConfig ( opts : BuildEditorOptions ) : Promise < EditorConfig > {
27+ const licenseKey = ( opts . forceGplLicense ? OPEN_SOURCE_LICENSE_KEY : getLicenseKey ( ) ) ;
2228 const hasPremiumLicense = ( licenseKey !== OPEN_SOURCE_LICENSE_KEY ) ;
2329
2430 const config : EditorConfig = {
2531 licenseKey,
32+ placeholder : t ( "editable_text.placeholder" ) ,
33+ mention : {
34+ feeds : [
35+ {
36+ marker : "@" ,
37+ feed : ( queryText : string ) => noteAutocompleteService . autocompleteSourceForCKEditor ( queryText ) ,
38+ itemRenderer : ( item ) => {
39+ const itemElement = document . createElement ( "button" ) ;
40+
41+ itemElement . innerHTML = `${ ( item as Suggestion ) . highlightedNotePathTitle } ` ;
42+
43+ return itemElement ;
44+ } ,
45+ minimumCharacters : 0
46+ }
47+ ] ,
48+ } ,
49+ codeBlock : {
50+ languages : buildListOfLanguages ( )
51+ } ,
52+ math : {
53+ engine : "katex" ,
54+ outputType : "span" , // or script
55+ lazyLoad : async ( ) => {
56+ ( window as any ) . katex = ( await import ( "../../../services/math.js" ) ) . default
57+ } ,
58+ forceOutputType : false , // forces output to use outputType
59+ enablePreview : true // Enable preview view
60+ } ,
61+ mermaid : {
62+ lazyLoad : async ( ) => ( await import ( "mermaid" ) ) . default , // FIXME
63+ config : getMermaidConfig ( )
64+ } ,
2665 image : {
2766 styles : {
2867 options : [
@@ -137,160 +176,51 @@ export async function buildConfig(): Promise<EditorConfig> {
137176 template : {
138177 definitions : await getTemplates ( )
139178 } ,
179+ htmlSupport : {
180+ allow : JSON . parse ( options . get ( "allowedHtmlTags" ) )
181+ } ,
140182 // This value must be kept in sync with the language defined in webpack.config.js.
141183 language : "en"
142184 } ;
143185
186+ // Set up content language.
187+ const { contentLanguage } = opts ;
188+ if ( contentLanguage ) {
189+ config . language = {
190+ ui : ( typeof config . language === "string" ? config . language : "en" ) ,
191+ content : contentLanguage
192+ }
193+ }
194+
144195 // Enable premium plugins.
145196 if ( hasPremiumLicense ) {
146197 config . extraPlugins = [
147198 ...PREMIUM_PLUGINS
148199 ] ;
149200 }
150201
151- return config ;
152- }
153-
154- export function buildToolbarConfig ( isClassicToolbar : boolean ) {
155- if ( utils . isMobile ( ) ) {
156- return buildMobileToolbar ( ) ;
157- } else if ( isClassicToolbar ) {
158- const multilineToolbar = utils . isDesktop ( ) && options . get ( "textNoteEditorMultilineToolbar" ) === "true" ;
159- return buildClassicToolbar ( multilineToolbar ) ;
160- } else {
161- return buildFloatingToolbar ( ) ;
162- }
163- }
164-
165- export function buildMobileToolbar ( ) {
166- const classicConfig = buildClassicToolbar ( false ) ;
167- const items : string [ ] = [ ] ;
168-
169- for ( const item of classicConfig . toolbar . items ) {
170- if ( typeof item === "object" && "items" in item ) {
171- for ( const subitem of item . items ) {
172- items . push ( subitem ) ;
173- }
174- } else {
175- items . push ( item ) ;
176- }
177- }
178-
179202 return {
180- ...classicConfig ,
181- toolbar : {
182- ...classicConfig . toolbar ,
183- items
184- }
203+ ...config ,
204+ ...buildToolbarConfig ( opts . isClassicEditor )
185205 } ;
186206}
187207
188- export function buildClassicToolbar ( multilineToolbar : boolean ) {
189- // For nested toolbars, refer to https://ckeditor.com/docs/ckeditor5/latest/getting-started/setup/toolbar.html#grouping-toolbar-items-in-dropdowns-nested-toolbars.
190- return {
191- toolbar : {
192- items : [
193- "heading" ,
194- "fontSize" ,
195- "|" ,
196- "bold" ,
197- "italic" ,
198- {
199- ...TEXT_FORMATTING_GROUP ,
200- items : [ "underline" , "strikethrough" , "|" , "superscript" , "subscript" , "|" , "kbd" ]
201- } ,
202- "|" ,
203- "fontColor" ,
204- "fontBackgroundColor" ,
205- "removeFormat" ,
206- "|" ,
207- "bulletedList" ,
208- "numberedList" ,
209- "todoList" ,
210- "|" ,
211- "blockQuote" ,
212- "admonition" ,
213- "insertTable" ,
214- "|" ,
215- "code" ,
216- "codeBlock" ,
217- "|" ,
218- "footnote" ,
219- {
220- label : "Insert" ,
221- icon : "plus" ,
222- items : [ "imageUpload" , "|" , "link" , "bookmark" , "internallink" , "includeNote" , "|" , "specialCharacters" , "emoji" , "math" , "mermaid" , "horizontalLine" , "pageBreak" , "dateTime" ]
223- } ,
224- "|" ,
225- "alignment" ,
226- "outdent" ,
227- "indent" ,
228- "|" ,
229- "insertTemplate" ,
230- "markdownImport" ,
231- "cuttonote" ,
232- "findAndReplace"
233- ] ,
234- shouldNotGroupWhenFull : multilineToolbar
235- }
236- } ;
237- }
208+ function buildListOfLanguages ( ) {
209+ const userLanguages = mimeTypesService
210+ . getMimeTypes ( )
211+ . filter ( ( mt ) => mt . enabled )
212+ . map ( ( mt ) => ( {
213+ language : normalizeMimeTypeForCKEditor ( mt . mime ) ,
214+ label : mt . title
215+ } ) ) ;
238216
239- export function buildFloatingToolbar ( ) {
240- return {
241- toolbar : {
242- items : [
243- "fontSize" ,
244- "bold" ,
245- "italic" ,
246- "underline" ,
247- {
248- ...TEXT_FORMATTING_GROUP ,
249- items : [ "strikethrough" , "|" , "superscript" , "subscript" , "|" , "kbd" ]
250- } ,
251- "|" ,
252- "fontColor" ,
253- "fontBackgroundColor" ,
254- "|" ,
255- "code" ,
256- "link" ,
257- "bookmark" ,
258- "removeFormat" ,
259- "internallink" ,
260- "cuttonote"
261- ]
217+ return [
218+ {
219+ language : mimeTypesService . MIME_TYPE_AUTO ,
220+ label : t ( "editable-text.auto-detect-language" )
262221 } ,
263-
264- blockToolbar : [
265- "heading" ,
266- "|" ,
267- "bulletedList" ,
268- "numberedList" ,
269- "todoList" ,
270- "|" ,
271- "blockQuote" ,
272- "admonition" ,
273- "codeBlock" ,
274- "insertTable" ,
275- "footnote" ,
276- {
277- label : "Insert" ,
278- icon : "plus" ,
279- items : [ "link" , "bookmark" , "internallink" , "includeNote" , "|" , "math" , "mermaid" , "horizontalLine" , "pageBreak" , "dateTime" ]
280- } ,
281- "|" ,
282- "alignment" ,
283- "outdent" ,
284- "indent" ,
285- "|" ,
286- "insertTemplate" ,
287- "imageUpload" ,
288- "markdownImport" ,
289- "specialCharacters" ,
290- "emoji" ,
291- "findAndReplace"
292- ]
293- } ;
222+ ...userLanguages
223+ ] ;
294224}
295225
296226function getLicenseKey ( ) {
0 commit comments