mirror of
https://github.com/zadam/trilium.git
synced 2026-05-07 03:16:35 +02:00
feat(ckeditor): add a toolbar to switch admonition types
This commit is contained in:
@@ -32,6 +32,8 @@ import MoveBlockUpDownPlugin from "./plugins/move_block_updown.js";
|
||||
import ScrollOnUndoRedoPlugin from "./plugins/scroll_on_undo_redo.js"
|
||||
import InlineCodeNoSpellcheck from "./plugins/inline_code_no_spellcheck.js";
|
||||
import InlineCodeToolbar from "./plugins/inline_code_toolbar.js";
|
||||
import AdmonitionTypeDropdown from "./plugins/admonition_type_dropdown.js";
|
||||
import AdmonitionToolbar from "./plugins/admonition_toolbar.js";
|
||||
|
||||
/**
|
||||
* Plugins that are specific to Trilium and not part of the CKEditor 5 core, included in both text editors but not in the attribute editor.
|
||||
@@ -55,6 +57,8 @@ const TRILIUM_PLUGINS: typeof Plugin[] = [
|
||||
ScrollOnUndoRedoPlugin,
|
||||
InlineCodeNoSpellcheck,
|
||||
InlineCodeToolbar,
|
||||
AdmonitionTypeDropdown,
|
||||
AdmonitionToolbar,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
55
packages/ckeditor5/src/plugins/admonition_toolbar.ts
Normal file
55
packages/ckeditor5/src/plugins/admonition_toolbar.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { Plugin, ViewDocumentFragment, WidgetToolbarRepository, type ViewNode } from "ckeditor5";
|
||||
import { Admonition } from "@triliumnext/ckeditor5-admonition";
|
||||
import AdmonitionTypeDropdown from "./admonition_type_dropdown";
|
||||
|
||||
export default class AdmonitionToolbar extends Plugin {
|
||||
|
||||
static get requires() {
|
||||
return [WidgetToolbarRepository, Admonition, AdmonitionTypeDropdown] as const;
|
||||
}
|
||||
|
||||
afterInit() {
|
||||
const editor = this.editor;
|
||||
const widgetToolbarRepository = editor.plugins.get(WidgetToolbarRepository);
|
||||
|
||||
widgetToolbarRepository.register("admonition", {
|
||||
items: [
|
||||
"admonitionTypeDropdown"
|
||||
],
|
||||
balloonClassName: "ck-toolbar-container admonition-type-list",
|
||||
getRelatedElement(selection) {
|
||||
const selectionPosition = selection.getFirstPosition();
|
||||
if (!selectionPosition) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let parent: ViewNode | ViewDocumentFragment | null = selectionPosition.parent;
|
||||
while (parent) {
|
||||
if (parent.is("element", "aside") || parent.is("element", "div")) {
|
||||
// Check if it's an admonition by looking for the admonition class
|
||||
const classes = (parent as any).getAttribute?.("class") || "";
|
||||
if (typeof classes === "string" && classes.includes("admonition")) {
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
parent = parent.parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// Hide balloon toolbar when in an admonition
|
||||
if (editor.plugins.has("BalloonToolbar")) {
|
||||
editor.listenTo(editor.plugins.get("BalloonToolbar"), "show", (evt) => {
|
||||
const firstPosition = editor.model.document.selection.getFirstPosition();
|
||||
const isInAdmonition = firstPosition?.findAncestor("aside");
|
||||
|
||||
if (isInAdmonition) {
|
||||
evt.stop(); // Prevent the balloon toolbar from showing
|
||||
}
|
||||
}, { priority: "high" });
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
79
packages/ckeditor5/src/plugins/admonition_type_dropdown.ts
Normal file
79
packages/ckeditor5/src/plugins/admonition_type_dropdown.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { Plugin, type ListDropdownButtonDefinition, Collection, ViewModel, createDropdown, addListToDropdown, DropdownButtonView } from "ckeditor5";
|
||||
import { Admonition, ADMONITION_TYPES, type AdmonitionCommand, type AdmonitionType } from "@triliumnext/ckeditor5-admonition";
|
||||
|
||||
const ADMONITION_ICONS: Record<AdmonitionType, string> = {
|
||||
note: "📝",
|
||||
tip: "💡",
|
||||
important: "📌",
|
||||
caution: "⚠️",
|
||||
warning: "🚨"
|
||||
};
|
||||
|
||||
/**
|
||||
* Toolbar item which displays the list of admonition types in a dropdown.
|
||||
*/
|
||||
export default class AdmonitionTypeDropdown extends Plugin {
|
||||
|
||||
static get requires() {
|
||||
return [Admonition] as const;
|
||||
}
|
||||
|
||||
public init() {
|
||||
const editor = this.editor;
|
||||
const componentFactory = editor.ui.componentFactory;
|
||||
|
||||
const itemDefinitions = this._getTypeListItemDefinitions();
|
||||
const command = editor.commands.get("admonition") as AdmonitionCommand;
|
||||
|
||||
componentFactory.add("admonitionTypeDropdown", _locale => {
|
||||
const dropdownView = createDropdown(editor.locale, DropdownButtonView);
|
||||
dropdownView.buttonView.set({
|
||||
withText: true
|
||||
});
|
||||
dropdownView.bind("isEnabled").to(command, "value", value => !!value);
|
||||
dropdownView.buttonView.bind("label").to(command, "value", (value) => {
|
||||
if (!value) return "";
|
||||
const typeDef = ADMONITION_TYPES[value as AdmonitionType];
|
||||
const icon = ADMONITION_ICONS[value as AdmonitionType];
|
||||
return typeDef ? `${icon} ${typeDef.title}` : value;
|
||||
});
|
||||
dropdownView.on("execute", evt => {
|
||||
const source = evt.source as any;
|
||||
editor.execute("admonition", {
|
||||
forceValue: source._admonitionType
|
||||
});
|
||||
editor.editing.view.focus();
|
||||
});
|
||||
addListToDropdown(dropdownView, itemDefinitions);
|
||||
return dropdownView;
|
||||
});
|
||||
}
|
||||
|
||||
private _getTypeListItemDefinitions(): Collection<ListDropdownButtonDefinition> {
|
||||
const editor = this.editor;
|
||||
const command = editor.commands.get("admonition") as AdmonitionCommand;
|
||||
const itemDefinitions = new Collection<ListDropdownButtonDefinition>();
|
||||
|
||||
for (const [type, typeDef] of Object.entries(ADMONITION_TYPES)) {
|
||||
const icon = ADMONITION_ICONS[type as AdmonitionType];
|
||||
const definition: ListDropdownButtonDefinition = {
|
||||
type: "button",
|
||||
model: new ViewModel({
|
||||
_admonitionType: type,
|
||||
label: `${icon} ${typeDef.title}`,
|
||||
role: "menuitemradio",
|
||||
withText: true
|
||||
})
|
||||
};
|
||||
|
||||
definition.model.bind("isOn").to(command, "value", value => {
|
||||
return value === type;
|
||||
});
|
||||
|
||||
itemDefinitions.add(definition);
|
||||
}
|
||||
|
||||
return itemDefinitions;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user