mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-27 10:02:59 +08:00
feat(ckeditor): fallback to GPL if license key fails
This commit is contained in:
parent
e280968271
commit
0325bee425
@ -4,25 +4,64 @@ 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";
|
||||||
import utils from "../../../services/utils.js";
|
|
||||||
import emojiDefinitionsUrl from "@triliumnext/ckeditor5/emoji_definitions/en.json?url";
|
import emojiDefinitionsUrl from "@triliumnext/ckeditor5/emoji_definitions/en.json?url";
|
||||||
import { copyTextWithToast } from "../../../services/clipboard_ext.js";
|
import { copyTextWithToast } from "../../../services/clipboard_ext.js";
|
||||||
import getTemplates from "./snippets.js";
|
import getTemplates from "./snippets.js";
|
||||||
import { PREMIUM_PLUGINS } from "../../../../../../packages/ckeditor5/src/plugins.js";
|
import { PREMIUM_PLUGINS } from "../../../../../../packages/ckeditor5/src/plugins.js";
|
||||||
|
import { t } from "../../../services/i18n.js";
|
||||||
|
import { getMermaidConfig } from "../../../services/mermaid.js";
|
||||||
|
import noteAutocompleteService, { type Suggestion } from "../../../services/note_autocomplete.js";
|
||||||
|
import mimeTypesService from "../../../services/mime_types.js";
|
||||||
|
import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons";
|
||||||
|
import { buildToolbarConfig } from "./toolbar.js";
|
||||||
|
|
||||||
const OPEN_SOURCE_LICENSE_KEY = "GPL";
|
export const OPEN_SOURCE_LICENSE_KEY = "GPL";
|
||||||
|
|
||||||
const TEXT_FORMATTING_GROUP = {
|
export interface BuildEditorOptions {
|
||||||
label: "Text formatting",
|
forceGplLicense: boolean;
|
||||||
icon: "text"
|
isClassicEditor: boolean;
|
||||||
};
|
contentLanguage: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export async function buildConfig(): Promise<EditorConfig> {
|
export async function buildConfig(opts: BuildEditorOptions): Promise<EditorConfig> {
|
||||||
const licenseKey = getLicenseKey();
|
const licenseKey = (opts.forceGplLicense ? OPEN_SOURCE_LICENSE_KEY : getLicenseKey());
|
||||||
const hasPremiumLicense = (licenseKey !== OPEN_SOURCE_LICENSE_KEY);
|
const hasPremiumLicense = (licenseKey !== OPEN_SOURCE_LICENSE_KEY);
|
||||||
|
|
||||||
const config: EditorConfig = {
|
const config: EditorConfig = {
|
||||||
licenseKey,
|
licenseKey,
|
||||||
|
placeholder: t("editable_text.placeholder"),
|
||||||
|
mention: {
|
||||||
|
feeds: [
|
||||||
|
{
|
||||||
|
marker: "@",
|
||||||
|
feed: (queryText: string) => noteAutocompleteService.autocompleteSourceForCKEditor(queryText),
|
||||||
|
itemRenderer: (item) => {
|
||||||
|
const itemElement = document.createElement("button");
|
||||||
|
|
||||||
|
itemElement.innerHTML = `${(item as Suggestion).highlightedNotePathTitle} `;
|
||||||
|
|
||||||
|
return itemElement;
|
||||||
|
},
|
||||||
|
minimumCharacters: 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
codeBlock: {
|
||||||
|
languages: buildListOfLanguages()
|
||||||
|
},
|
||||||
|
math: {
|
||||||
|
engine: "katex",
|
||||||
|
outputType: "span", // or script
|
||||||
|
lazyLoad: async () => {
|
||||||
|
(window as any).katex = (await import("../../../services/math.js")).default
|
||||||
|
},
|
||||||
|
forceOutputType: false, // forces output to use outputType
|
||||||
|
enablePreview: true // Enable preview view
|
||||||
|
},
|
||||||
|
mermaid: {
|
||||||
|
lazyLoad: async () => (await import("mermaid")).default, // FIXME
|
||||||
|
config: getMermaidConfig()
|
||||||
|
},
|
||||||
image: {
|
image: {
|
||||||
styles: {
|
styles: {
|
||||||
options: [
|
options: [
|
||||||
@ -137,10 +176,22 @@ export async function buildConfig(): Promise<EditorConfig> {
|
|||||||
template: {
|
template: {
|
||||||
definitions: await getTemplates()
|
definitions: await getTemplates()
|
||||||
},
|
},
|
||||||
|
htmlSupport: {
|
||||||
|
allow: JSON.parse(options.get("allowedHtmlTags"))
|
||||||
|
},
|
||||||
// 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"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Set up content language.
|
||||||
|
const { contentLanguage } = opts;
|
||||||
|
if (contentLanguage) {
|
||||||
|
config.language = {
|
||||||
|
ui: (typeof config.language === "string" ? config.language : "en"),
|
||||||
|
content: contentLanguage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Enable premium plugins.
|
// Enable premium plugins.
|
||||||
if (hasPremiumLicense) {
|
if (hasPremiumLicense) {
|
||||||
config.extraPlugins = [
|
config.extraPlugins = [
|
||||||
@ -148,149 +199,28 @@ export async function buildConfig(): Promise<EditorConfig> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildToolbarConfig(isClassicToolbar: boolean) {
|
|
||||||
if (utils.isMobile()) {
|
|
||||||
return buildMobileToolbar();
|
|
||||||
} else if (isClassicToolbar) {
|
|
||||||
const multilineToolbar = utils.isDesktop() && options.get("textNoteEditorMultilineToolbar") === "true";
|
|
||||||
return buildClassicToolbar(multilineToolbar);
|
|
||||||
} else {
|
|
||||||
return buildFloatingToolbar();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildMobileToolbar() {
|
|
||||||
const classicConfig = buildClassicToolbar(false);
|
|
||||||
const items: string[] = [];
|
|
||||||
|
|
||||||
for (const item of classicConfig.toolbar.items) {
|
|
||||||
if (typeof item === "object" && "items" in item) {
|
|
||||||
for (const subitem of item.items) {
|
|
||||||
items.push(subitem);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
items.push(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...classicConfig,
|
...config,
|
||||||
toolbar: {
|
...buildToolbarConfig(opts.isClassicEditor)
|
||||||
...classicConfig.toolbar,
|
|
||||||
items
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildClassicToolbar(multilineToolbar: boolean) {
|
function buildListOfLanguages() {
|
||||||
// For nested toolbars, refer to https://ckeditor.com/docs/ckeditor5/latest/getting-started/setup/toolbar.html#grouping-toolbar-items-in-dropdowns-nested-toolbars.
|
const userLanguages = mimeTypesService
|
||||||
return {
|
.getMimeTypes()
|
||||||
toolbar: {
|
.filter((mt) => mt.enabled)
|
||||||
items: [
|
.map((mt) => ({
|
||||||
"heading",
|
language: normalizeMimeTypeForCKEditor(mt.mime),
|
||||||
"fontSize",
|
label: mt.title
|
||||||
"|",
|
}));
|
||||||
"bold",
|
|
||||||
"italic",
|
|
||||||
{
|
|
||||||
...TEXT_FORMATTING_GROUP,
|
|
||||||
items: ["underline", "strikethrough", "|", "superscript", "subscript", "|", "kbd"]
|
|
||||||
},
|
|
||||||
"|",
|
|
||||||
"fontColor",
|
|
||||||
"fontBackgroundColor",
|
|
||||||
"removeFormat",
|
|
||||||
"|",
|
|
||||||
"bulletedList",
|
|
||||||
"numberedList",
|
|
||||||
"todoList",
|
|
||||||
"|",
|
|
||||||
"blockQuote",
|
|
||||||
"admonition",
|
|
||||||
"insertTable",
|
|
||||||
"|",
|
|
||||||
"code",
|
|
||||||
"codeBlock",
|
|
||||||
"|",
|
|
||||||
"footnote",
|
|
||||||
{
|
|
||||||
label: "Insert",
|
|
||||||
icon: "plus",
|
|
||||||
items: ["imageUpload", "|", "link", "bookmark", "internallink", "includeNote", "|", "specialCharacters", "emoji", "math", "mermaid", "horizontalLine", "pageBreak", "dateTime"]
|
|
||||||
},
|
|
||||||
"|",
|
|
||||||
"alignment",
|
|
||||||
"outdent",
|
|
||||||
"indent",
|
|
||||||
"|",
|
|
||||||
"insertTemplate",
|
|
||||||
"markdownImport",
|
|
||||||
"cuttonote",
|
|
||||||
"findAndReplace"
|
|
||||||
],
|
|
||||||
shouldNotGroupWhenFull: multilineToolbar
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildFloatingToolbar() {
|
return [
|
||||||
return {
|
{
|
||||||
toolbar: {
|
language: mimeTypesService.MIME_TYPE_AUTO,
|
||||||
items: [
|
label: t("editable-text.auto-detect-language")
|
||||||
"fontSize",
|
|
||||||
"bold",
|
|
||||||
"italic",
|
|
||||||
"underline",
|
|
||||||
{
|
|
||||||
...TEXT_FORMATTING_GROUP,
|
|
||||||
items: [ "strikethrough", "|", "superscript", "subscript", "|", "kbd" ]
|
|
||||||
},
|
|
||||||
"|",
|
|
||||||
"fontColor",
|
|
||||||
"fontBackgroundColor",
|
|
||||||
"|",
|
|
||||||
"code",
|
|
||||||
"link",
|
|
||||||
"bookmark",
|
|
||||||
"removeFormat",
|
|
||||||
"internallink",
|
|
||||||
"cuttonote"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
|
...userLanguages
|
||||||
blockToolbar: [
|
];
|
||||||
"heading",
|
|
||||||
"|",
|
|
||||||
"bulletedList",
|
|
||||||
"numberedList",
|
|
||||||
"todoList",
|
|
||||||
"|",
|
|
||||||
"blockQuote",
|
|
||||||
"admonition",
|
|
||||||
"codeBlock",
|
|
||||||
"insertTable",
|
|
||||||
"footnote",
|
|
||||||
{
|
|
||||||
label: "Insert",
|
|
||||||
icon: "plus",
|
|
||||||
items: ["link", "bookmark", "internallink", "includeNote", "|", "math", "mermaid", "horizontalLine", "pageBreak", "dateTime"]
|
|
||||||
},
|
|
||||||
"|",
|
|
||||||
"alignment",
|
|
||||||
"outdent",
|
|
||||||
"indent",
|
|
||||||
"|",
|
|
||||||
"insertTemplate",
|
|
||||||
"imageUpload",
|
|
||||||
"markdownImport",
|
|
||||||
"specialCharacters",
|
|
||||||
"emoji",
|
|
||||||
"findAndReplace"
|
|
||||||
]
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLicenseKey() {
|
function getLicenseKey() {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { buildClassicToolbar, buildFloatingToolbar } from "./config.js";
|
import { buildClassicToolbar, buildFloatingToolbar } from "./toolbar.js";
|
||||||
|
|
||||||
type ToolbarConfig = string | "|" | { items: ToolbarConfig[] };
|
type ToolbarConfig = string | "|" | { items: ToolbarConfig[] };
|
||||||
|
|
149
apps/client/src/widgets/type_widgets/ckeditor/toolbar.ts
Normal file
149
apps/client/src/widgets/type_widgets/ckeditor/toolbar.ts
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
import utils from "../../../services/utils.js";
|
||||||
|
import options from "../../../services/options.js";
|
||||||
|
|
||||||
|
const TEXT_FORMATTING_GROUP = {
|
||||||
|
label: "Text formatting",
|
||||||
|
icon: "text"
|
||||||
|
};
|
||||||
|
|
||||||
|
export function buildToolbarConfig(isClassicToolbar: boolean) {
|
||||||
|
if (utils.isMobile()) {
|
||||||
|
return buildMobileToolbar();
|
||||||
|
} else if (isClassicToolbar) {
|
||||||
|
const multilineToolbar = utils.isDesktop() && options.get("textNoteEditorMultilineToolbar") === "true";
|
||||||
|
return buildClassicToolbar(multilineToolbar);
|
||||||
|
} else {
|
||||||
|
return buildFloatingToolbar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildMobileToolbar() {
|
||||||
|
const classicConfig = buildClassicToolbar(false);
|
||||||
|
const items: string[] = [];
|
||||||
|
|
||||||
|
for (const item of classicConfig.toolbar.items) {
|
||||||
|
if (typeof item === "object" && "items" in item) {
|
||||||
|
for (const subitem of item.items) {
|
||||||
|
items.push(subitem);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
items.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...classicConfig,
|
||||||
|
toolbar: {
|
||||||
|
...classicConfig.toolbar,
|
||||||
|
items
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildClassicToolbar(multilineToolbar: boolean) {
|
||||||
|
// For nested toolbars, refer to https://ckeditor.com/docs/ckeditor5/latest/getting-started/setup/toolbar.html#grouping-toolbar-items-in-dropdowns-nested-toolbars.
|
||||||
|
return {
|
||||||
|
toolbar: {
|
||||||
|
items: [
|
||||||
|
"heading",
|
||||||
|
"fontSize",
|
||||||
|
"|",
|
||||||
|
"bold",
|
||||||
|
"italic",
|
||||||
|
{
|
||||||
|
...TEXT_FORMATTING_GROUP,
|
||||||
|
items: ["underline", "strikethrough", "|", "superscript", "subscript", "|", "kbd"]
|
||||||
|
},
|
||||||
|
"|",
|
||||||
|
"fontColor",
|
||||||
|
"fontBackgroundColor",
|
||||||
|
"removeFormat",
|
||||||
|
"|",
|
||||||
|
"bulletedList",
|
||||||
|
"numberedList",
|
||||||
|
"todoList",
|
||||||
|
"|",
|
||||||
|
"blockQuote",
|
||||||
|
"admonition",
|
||||||
|
"insertTable",
|
||||||
|
"|",
|
||||||
|
"code",
|
||||||
|
"codeBlock",
|
||||||
|
"|",
|
||||||
|
"footnote",
|
||||||
|
{
|
||||||
|
label: "Insert",
|
||||||
|
icon: "plus",
|
||||||
|
items: ["imageUpload", "|", "link", "bookmark", "internallink", "includeNote", "|", "specialCharacters", "emoji", "math", "mermaid", "horizontalLine", "pageBreak", "dateTime"]
|
||||||
|
},
|
||||||
|
"|",
|
||||||
|
"alignment",
|
||||||
|
"outdent",
|
||||||
|
"indent",
|
||||||
|
"|",
|
||||||
|
"insertTemplate",
|
||||||
|
"markdownImport",
|
||||||
|
"cuttonote",
|
||||||
|
"findAndReplace"
|
||||||
|
],
|
||||||
|
shouldNotGroupWhenFull: multilineToolbar
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildFloatingToolbar() {
|
||||||
|
return {
|
||||||
|
toolbar: {
|
||||||
|
items: [
|
||||||
|
"fontSize",
|
||||||
|
"bold",
|
||||||
|
"italic",
|
||||||
|
"underline",
|
||||||
|
{
|
||||||
|
...TEXT_FORMATTING_GROUP,
|
||||||
|
items: [ "strikethrough", "|", "superscript", "subscript", "|", "kbd" ]
|
||||||
|
},
|
||||||
|
"|",
|
||||||
|
"fontColor",
|
||||||
|
"fontBackgroundColor",
|
||||||
|
"|",
|
||||||
|
"code",
|
||||||
|
"link",
|
||||||
|
"bookmark",
|
||||||
|
"removeFormat",
|
||||||
|
"internallink",
|
||||||
|
"cuttonote"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
blockToolbar: [
|
||||||
|
"heading",
|
||||||
|
"|",
|
||||||
|
"bulletedList",
|
||||||
|
"numberedList",
|
||||||
|
"todoList",
|
||||||
|
"|",
|
||||||
|
"blockQuote",
|
||||||
|
"admonition",
|
||||||
|
"codeBlock",
|
||||||
|
"insertTable",
|
||||||
|
"footnote",
|
||||||
|
{
|
||||||
|
label: "Insert",
|
||||||
|
icon: "plus",
|
||||||
|
items: ["link", "bookmark", "internallink", "includeNote", "|", "math", "mermaid", "horizontalLine", "pageBreak", "dateTime"]
|
||||||
|
},
|
||||||
|
"|",
|
||||||
|
"alignment",
|
||||||
|
"outdent",
|
||||||
|
"indent",
|
||||||
|
"|",
|
||||||
|
"insertTemplate",
|
||||||
|
"imageUpload",
|
||||||
|
"markdownImport",
|
||||||
|
"specialCharacters",
|
||||||
|
"emoji",
|
||||||
|
"findAndReplace"
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
@ -1,6 +1,3 @@
|
|||||||
import { t } from "../../services/i18n.js";
|
|
||||||
import noteAutocompleteService, { type Suggestion } from "../../services/note_autocomplete.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";
|
||||||
import froca from "../../services/froca.js";
|
import froca from "../../services/froca.js";
|
||||||
@ -12,29 +9,12 @@ import dialogService from "../../services/dialog.js";
|
|||||||
import options from "../../services/options.js";
|
import options from "../../services/options.js";
|
||||||
import toast from "../../services/toast.js";
|
import toast from "../../services/toast.js";
|
||||||
import { buildSelectedBackgroundColor } from "../../components/touch_bar.js";
|
import { buildSelectedBackgroundColor } from "../../components/touch_bar.js";
|
||||||
import { buildConfig, buildToolbarConfig } from "./ckeditor/config.js";
|
import { buildConfig, BuildEditorOptions, OPEN_SOURCE_LICENSE_KEY } 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 { PopupEditor, ClassicEditor, EditorWatchdog, type CKTextEditor, type MentionFeed, type WatchdogConfig, EditorConfig } 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";
|
||||||
import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons";
|
|
||||||
import { updateTemplateCache } from "./ckeditor/snippets.js";
|
import { updateTemplateCache } from "./ckeditor/snippets.js";
|
||||||
|
|
||||||
const mentionSetup: MentionFeed[] = [
|
|
||||||
{
|
|
||||||
marker: "@",
|
|
||||||
feed: (queryText: string) => noteAutocompleteService.autocompleteSourceForCKEditor(queryText),
|
|
||||||
itemRenderer: (item) => {
|
|
||||||
const itemElement = document.createElement("button");
|
|
||||||
|
|
||||||
itemElement.innerHTML = `${(item as Suggestion).highlightedNotePathTitle} `;
|
|
||||||
|
|
||||||
return itemElement;
|
|
||||||
},
|
|
||||||
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">
|
||||||
<style>
|
<style>
|
||||||
@ -97,24 +77,6 @@ const TPL = /*html*/`
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function buildListOfLanguages() {
|
|
||||||
const userLanguages = mimeTypesService
|
|
||||||
.getMimeTypes()
|
|
||||||
.filter((mt) => mt.enabled)
|
|
||||||
.map((mt) => ({
|
|
||||||
language: normalizeMimeTypeForCKEditor(mt.mime),
|
|
||||||
label: mt.title
|
|
||||||
}));
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
language: mimeTypesService.MIME_TYPE_AUTO,
|
|
||||||
label: t("editable-text.auto-detect-language")
|
|
||||||
},
|
|
||||||
...userLanguages
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The editor can operate into two distinct modes:
|
* The editor can operate into two distinct modes:
|
||||||
*
|
*
|
||||||
@ -147,7 +109,6 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
|||||||
|
|
||||||
async initEditor() {
|
async initEditor() {
|
||||||
const isClassicEditor = utils.isMobile() || options.get("textNoteEditorType") === "ckeditor-classic";
|
const isClassicEditor = utils.isMobile() || options.get("textNoteEditorType") === "ckeditor-classic";
|
||||||
const editorClass = isClassicEditor ? ClassicEditor : PopupEditor;
|
|
||||||
|
|
||||||
// CKEditor since version 12 needs the element to be visible before initialization. At the same time,
|
// CKEditor since version 12 needs the element to be visible before initialization. At the same time,
|
||||||
// we want to avoid flicker - i.e., show editor only once everything is ready. That's why we have separate
|
// we want to avoid flicker - i.e., show editor only once everything is ready. That's why we have separate
|
||||||
@ -192,33 +153,15 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
|||||||
this.watchdog.setCreator(async (_, editorConfig) => {
|
this.watchdog.setCreator(async (_, editorConfig) => {
|
||||||
logInfo("Creating new CKEditor");
|
logInfo("Creating new CKEditor");
|
||||||
|
|
||||||
const finalConfig = {
|
|
||||||
...editorConfig,
|
|
||||||
...(await buildConfig()),
|
|
||||||
...buildToolbarConfig(isClassicEditor),
|
|
||||||
htmlSupport: {
|
|
||||||
allow: JSON.parse(options.get("allowedHtmlTags")),
|
|
||||||
styles: true,
|
|
||||||
classes: true,
|
|
||||||
attributes: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const contentLanguage = this.note?.getLabelValue("language");
|
const contentLanguage = this.note?.getLabelValue("language");
|
||||||
if (contentLanguage) {
|
this.contentLanguage = contentLanguage ?? null;
|
||||||
// TODO: Wrong type?
|
|
||||||
//@ts-ignore
|
|
||||||
finalConfig.language = {
|
|
||||||
ui: (typeof finalConfig.language === "string" ? finalConfig.language : "en"),
|
|
||||||
content: contentLanguage
|
|
||||||
}
|
|
||||||
this.contentLanguage = contentLanguage;
|
|
||||||
} else {
|
|
||||||
this.contentLanguage = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//@ts-ignore
|
const opts: BuildEditorOptions = {
|
||||||
const editor = await editorClass.create(this.$editor[0], finalConfig);
|
contentLanguage: this.contentLanguage,
|
||||||
|
forceGplLicense: false,
|
||||||
|
isClassicEditor
|
||||||
|
};
|
||||||
|
const editor = await buildEditor(this.$editor[0], isClassicEditor, opts);
|
||||||
|
|
||||||
const notificationsPlugin = editor.plugins.get("Notification");
|
const notificationsPlugin = editor.plugins.get("Notification");
|
||||||
notificationsPlugin.on("show:warning", (evt, data) => {
|
notificationsPlugin.on("show:warning", (evt, data) => {
|
||||||
@ -295,28 +238,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async createEditor() {
|
async createEditor() {
|
||||||
await this.watchdog.create(this.$editor[0], {
|
await this.watchdog.create(this.$editor[0]);
|
||||||
placeholder: t("editable_text.placeholder"),
|
|
||||||
mention: {
|
|
||||||
feeds: mentionSetup,
|
|
||||||
},
|
|
||||||
codeBlock: {
|
|
||||||
languages: buildListOfLanguages()
|
|
||||||
},
|
|
||||||
math: {
|
|
||||||
engine: "katex",
|
|
||||||
outputType: "span", // or script
|
|
||||||
lazyLoad: async () => {
|
|
||||||
(window as any).katex = (await import("../../services/math.js")).default
|
|
||||||
},
|
|
||||||
forceOutputType: false, // forces output to use outputType
|
|
||||||
enablePreview: true // Enable preview view
|
|
||||||
},
|
|
||||||
mermaid: {
|
|
||||||
lazyLoad: async () => (await import("mermaid")).default, // FIXME
|
|
||||||
config: getMermaidConfig()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async doRefresh(note: FNote) {
|
async doRefresh(note: FNote) {
|
||||||
@ -655,3 +577,18 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function buildEditor(element: HTMLElement, isClassicEditor: boolean, opts: BuildEditorOptions) {
|
||||||
|
const editorClass = isClassicEditor ? ClassicEditor : PopupEditor;
|
||||||
|
let config = await buildConfig(opts);
|
||||||
|
let editor = await editorClass.create(element, config);
|
||||||
|
|
||||||
|
if (editor.isReadOnly) {
|
||||||
|
editor.destroy();
|
||||||
|
|
||||||
|
opts.forceGplLicense = true;
|
||||||
|
config = await buildConfig(opts);
|
||||||
|
editor = await editorClass.create(element, config);
|
||||||
|
}
|
||||||
|
return editor;
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -97,6 +97,9 @@ export default defineConfig(() => ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
test: {
|
||||||
|
environment: "happy-dom"
|
||||||
|
},
|
||||||
optimizeDeps: {
|
optimizeDeps: {
|
||||||
exclude: [
|
exclude: [
|
||||||
"@triliumnext/highlightjs"
|
"@triliumnext/highlightjs"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user