diff --git a/site/demo.html b/site/demo.html index 4c6c574..1a01f5b 100644 --- a/site/demo.html +++ b/site/demo.html @@ -156,23 +156,28 @@
-

- MetonaEditor 功能演示 - ← 返回首页 -

-
- 主题 -
- - - -
- 语言 -
- - -
-
+

+ MetonaEditor 功能演示 + ← 返回首页 + 📖 文档 +

+
+ 主题 +
+ + + +
+ 语言 +
+ + +
+ 模式 +
+ +
+
@@ -214,6 +219,7 @@ +
@@ -299,6 +305,8 @@ '## 行内格式', '', '- 支持 **加粗**、*斜体*、~~删除线~~、`行内代码`', + '- 高亮 ==重点标记== 、上标 x^2^、下标 H~2~O', + '- Emoji 短码 :smile: :rocket: :fire: :tada:', '- 支持 [链接](https://example.com) 与 ![图片](https://placehold.co/100)', '', '## 表格', @@ -328,7 +336,7 @@ '', '右侧事件流会实时显示编辑器触发的事件。' ].join('\n'), - plugins: ['autoSave', 'exportTool', 'searchReplace'], + plugins: ['autoSave', 'exportTool', 'searchReplace', 'imagePaste'], onChange: (val) => { logEvent('change', val); updateStatus(); }, onInput: (val) => logEvent('input', val), onFocus: () => logEvent('focus'), @@ -364,6 +372,16 @@ }); document.querySelector('#localeCtrl [data-locale="zh-CN"]').classList.add('active'); + // 只读切换 + document.getElementById('btnReadOnly').addEventListener('click', () => { + const isRO = editor.isReadOnly(); + editor.setReadOnly(!isRO); + document.getElementById('btnReadOnly').classList.toggle('active', !isRO); + document.getElementById('btnReadOnly').textContent = !isRO ? '只读中' : '只读'; + log('setReadOnly', String(!isRO)); + updateStatus(); + }); + // API 控制台 document.querySelector('.api-grid').addEventListener('click', (e) => { const btn = e.target.closest('[data-api]'); @@ -388,6 +406,7 @@ case 'exportHTML': editor.exportHTML('demo.html', { title: 'MetonaEditor 导出' }); log('export', '已触发 .html 下载'); break; case 'restoreDraft': editor.restoreDraft(); log('restoreDraft', '已从 localStorage 恢复草稿'); break; case 'clearDraft': editor.clearDraft(); log('clearDraft', '已清空草稿'); break; + case 'refresh': editor.refresh(); log('refresh', '强制刷新预览'); break; case 'destroy': editor.destroy(); log('destroy', '编辑器已销毁'); updateStatus(); break; } }); diff --git a/site/docs.html b/site/docs.html new file mode 100644 index 0000000..9d776e5 --- /dev/null +++ b/site/docs.html @@ -0,0 +1,621 @@ + + + + + +MetonaEditor · 文档 + + + + + + +
+

文档

+

MetonaEditor v0.1.3 完整 API、配置与使用指南

+
+ +
+
+ + +
+ + +
+

安装与引入

+ +
# npm 安装
+npm install @metona-team/metona-editor
+
+# ES Module
+import MeEditor from '@metona-team/metona-editor';
+const editor = MeEditor.create('#editor', {
+  value: '# Hello World',
+  mode: 'split',
+});
+
+# 浏览器 UMD
+<script src="dist/metona-editor.js"></script>
+<script>
+const editor = MeEditor.create('#editor');
+</script>
+
+ + +
+

全部配置项

+

所有配置均为可选,以下是默认值:

+ +
MeEditor.create(container, {
+  // 内容
+  value: '',              // 初始 Markdown 文本
+  placeholder: '',        // 占位符
+
+  // 视图
+  mode: 'split',          // 'edit' | 'split' | 'preview'
+  height: 400,            // 数字为 px,字符串原样使用
+  toolbar: DEFAULT_TOOLBAR, // 工具栏配置,false 隐藏
+  wordCount: true,        // 字数统计状态栏
+
+  // 行为
+  autofocus: false,       // 自动聚焦
+  spellcheck: false,      // 拼写检查
+  readOnly: false,        // 只读模式
+  historyLimit: 100,      // 历史栈上限
+  historyDebounce: 400,   // 历史防抖延迟(ms)
+  syncScroll: true,       // 分屏模式同步滚动
+  tabSize: 2,             // 制表符空格数(0 表示 \t)
+
+  // 主题与国际化
+  theme: 'auto',          // 'light' | 'dark' | 'auto' | 'warm' | 自定义
+  locale: 'zh-CN',        // 'zh-CN' | 'en-US' | 自定义
+
+  // 自定义渲染
+  render: null,           // (md, env) => html
+  highlight: null,        // (code, lang) => html
+  sanitize: null,         // (html) => safeHtml
+
+  // 外观
+  className: '',          // 容器额外 class
+  style: {},              // 内联样式
+
+  // 插件与回调
+  plugins: [],            // 实例级插件数组
+  onChange: null,         // (value, editor) => void
+  onInput: null,          // (value, editor) => void
+  onFocus: null,          // (editor) => void
+  onBlur: null,           // (editor) => void
+  onSave: null,           // (value, editor) => void
+  onModeChange: null,     // (mode, editor) => void
+  onFullscreen: null,    // (fullscreen, editor) => void
+  onCreate: null,         // (editor) => void
+  onDestroy: null,        // (editor) => void
+});
+
+ + +
+

工具栏配置

+ +
// 默认工具栏(完整按钮)
+MeEditor.create(container, { toolbar: true });
+
+// 隐藏工具栏
+MeEditor.create(container, { toolbar: false });
+
+// 自定义工具栏 — '|' 为分隔符
+MeEditor.create(container, {
+  toolbar: ['bold', 'italic', '|', 'h1', 'h2', '|', 'undo', 'redo'],
+});
+ +

可用动作:

+

+bolditalicstrikethroughunderlinecode +h1h2h3quoteulol +indentoutdenthr +linkimagetable +undoredo +editsplitpreviewfullscreen +

+
+ + +
+

实例 API

+ +

内容操作

+
editor.getValue();                    // 获取 Markdown 文本
+editor.setValue(md, { silent });      // 设置内容,silent 不触发 change
+editor.getHTML();                     // 获取渲染后的 HTML
+editor.refresh();                     // 强制刷新预览(内容未变时)
+editor.insert(text, { replace });     // 光标处插入 / 替换选区
+editor.wrap(before, after);           // 选区包裹
+editor.focus();                       // 聚焦
+editor.blur();                        // 失焦
+
+ +
+

命令执行

+
editor.exec(action, ...args);         // 执行命令,返回 this 链式调用
+
+editor.exec('bold').exec('h1');        // 链式调用
+ + + + + + + + + + + + + + + + + + + +
action效果快捷键
bold加粗 **text**Ctrl+B
italic斜体 *text*Ctrl+I
strikethrough删除线 ~~text~~
underline下划线 <u>text</u>Ctrl+U
code行内代码 `text`Ctrl+E
h1/h2/h3标题 # / ## / ###Ctrl+1/2/3
quote引用 >Ctrl+Q
ul/ol无序/有序列表
indent/outdent缩进/反缩进Tab/Shift+Tab
hr水平线 ---
link插入链接 [text](url)Ctrl+K
image插入图片 ![alt](url)
table插入表格
undo/redo撤销/重做Ctrl+Z / Ctrl+Y
edit/split/preview切换模式
fullscreen切换全屏
+
+ +
+

历史栈

+
editor.undo();                        // 撤销
+editor.redo();                        // 重做
+editor.canUndo();                     // 是否可撤销
+editor.canRedo();                     // 是否可重做
+
+ +
+

模式与全屏

+
editor.setMode('split');              // 设置模式:edit | split | preview
+editor.getMode();                     // 获取当前模式
+editor.toggleFullscreen();            // 切换全屏
+editor.exitFullscreen();              // 退出全屏
+editor.isFullscreen();                // 是否全屏
+
+ +
+

统计与状态

+
editor.getStats();
+// => { characters, words, chineseChars, englishWords, lines, readingTime }
+
+editor.getStatus();
+// => { id, mode, theme, locale, fullscreen, readOnly, disabled, destroyed, plugins }
+
+ +
+

启用/禁用/只读

+
editor.enable();                      // 启用
+editor.disable();                     // 禁用
+editor.isDisabled();                  // 是否禁用
+editor.setReadOnly(true);             // 只读模式
+editor.isReadOnly();                  // 是否只读
+
+ +
+

事件系统

+ + + + + + + + + + + + + + +
事件名触发时机回调参数
inputtextarea 原生 input(value, editor)
change内容变化(value, editor)
focus聚焦(editor)
blur失焦(editor)
saveCtrl+S(value, editor)
modeChange模式切换(mode, editor)
fullscreen全屏切换(fullscreen, editor)
destroy销毁()
autosaveautoSave 保存({ key, value })
beforeRender渲染前(editor)
afterRender渲染后(editor)
+ +

全局钩子(所有实例共享)

+ + + + + + + + +
钩子触发时机
beforeCreate构造函数初始化前
afterCreate构造函数初始化完成
beforeRender每次渲染前(全局)
afterRender每次渲染后(全局)
beforeDestroydestroy 前
afterDestroydestroy 后
+
+ +
+

插件管理

+
editor.use(plugin, options);          // 安装插件
+editor.getPlugins();                  // 获取已安装插件列表
+editor.addToolbarButton(config);      // 追加工具栏按钮
+
+ +
+

生命周期

+
editor.destroy();                     // 销毁实例
+editor.isDestroyed();                 // 是否已销毁
+
+ + +
+

静态 API

+ +
import MeEditor from '@metona-team/metona-editor';
+
+// 工厂函数
+MeEditor.create(container, options);
+
+// 全局默认插件
+MeEditor.use(presetPlugins.autoSave, { delay: 2000 });
+MeEditor.use('searchReplace');
+MeEditor.use(customPlugin);
+
+// 全局事件钩子
+MeEditor.on('beforeCreate', (editor) => {});
+MeEditor.off('beforeCreate', handler);
+
+// 主题与语言
+MeEditor.setTheme('dark');
+MeEditor.setLocale('en-US');
+
+// 状态查询
+MeEditor.getStatus(); // => { version, theme, locale, globalPlugins, presetPlugins }
+
+// 销毁全局资源
+MeEditor.destroy();
+
+// 内置解析器
+import { parseMarkdown, safeUrl, slugify } from '@metona-team/metona-editor';
+parseMarkdown('# Hello');           // => '<h1 id="hello">Hello</h1>'
+safeUrl('javascript:alert(1)');     // => ''
+slugify('Hello World');             // => 'hello-world'
+
+ + +
+

解析器语法参考

+ + + + + + + + + + + + + + + + + + + + + + + +
语法示例输出
标题# H1 ~ ###### H6<h1> ~ <h6>
段落纯文本<p>
粗体**bold** __bold__<strong>
斜体*italic* _italic_<em>
删除线~~text~~<del>
高亮标记==text==<mark>
上标x^2^<sup>
下标H~2~O<sub>
行内代码`code`<code>
代码块```lang<pre><code>
引用> quote<blockquote>
无序列表- item<ul><li>
有序列表1. item<ol><li>
任务列表- [x] done<li class="me-task-item">
水平线--- *** ___<hr>
表格| a | b |<table>(支持 :---: 列对齐)
链接[text](url)<a>
图片![alt](url)<img>
自动链接<https://...><a>
Emoji:smile: :rocket:😊 🚀(80+ 常用)
+ +

XSS 防护

+

所有文本经 HTML 转义。URL 自动过滤 javascript: vbscript: file: 及非图片 data: 协议。

+
+ + +
+

插件约定

+ +
const myPlugin = {
+  name: 'myPlugin',
+  description: '我的自定义插件',
+
+  install(editor, options) {
+    // this 指向插件对象本身
+    this._timer = null;
+    editor.on('change', this._onChange);
+  },
+
+  destroy(editor) {
+    if (this._timer) clearTimeout(this._timer);
+    editor.off('change', this._onChange);
+  },
+};
+
+ +
+

预设插件

+ +

autoSave — 自动保存草稿

+
editor.use(presetPlugins.autoSave, {
+  key: 'me-draft-' + editor.id,  // localStorage key
+  delay: 1000,                    // 防抖延迟(ms)
+});
+editor.restoreDraft();             // 恢复草稿
+editor.clearDraft();               // 清除草稿
+editor.getDraftKey();              // 获取存储 key
+ +

exportTool — 导出文件

+
editor.use(presetPlugins.exportTool);
+editor.exportMarkdown('my-doc.md');
+editor.exportHTML('my-doc.html', {
+  title: '文档标题',
+  css: 'body { font-family: sans-serif; }',
+  lang: 'zh-CN',
+});
+ +

searchReplace — 查找替换

+
editor.use(presetPlugins.searchReplace);
+// Ctrl+F → 查找  Ctrl+H → 替换
+// Enter → 下一个  Shift+Enter → 上一个  Escape → 关闭
+ +

imagePaste — 粘贴图片转 base64

+
editor.use(presetPlugins.imagePaste);
+// 在编辑区 Ctrl+V 粘贴剪贴板图片
+// 自动插入 ![](data:image/png;base64,...)
+
+ + +
+

主题系统

+ +
// 切换主题
+MeEditor.setTheme('light');         // 亮色
+MeEditor.setTheme('dark');          // 暗色
+MeEditor.setTheme('warm');          // 暖色
+MeEditor.setTheme('auto');          // 自动(默认)
+
+// 注册自定义主题
+import { themeUtils } from '@metona-team/metona-editor';
+themeUtils.registerTheme('ocean', {
+  bg: '#001122', text: '#aabbcc', accent: '#00ddff',
+});
+themeUtils.applyTheme('ocean');
+ +

CSS 变量:主题变量限定在 .me-wrapper 元素上,不污染全局样式。支持 @media print 打印样式。

+
+ + +
+

国际化

+ +
// 切换语言
+MeEditor.setLocale('en-US');
+MeEditor.setLocale('zh-CN');
+
+// 翻译函数
+import { i18nUtils } from '@metona-team/metona-editor';
+i18nUtils.t('bold');                 // => '粗体'(zh-CN)
+i18nUtils.t('bold');                 // => 'Bold'(en-US)
+
+// 添加语言
+i18nUtils.addTranslations('ja', { bold: '太字', italic: '斜体' });
+
+// 格式化
+i18nUtils.formatNumber(1234567);              // => '1,234,567'
+i18nUtils.formatCurrency(99.99, 'USD');       // => '$99.99'
+i18nUtils.formatDate('2024-01-15');           // => '1/15/2024'
+
+ +
+
+
+ + + + + + + diff --git a/site/index.html b/site/index.html index 85c36f4..869e384 100644 --- a/site/index.html +++ b/site/index.html @@ -386,13 +386,14 @@ MetonaEditor - + @@ -668,12 +669,13 @@