mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-27 10:02:59 +08:00
fix(ckeditor5): reintroduce block handle for floating editor
This commit is contained in:
parent
10e5852a67
commit
910b0d280d
@ -26,6 +26,7 @@ import type TypeWidget from "../widgets/type_widgets/type_widget.js";
|
||||
import type EditableTextTypeWidget from "../widgets/type_widgets/editable_text.js";
|
||||
import type { NativeImage, TouchBar } from "electron";
|
||||
import TouchBarComponent from "./touch_bar.js";
|
||||
import type { ClassicEditor, PopupEditor } from "@triliumnext/ckeditor5";
|
||||
|
||||
interface Layout {
|
||||
getRootWidget: (appContext: AppContext) => RootWidget;
|
||||
@ -187,7 +188,7 @@ export type CommandMappings = {
|
||||
callback: (value: NoteDetailWidget | PromiseLike<NoteDetailWidget>) => void;
|
||||
};
|
||||
executeWithTextEditor: CommandData &
|
||||
ExecuteCommandData<TextEditor> & {
|
||||
ExecuteCommandData<ClassicEditor | PopupEditor> & {
|
||||
callback?: GetTextEditorCallback;
|
||||
};
|
||||
executeWithCodeEditor: CommandData & ExecuteCommandData<CodeMirrorInstance>;
|
||||
|
@ -10,13 +10,14 @@ import options from "../services/options.js";
|
||||
import type { ViewScope } from "../services/link.js";
|
||||
import type FNote from "../entities/fnote.js";
|
||||
import type TypeWidget from "../widgets/type_widgets/type_widget.js";
|
||||
import type { ClassicEditor, PopupEditor } from "@triliumnext/ckeditor5";
|
||||
|
||||
export interface SetNoteOpts {
|
||||
triggerSwitchEvent?: unknown;
|
||||
viewScope?: ViewScope;
|
||||
}
|
||||
|
||||
export type GetTextEditorCallback = (editor: TextEditor) => void;
|
||||
export type GetTextEditorCallback = (editor: ClassicEditor | PopupEditor) => void;
|
||||
|
||||
class NoteContext extends Component implements EventListener<"entitiesReloaded"> {
|
||||
ntxId: string | null;
|
||||
@ -298,7 +299,7 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
|
||||
}
|
||||
|
||||
async getTextEditor(callback?: GetTextEditorCallback) {
|
||||
return this.timeout<TextEditor>(
|
||||
return this.timeout<ClassicEditor | PopupEditor>(
|
||||
new Promise((resolve) =>
|
||||
appContext.triggerCommand("executeWithTextEditor", {
|
||||
callback,
|
||||
|
103
apps/client/src/types.d.ts
vendored
103
apps/client/src/types.d.ts
vendored
@ -332,109 +332,6 @@ declare global {
|
||||
};
|
||||
}
|
||||
|
||||
interface TextEditor {
|
||||
create(el: HTMLElement, config: {
|
||||
removePlugins?: string[];
|
||||
toolbar: {
|
||||
items: any[];
|
||||
},
|
||||
placeholder: string;
|
||||
mention: MentionConfig
|
||||
});
|
||||
enableReadOnlyMode(reason: string);
|
||||
commands: {
|
||||
get(name: string): {
|
||||
value: unknown;
|
||||
on(event: string, callback: () => void): void;
|
||||
};
|
||||
}
|
||||
model: {
|
||||
document: {
|
||||
on(event: string, cb: () => void);
|
||||
getRoot(): CKNode;
|
||||
registerPostFixer(callback: (writer: Writer) => boolean);
|
||||
selection: {
|
||||
getFirstPosition(): undefined | TextPosition;
|
||||
getLastPosition(): undefined | TextPosition;
|
||||
getSelectedElement(): CKNode;
|
||||
hasAttribute(attribute: string): boolean;
|
||||
getAttribute(attribute: string): string;
|
||||
getFirstRange(): Range;
|
||||
isCollapsed: boolean;
|
||||
};
|
||||
differ: {
|
||||
getChanges(): {
|
||||
type: string;
|
||||
name: string;
|
||||
position?: {
|
||||
nodeAfter?: CKNode;
|
||||
parent: CKNode;
|
||||
toJSON(): Object;
|
||||
}
|
||||
}[];
|
||||
}
|
||||
},
|
||||
insertContent(modelFragment: any, selection?: any);
|
||||
change(cb: (writer: Writer) => void)
|
||||
},
|
||||
editing: {
|
||||
view: {
|
||||
document: {
|
||||
on(event: string, cb: (event: CKEvent, data: {
|
||||
preventDefault();
|
||||
}) => void, opts?: {
|
||||
priority: "high"
|
||||
});
|
||||
getRoot(): CKNode
|
||||
},
|
||||
domRoots: {
|
||||
values: () => {
|
||||
next: () => {
|
||||
value: string;
|
||||
}
|
||||
};
|
||||
}
|
||||
change(cb: (writer: Writer) => void);
|
||||
scrollToTheSelection(): void;
|
||||
focus(): void;
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
get(command: string)
|
||||
},
|
||||
data: {
|
||||
processor: {
|
||||
toView(html: string);
|
||||
};
|
||||
toModel(viewFeragment: any);
|
||||
},
|
||||
ui: {
|
||||
view: {
|
||||
toolbar: {
|
||||
items: any[];
|
||||
element: HTMLElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
conversion: {
|
||||
for(filter: string): {
|
||||
markerToHighlight(data: {
|
||||
model: string;
|
||||
view: (data: {
|
||||
markerName: string;
|
||||
}) => void;
|
||||
})
|
||||
}
|
||||
}
|
||||
getData(): string;
|
||||
setData(data: string): void;
|
||||
getSelectedHtml(): string;
|
||||
removeSelection(): void;
|
||||
execute<T>(action: string, ...args: unknown[]): T;
|
||||
focus(): void;
|
||||
sourceElement: HTMLElement;
|
||||
}
|
||||
|
||||
interface EditingState {
|
||||
highlightedResult: string;
|
||||
results: unknown[];
|
||||
|
@ -4,7 +4,7 @@ import noteAutocompleteService from "../../services/note_autocomplete.js";
|
||||
import server from "../../services/server.js";
|
||||
import contextMenuService from "../../menus/context_menu.js";
|
||||
import attributeParser, { type Attribute } from "../../services/attribute_parser.js";
|
||||
import { BalloonEditor } from "@triliumnext/ckeditor5";
|
||||
import { AttributeEditor } from "@triliumnext/ckeditor5";
|
||||
import froca from "../../services/froca.js";
|
||||
import attributeRenderer from "../../services/attribute_renderer.js";
|
||||
import noteCreateService from "../../services/note_create.js";
|
||||
@ -199,7 +199,7 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget implem
|
||||
private $saveAttributesButton!: JQuery<HTMLElement>;
|
||||
private $errors!: JQuery<HTMLElement>;
|
||||
|
||||
private textEditor!: BalloonEditor;
|
||||
private textEditor!: AttributeEditor;
|
||||
private lastUpdatedNoteId!: string | undefined;
|
||||
private lastSavedContent!: string;
|
||||
|
||||
@ -373,7 +373,7 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget implem
|
||||
|
||||
this.$editor.on("click", (e) => this.handleEditorClick(e));
|
||||
|
||||
this.textEditor = await BalloonEditor.create(this.$editor[0], editorConfig);
|
||||
this.textEditor = await AttributeEditor.create(this.$editor[0], editorConfig);
|
||||
this.textEditor.model.document.on("change:data", () => this.dataChanged());
|
||||
this.textEditor.editing.view.document.on(
|
||||
"enter",
|
||||
|
@ -18,7 +18,7 @@ import { buildSelectedBackgroundColor } from "../../components/touch_bar.js";
|
||||
import { buildConfig, buildToolbarConfig } from "./ckeditor/config.js";
|
||||
import type FNote from "../../entities/fnote.js";
|
||||
import { getMermaidConfig } from "../../services/mermaid.js";
|
||||
import { BalloonEditor, COMMON_PLUGINS, DecoupledEditor, EditorWatchdog } from "@triliumnext/ckeditor5";
|
||||
import { PopupEditor, ClassicEditor, EditorWatchdog } from "@triliumnext/ckeditor5";
|
||||
|
||||
const ENABLE_INSPECTOR = false;
|
||||
|
||||
@ -128,7 +128,7 @@ function buildListOfLanguages() {
|
||||
export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
||||
|
||||
private contentLanguage?: string | null;
|
||||
private watchdog!: EditorWatchdog<DecoupledEditor | BalloonEditor>;
|
||||
private watchdog!: EditorWatchdog<ClassicEditor | PopupEditor>;
|
||||
|
||||
private $editor!: JQuery<HTMLElement>;
|
||||
|
||||
@ -151,14 +151,14 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
||||
|
||||
async initEditor() {
|
||||
const isClassicEditor = utils.isMobile() || options.get("textNoteEditorType") === "ckeditor-classic";
|
||||
const editorClass = isClassicEditor ? DecoupledEditor : BalloonEditor;
|
||||
const editorClass = isClassicEditor ? ClassicEditor : PopupEditor;
|
||||
|
||||
// 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
|
||||
// display of $widget in both branches.
|
||||
this.$widget.show();
|
||||
|
||||
this.watchdog = new EditorWatchdog<DecoupledEditor | BalloonEditor>(editorClass, {
|
||||
this.watchdog = new EditorWatchdog<ClassicEditor | PopupEditor>(editorClass, {
|
||||
// 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
|
||||
// is also reached, the watchdog changes its state to crashedPermanently, and it stops
|
||||
@ -252,7 +252,10 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
||||
|
||||
$classicToolbarWidget.empty();
|
||||
if ($classicToolbarWidget.length) {
|
||||
$classicToolbarWidget[0].appendChild(editor.ui.view.toolbar.element);
|
||||
const toolbarView = (editor as ClassicEditor).ui.view.toolbar;
|
||||
if (toolbarView.element) {
|
||||
$classicToolbarWidget[0].appendChild(toolbarView.element);
|
||||
}
|
||||
}
|
||||
|
||||
if (utils.isMobile()) {
|
||||
@ -260,7 +263,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
||||
|
||||
// Reposition all dropdowns to point upwards instead of downwards.
|
||||
// See https://ckeditor.com/docs/ckeditor5/latest/examples/framework/bottom-toolbar-editor.html for more info.
|
||||
const toolbarView = (editor as DecoupledEditor).ui.view.toolbar;
|
||||
const toolbarView = (editor as ClassicEditor).ui.view.toolbar;
|
||||
for (const item of toolbarView.items) {
|
||||
if (!("panelView" in item)) {
|
||||
continue;
|
||||
@ -317,8 +320,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
||||
mermaid: {
|
||||
lazyLoad: async () => (await import("mermaid")).default, // FIXME
|
||||
config: getMermaidConfig()
|
||||
},
|
||||
plugins: COMMON_PLUGINS
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -443,6 +445,10 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
||||
|
||||
await this.initialized;
|
||||
|
||||
if (!this.watchdog.editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback(this.watchdog.editor);
|
||||
}
|
||||
@ -489,7 +495,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
||||
}
|
||||
}
|
||||
|
||||
if (!selection.hasAttribute("linkHref")) {
|
||||
if (!selection?.hasAttribute("linkHref")) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,22 @@
|
||||
import "ckeditor5/ckeditor5.css";
|
||||
export { EditorWatchdog, BalloonEditor, DecoupledEditor } from "ckeditor5";
|
||||
export * from "./plugins.js";
|
||||
import { COMMON_PLUGINS, POPUP_EDITOR_PLUGINS } from "./plugins";
|
||||
import { BalloonEditor, DecoupledEditor } from "ckeditor5";
|
||||
export { EditorWatchdog } from "ckeditor5";
|
||||
|
||||
export class AttributeEditor extends BalloonEditor {
|
||||
static override get builtinPlugins() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export class ClassicEditor extends DecoupledEditor {
|
||||
static override get builtinPlugins() {
|
||||
return COMMON_PLUGINS;
|
||||
}
|
||||
}
|
||||
|
||||
export class PopupEditor extends BalloonEditor {
|
||||
static override get builtinPlugins() {
|
||||
return POPUP_EDITOR_PLUGINS;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Autoformat, AutoLink, BlockQuote, Bold, CKFinderUploadAdapter, Clipboard, Code, CodeBlock, Enter, FindAndReplace, Font, FontBackgroundColor, FontColor, GeneralHtmlSupport, Heading, HeadingButtonsUI, HorizontalLine, Image, ImageCaption, ImageInline, ImageResize, ImageStyle, ImageToolbar, ImageUpload, 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 } 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, 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 } from "ckeditor5";
|
||||
import type { Plugin } from "ckeditor5";
|
||||
import CutToNotePlugin from "./plugins/cuttonote.js";
|
||||
import UploadimagePlugin from "./plugins/uploadimage.js";
|
||||
@ -110,4 +110,9 @@ export const COMMON_PLUGINS: typeof Plugin[] = [
|
||||
Style
|
||||
];
|
||||
|
||||
export const POPUP_EDITOR_PLUGINS: typeof Plugin[] = [
|
||||
...COMMON_PLUGINS,
|
||||
BlockToolbar
|
||||
];
|
||||
|
||||
export const COMMON_SETTINGS = { };
|
||||
|
@ -4,10 +4,10 @@
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "../ckeditor5-math"
|
||||
"path": "../ckeditor5-footnotes"
|
||||
},
|
||||
{
|
||||
"path": "../ckeditor5-footnotes"
|
||||
"path": "../ckeditor5-math"
|
||||
},
|
||||
{
|
||||
"path": "../ckeditor5-admonition"
|
||||
|
@ -20,10 +20,10 @@
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../ckeditor5-math"
|
||||
"path": "../ckeditor5-footnotes"
|
||||
},
|
||||
{
|
||||
"path": "../ckeditor5-footnotes"
|
||||
"path": "../ckeditor5-math"
|
||||
},
|
||||
{
|
||||
"path": "../ckeditor5-admonition"
|
||||
|
Loading…
x
Reference in New Issue
Block a user