/** * MetonaEditor - 轻量级 Markdown Editor 库 * @module metona-editor * @version 0.1.14 * @author thzxx * @description 现代化、零依赖、易扩展、易维护、易使用的 Markdown 编辑器库。单文件,开箱即用。 * @license MIT * * 用法: * // 浏览器 * * 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, };