release: v0.1.2 — readOnly, new syntax, plugins, optimizations

Features:
- feat(core): readOnly mode with config option and setReadOnly() API
- feat(parser): superscript ^text^ and subscript ~text~ support
- feat(parser): highlight/mark ==text== syntax
- feat(parser): table column alignment with colons (:---, :---:, ---:)
- feat(parser): emoji shortcodes 😄😊 (80+ common emojis)
- feat(plugins): imagePaste preset — paste clipboard images as base64
- feat(core): instance-level beforeRender/afterRender events
- feat(styles): print stylesheet (@media print)
- feat(styles): mark element CSS styling
- feat(styles): readOnly mode CSS (.me-readonly)

Optimizations:
- perf(core): history debounce now configurable via historyDebounce option
- perf(core): skip _render() in edit-only mode (already guarded)
- fix(core): divider drag division-by-zero guard
- fix(core): config.style deep merge with DEFAULTS
- fix(core): scroll position preserved across mode switches

Tests:
- 9 new test cases: readOnly (3), parser syntax (6)
- Total: 418 tests passing (+9 from v0.1.1)

Chores:
- version bump 0.1.1 → 0.1.2
- TypeScript definitions updated for new APIs
This commit is contained in:
2026-07-23 20:53:36 +08:00
parent e3142a17a8
commit 12875921eb
18 changed files with 257 additions and 26 deletions
+43 -1
View File
@@ -1,7 +1,7 @@
/**
* MetonaEditor Plugins - 插件系统
* @module plugins
* @version 0.1.1
* @version 0.1.2
* @description 插件管理器 + 预设插件(autoSave / exportTool / searchReplace
*
* 插件约定:
@@ -419,6 +419,47 @@ const searchReplacePlugin = {
},
};
/**
* 图片粘贴插件
* 监听 textarea 粘贴事件,自动将剪贴板中的图片转换为 base64 data URI 并插入。
*/
const imagePastePlugin = {
name: 'imagePaste',
description: '粘贴图片自动转为 base64 内联',
_onPaste: null,
install(editor) {
if (!editor || !editor.textarea || typeof document === 'undefined') return;
this._onPaste = (e) => {
const items = e.clipboardData && e.clipboardData.items;
if (!items) return;
for (const item of items) {
if (item.type && item.type.startsWith('image/')) {
e.preventDefault();
const reader = new FileReader();
reader.onload = () => {
const dataUri = reader.result;
const name = `image-${Date.now().toString(36)}.png`;
editor.insert(`![${name}](${dataUri})\n`);
};
reader.readAsDataURL(item.getAsFile());
break;
}
}
};
editor.textarea.addEventListener('paste', this._onPaste);
},
destroy(editor) {
if (this._onPaste && editor && editor.textarea) {
editor.textarea.removeEventListener('paste', this._onPaste);
}
this._onPaste = null;
},
};
/**
* 预设插件注册表
*/
@@ -426,6 +467,7 @@ const presetPlugins = {
autoSave: autoSavePlugin,
exportTool: exportToolPlugin,
searchReplace: searchReplacePlugin,
imagePaste: imagePastePlugin,
};
/**