umbraco-monaco-markdown-editor-action
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseUmbraco Monaco Markdown Editor Action
Umbraco Monaco Markdown编辑器操作
What is it?
这是什么?
Monaco Markdown Editor Actions add custom toolbar buttons and keyboard shortcuts to the Markdown editor in Umbraco. They allow you to extend the editing experience with custom functionality like inserting links, images, or custom markdown syntax. Actions appear in the editor toolbar and can respond to keyboard shortcuts.
Monaco Markdown编辑器操作可在Umbraco的Markdown编辑器中添加自定义工具栏按钮和键盘快捷键。它们允许您通过插入链接、图片或自定义Markdown语法等功能扩展编辑体验。操作会显示在编辑器工具栏中,并且可响应键盘快捷键。
Documentation
文档
Always fetch the latest docs before implementing:
Related Foundation Skills
相关基础技能
-
Modals: When opening modal dialogs from actions
- Reference skill:
umbraco-modals
- Reference skill:
-
Localization: When providing localized labels
- Reference skill:
umbraco-localization
- Reference skill:
-
模态框:从操作中打开模态对话框时
- 参考技能:
umbraco-modals
- 参考技能:
-
本地化:提供本地化标签时
- 参考技能:
umbraco-localization
- 参考技能:
Workflow
工作流程
- Fetch docs - Use WebFetch on the URLs above
- Ask questions - What functionality? What keyboard shortcut? What icon?
- Generate files - Create manifest + action class based on latest docs
- Explain - Show what was created and how to test
- 获取文档 - 使用WebFetch访问上述URL
- 确认需求 - 需要什么功能?什么键盘快捷键?什么图标?
- 生成文件 - 根据最新文档创建清单文件(manifest)和操作类
- 说明解释 - 展示创建的内容以及测试方法
Minimal Examples
最简示例
Manifest (manifests.ts)
清单文件(manifests.ts)
typescript
export const manifests: Array<UmbExtensionManifest> = [
{
type: 'monacoMarkdownEditorAction',
alias: 'My.MonacoMarkdownEditorAction.Custom',
name: 'Custom Monaco Markdown Editor Action',
api: () => import('./my-markdown-action.js'),
meta: {
label: 'Insert Custom',
icon: 'icon-favorite',
},
},
];typescript
export const manifests: Array<UmbExtensionManifest> = [
{
type: 'monacoMarkdownEditorAction',
alias: 'My.MonacoMarkdownEditorAction.Custom',
name: 'Custom Monaco Markdown Editor Action',
api: () => import('./my-markdown-action.js'),
meta: {
label: 'Insert Custom',
icon: 'icon-favorite',
},
},
];Action Implementation (my-markdown-action.ts)
操作实现(my-markdown-action.ts)
typescript
import { monaco } from '@umbraco-cms/backoffice/external/monaco-editor';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type { UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui';
export class MyMarkdownAction extends UmbControllerBase {
constructor(host: UmbControllerHost) {
super(host);
}
getUnique() {
return 'My.MonacoMarkdownEditorAction.Custom';
}
getLabel() {
return 'Insert Custom';
}
getKeybindings() {
// Ctrl/Cmd + Shift + C
return [monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyC];
}
async execute({ editor, overlaySize }: { editor: any; overlaySize: UUIModalSidebarSize }) {
if (!editor) throw new Error('Editor not found');
const selection = editor.getSelections()[0];
if (!selection) return;
const selectedValue = editor.getValueInRange(selection);
// Insert custom markdown
editor.monacoEditor?.executeEdits('', [
{ range: selection, text: `**${selectedValue || 'custom'}**` },
]);
editor.monacoEditor?.focus();
}
}
export { MyMarkdownAction as api };typescript
import { monaco } from '@umbraco-cms/backoffice/external/monaco-editor';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type { UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui';
export class MyMarkdownAction extends UmbControllerBase {
constructor(host: UmbControllerHost) {
super(host);
}
getUnique() {
return 'My.MonacoMarkdownEditorAction.Custom';
}
getLabel() {
return 'Insert Custom';
}
getKeybindings() {
// Ctrl/Cmd + Shift + C
return [monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyC];
}
async execute({ editor, overlaySize }: { editor: any; overlaySize: UUIModalSidebarSize }) {
if (!editor) throw new Error('Editor not found');
const selection = editor.getSelections()[0];
if (!selection) return;
const selectedValue = editor.getValueInRange(selection);
// Insert custom markdown
editor.monacoEditor?.executeEdits('', [
{ range: selection, text: `**${selectedValue || 'custom'}**` },
]);
editor.monacoEditor?.focus();
}
}
export { MyMarkdownAction as api };Action with Modal
带模态框的操作
typescript
import { monaco } from '@umbraco-cms/backoffice/external/monaco-editor';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
export class MyModalMarkdownAction extends UmbControllerBase {
getUnique() {
return 'My.MonacoMarkdownEditorAction.Modal';
}
getLabel() {
return 'Insert with Modal';
}
getKeybindings() {
return [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyM];
}
async execute({ editor, overlaySize }) {
const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT);
if (!modalManager) throw new Error('Modal manager not found');
const selection = editor?.getSelections()[0];
if (!selection) return;
// Open a modal and use the result
const modalContext = modalManager.open(this, MY_CUSTOM_MODAL, {
modal: { size: overlaySize },
});
modalContext?.onSubmit().then((value) => {
if (!value) return;
editor.monacoEditor?.executeEdits('', [
{ range: selection, text: value.text },
]);
});
}
}
export { MyModalMarkdownAction as api };typescript
import { monaco } from '@umbraco-cms/backoffice/external/monaco-editor';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
export class MyModalMarkdownAction extends UmbControllerBase {
getUnique() {
return 'My.MonacoMarkdownEditorAction.Modal';
}
getLabel() {
return 'Insert with Modal';
}
getKeybindings() {
return [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyM];
}
async execute({ editor, overlaySize }) {
const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT);
if (!modalManager) throw new Error('Modal manager not found');
const selection = editor?.getSelections()[0];
if (!selection) return;
// Open a modal and use the result
const modalContext = modalManager.open(this, MY_CUSTOM_MODAL, {
modal: { size: overlaySize },
});
modalContext?.onSubmit().then((value) => {
if (!value) return;
editor.monacoEditor?.executeEdits('', [
{ range: selection, text: value.text },
]);
});
}
}
export { MyModalMarkdownAction as api };Interface Reference
接口参考
typescript
interface ManifestMonacoMarkdownEditorAction extends ManifestApi<any> {
type: 'monacoMarkdownEditorAction';
meta?: MetaMonacoMarkdownEditorAction;
}
interface MetaMonacoMarkdownEditorAction {
icon?: string | null;
label?: string | null; // Can use localization key like '#buttons_linkInsert'
}typescript
interface ManifestMonacoMarkdownEditorAction extends ManifestApi<any> {
type: 'monacoMarkdownEditorAction';
meta?: MetaMonacoMarkdownEditorAction;
}
interface MetaMonacoMarkdownEditorAction {
icon?: string | null;
label?: string | null; // Can use localization key like '#buttons_linkInsert'
}Common Key Bindings
常用快捷键
typescript
// Single key
monaco.KeyCode.Enter
// Ctrl/Cmd combinations
monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyK // Ctrl+K or Cmd+K
monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyC // Ctrl+Shift+C
monaco.KeyMod.Alt | monaco.KeyCode.KeyI // Alt+IThat's it! Always fetch fresh docs, keep examples minimal, generate complete working code.
typescript
// Single key
monaco.KeyCode.Enter
// Ctrl/Cmd combinations
monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyK // Ctrl+K or Cmd+K
monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyC // Ctrl+Shift+C
monaco.KeyMod.Alt | monaco.KeyCode.KeyI // Alt+I就是这样!请务必获取最新文档,保持示例简洁,生成完整可运行的代码。