Files
MetonaEditor/src/index.js
T
thzxx b9e98a4ff4 release: v0.1.14 — syntax highlight, Mermaid, fileSystem, preview links
feat(core): syntax highlight editor overlay
- Transparent highlight-layer behind textarea with regex-based token coloring
- Supports heading, bold, italic, strikethrough, code, link, image, list, quote, hr
- Scroll-synced with textarea, config.syntaxHighlight toggle

feat(core): preview link click interception
- Clicks on preview links intercepted, emitted as 'linkClick' event
- Configurable via onLinkClick(uri, text, editor) callback
- Default: opens in new tab, anchor links pass through

feat(parser): Mermaid diagram rendering
- ```mermaid code blocks render as <div class="me-mermaid"><pre class="mermaid">

feat(plugins): fileSystem plugin (IndexedDB persistence)
- saveToFile(id) / loadFromFile(id) / deleteFile(id) / listFiles()
- Uses IndexedDB 'metona-editor-fs' database

feat(config): maxLength (char limit), syntaxHighlight toggle

style: syntax highlight theme colors, Mermaid container

chore: bump version 0.1.13 → 0.1.14 across all files
2026-07-24 17:16:55 +08:00

275 lines
7.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* MetonaEditor - 轻量级 Markdown Editor 库
* @module metona-editor
* @version 0.1.14
* @author thzxx
* @description 现代化、零依赖、易扩展、易维护、易使用的 Markdown 编辑器库。单文件,开箱即用。
* @license MIT
*
* 用法:
* // 浏览器
* <script src="dist/metona-editor.js"></script>
* const editor = MeEditor.create('#editor', { mode: 'split' });
*
* // ES Module
* import MeEditor from 'metona-editor';
* const editor = MeEditor.create(container, options);
*
* // 直接使用类
* import { MarkdownEditor } from 'metona-editor';
* const editor = new MarkdownEditor(container, options);
*/
import { MarkdownEditor } from './core.js';
import { parseMarkdown, safeUrl, slugify, clearRenderCache } from './parser.js';
import { themeUtils, exportCSSVars, getCSSVariable, followExternalTheme, adoptFromParent, createInstanceTheme } from './themes.js';
import { i18nUtils, createInstanceI18n, loadRemote } from './i18n.js';
import { pluginUtils, presetPlugins, topologicalSort, validateConfig } from './plugins.js';
import { animationUtils } from './animations.js';
import { DEFAULTS, ICONS, THEMES, EDIT_MODES, DEFAULT_TOOLBAR, TOOLBAR_ACTIONS } from './constants.js';
// 版本信息
const VERSION = '0.1.14';
/**
* 全局默认插件队列
* 通过 beforeCreate 钩子自动应用到所有后续创建的编辑器实例
*/
const globalPlugins = [];
// 注册全局钩子:每个新实例创建时自动安装全局默认插件
// 注意:core.js 构造函数中 beforeCreate 在 config.plugins 安装之前触发,
// 且 this._plugins 已初始化为 [],因此此处调用 editor.use() 安全。
MarkdownEditor.on('beforeCreate', (editor) => {
if (!editor || editor._destroyed) return;
globalPlugins.forEach((p) => {
try { editor.use(p); } catch (e) { console.error('MeEditor global plugin install error:', e); }
});
});
/**
* 创建编辑器实例(工厂函数,推荐用法)
* @param {string|HTMLElement} container - 容器选择器或 DOM 元素
* @param {Object} [options] - 配置项(见 DEFAULTS
* @returns {MarkdownEditor} 编辑器实例
*/
function create(container, options = {}) {
return new MarkdownEditor(container, options);
}
/**
* 注册全局默认插件(作用于所有后续创建的编辑器实例)
* @param {string|Object} plugin - 预设插件名 或 插件对象
* @param {Object} [options] - 插件配置(覆盖预设默认值)
* @returns {typeof api} 返回 api 自身以支持链式调用
*/
function use(plugin, options = {}) {
let p = plugin;
if (typeof plugin === 'string') {
p = presetPlugins[plugin];
if (!p) {
console.warn(`MeEditor: preset plugin "${plugin}" not found`);
return api;
}
}
if (!p || typeof p !== 'object') {
console.warn('MeEditor: invalid plugin');
return api;
}
const merged = (options && typeof options === 'object' && Object.keys(options).length > 0)
? { ...p, ...options }
: p;
globalPlugins.push(merged);
return api;
}
/**
* 注册全局事件钩子(转发到 MarkdownEditor 静态钩子,所有实例共享)
* 可用钩子:beforeCreate / afterCreate / beforeRender / afterRender / beforeDestroy / afterDestroy
* @param {string} name - 钩子名
* @param {Function} fn - 回调 (editor) => void
* @returns {Function} 取消注册函数
*/
function on(name, fn) {
return MarkdownEditor.on(name, fn);
}
/**
* 注销全局事件钩子
*/
function off(name, fn) {
MarkdownEditor.off(name, fn);
return api;
}
/**
* 切换全局主题(转发到 themeUtils
*/
function setTheme(theme, options) {
if (themeUtils && typeof themeUtils.switchTheme === 'function') {
themeUtils.switchTheme(theme, options);
}
return api;
}
/**
* 切换全局语言(转发到 i18nUtils)
*/
function setLocale(locale) {
if (i18nUtils && typeof i18nUtils.setCurrentLocale === 'function') {
i18nUtils.setCurrentLocale(locale);
}
return api;
}
/**
* 销毁所有全局资源(主题监听、i18n 监听、动画、全局插件队列)
* 注意:此方法不销毁已创建的编辑器实例,请单独调用每个实例的 destroy()
*/
function destroy() {
if (themeUtils) {
if (typeof themeUtils.clearThemeListeners === 'function') {
try { themeUtils.clearThemeListeners(); } catch (_) {}
}
if (typeof themeUtils.unwatchSystemTheme === 'function') {
try { themeUtils.unwatchSystemTheme(); } catch (_) {}
}
}
if (i18nUtils && typeof i18nUtils.clearLocaleListeners === 'function') {
try { i18nUtils.clearLocaleListeners(); } catch (_) {}
}
if (animationUtils && typeof animationUtils.cancelAll === 'function') {
try { animationUtils.cancelAll(); } catch (_) {}
}
globalPlugins.length = 0;
}
/**
* 获取库运行状态
*/
function getStatus() {
return {
version: VERSION,
theme: (themeUtils && typeof themeUtils.getCurrentTheme === 'function') ? themeUtils.getCurrentTheme() : 'auto',
locale: (i18nUtils && typeof i18nUtils.getCurrentLocale === 'function') ? i18nUtils.getCurrentLocale() : 'zh-CN',
globalPlugins: globalPlugins.map((p) => p.name || 'custom'),
presetPlugins: Object.keys(presetPlugins || {}),
};
}
// 初始化主题与国际化(浏览器环境)
if (typeof themeUtils === 'object' && typeof themeUtils.initTheme === 'function') {
try { themeUtils.initTheme(); } catch (_) {}
}
if (typeof i18nUtils === 'object' && typeof i18nUtils.initI18n === 'function') {
try { i18nUtils.initI18n(); } catch (_) {}
}
/**
* 顶层 API 对象(默认导出)
*/
const api = {
// 版本
VERSION,
version: VERSION,
// 核心类
MarkdownEditor,
Editor: MarkdownEditor,
// 工厂函数(推荐入口)
create,
// 顶层 API
use,
on,
off,
setTheme,
setLocale,
destroy,
getStatus,
// 内置解析器(可单独使用或替换)
parseMarkdown,
safeUrl,
slugify,
clearRenderCache,
// 工具集
themes: themeUtils,
i18n: i18nUtils,
animations: animationUtils,
plugins: pluginUtils,
presetPlugins,
// 插件工具(v0.1.6
topologicalSort,
validateConfig,
// i18n 工具(v0.1.6
createInstanceI18n,
loadRemote,
// 主题工具(v0.1.5 新增)
exportCSSVars,
getCSSVariable,
followExternalTheme,
adoptFromParent,
createInstanceTheme,
// 常量
DEFAULTS,
ICONS,
THEMES,
EDIT_MODES,
DEFAULT_TOOLBAR,
TOOLBAR_ACTIONS,
};
// 浏览器环境全局注册(UMD/CDN 场景:window.MeEditor
if (typeof window !== 'undefined') {
window.MeEditor = api;
}
export default api;
export {
api,
api as meEditor,
api as MeEditor,
MarkdownEditor,
MarkdownEditor as Editor,
create,
use,
on,
off,
setTheme,
setLocale,
destroy,
getStatus,
parseMarkdown,
safeUrl,
slugify,
clearRenderCache,
themeUtils,
i18nUtils,
pluginUtils,
presetPlugins,
animationUtils,
topologicalSort,
validateConfig,
createInstanceI18n,
loadRemote,
exportCSSVars,
getCSSVariable,
followExternalTheme,
adoptFromParent,
createInstanceTheme,
DEFAULTS,
ICONS,
THEMES,
EDIT_MODES,
DEFAULT_TOOLBAR,
TOOLBAR_ACTIONS,
VERSION,
};