From c6db68af59a9155b00734a5d70beb2de9de83e32 Mon Sep 17 00:00:00 2001 From: thzxx <1440196015@qq.com> Date: Fri, 24 Jul 2026 18:10:27 +0800 Subject: [PATCH] revert: remove syntax highlighting feature entirely Syntax highlighting overlay approach proved too fragile: - pixel alignment between textarea and overlay unreliable - transparent textarea caused invisible content bugs - dynamic gutter width positioning added complexity Removed: - _highlightEditor, _doHighlight, toggleSyntaxHighlight, _positionHighlightLayer - highlightLayer DOM element creation - .me-highlight-layer, .mh-*, .me-textarea-highlight CSS - syntaxHighlight config option from DEFAULTS - highlight toggle button from demo.html Kept: Mermaid, fileSystem, preview links, all other v0.1.14 features --- site/demo.html | 3 -- src/constants.js | 2 -- src/core.js | 94 +----------------------------------------------- src/styles.js | 25 ------------- 4 files changed, 1 insertion(+), 123 deletions(-) diff --git a/site/demo.html b/site/demo.html index 392470d..235f780 100644 --- a/site/demo.html +++ b/site/demo.html @@ -68,7 +68,6 @@ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Micr
- @@ -199,7 +198,6 @@ var editor=MeEditor.create('#editor',{ value:demoMd, mode:'split',height:620, lineNumbers:true,autoBrackets:true,wordCount:true, - syntaxHighlight:true, theme:'auto',locale:'zh-CN', outline:false, plugins:['autoSave','exportTool','searchReplace','imagePaste','shortcutHelp','fileSystem'], @@ -229,7 +227,6 @@ bar.addEventListener('click',function(e){ if(cmd==='mode'){editor.setMode(btn.dataset.arg);updateModeBtns(btn.dataset.arg);} else if(cmd==='zen'){editor.toggleZen();btn.classList.toggle('on',editor.isZen());} else if(cmd==='outline'){toggleOutline(btn);} - else if(cmd==='highlight'){editor.toggleSyntaxHighlight();btn.classList.toggle('on',editor.config.syntaxHighlight);} else if(cmd==='wrap'){editor.toggleWordWrap();btn.classList.toggle('on',!editor.isWordWrap());} else if(cmd==='toast'){ var types=['success','error','warning','info']; diff --git a/src/constants.js b/src/constants.js index fbb3bf6..6dfb396 100644 --- a/src/constants.js +++ b/src/constants.js @@ -62,8 +62,6 @@ export const DEFAULTS = Object.freeze({ wordWrap: true, // 最大字符数(v0.1.14,0=不限) maxLength: 0, - // 语法高亮编辑区(v0.1.14) - syntaxHighlight: true, // 主题:light / dark / auto / warm / 自定义 theme: 'auto', // 国际化 diff --git a/src/core.js b/src/core.js index 0280f45..f505445 100644 --- a/src/core.js +++ b/src/core.js @@ -6,7 +6,7 @@ * v0.1.6: 插件依赖拓扑排序、实例 i18n、快捷键/工具栏定制、右键菜单、Toast * v0.1.7: 行号装订线、自动格式化、括号自动闭合、拖放、大纲面板 * v0.1.12: 工具栏键盘导航、aria-live、Zen模式、滚动同步v2、WordWrap - * v0.1.14: 语法高亮编辑区、图片上传钩子、预览链接拦截、Mermaid、文件存储 + * v0.1.14: 预览链接拦截、Mermaid、文件存储 */ import { generateId, escapeHTML, isBrowser } from './utils.js'; @@ -115,7 +115,6 @@ class MarkdownEditor { this._zenMode = false; // v0.1.12: Zen 模式 this._wordWrap = true; // v0.1.12: 自动换行 this._syncing = false; // 滚动同步锁 - this._hlRaf = null; // v0.1.14: 高亮节流 // 渲染函数:自定义覆盖内置解析器 this._renderFn = (typeof this.config.render === 'function') ? this.config.render : parseMarkdown; @@ -217,12 +216,6 @@ class MarkdownEditor { if (!this.config.lineNumbers) gutter.style.display = 'none'; editorInner.appendChild(gutter); - // 语法高亮叠加层(v0.1.14) - const highlightLayer = document.createElement('pre'); - highlightLayer.className = 'me-highlight-layer'; - highlightLayer.setAttribute('aria-hidden', 'true'); - editorInner.appendChild(highlightLayer); - const textarea = document.createElement('textarea'); textarea.className = 'me-textarea'; textarea.spellcheck = !!this.config.spellcheck; @@ -230,12 +223,6 @@ class MarkdownEditor { textarea.style.tabSize = String(this.config.tabSize || 2); textarea.placeholder = this.config.placeholder || i18nT('placeholder'); textarea.setAttribute('aria-label', i18nT('edit')); - if (this.config.syntaxHighlight) { - textarea.classList.add('me-textarea-highlight'); - } - if (highlightLayer && !this.config.syntaxHighlight) { - highlightLayer.hidden = true; - } editorInner.appendChild(textarea); editorPane.appendChild(editorInner); @@ -276,7 +263,6 @@ class MarkdownEditor { this.editorPane = editorPane; this.editorInner = editorInner; this.gutter = gutter; - this.highlightLayer = highlightLayer; this.previewPane = previewPane; this.dividerEl = divider; this.textarea = textarea; @@ -343,7 +329,6 @@ class MarkdownEditor { this._updateWordCount(); this._renderGutter(); this._updateOutline(); - this._highlightEditor(); // v0.1.14 this._emit('input', this._value); this._emit('change', this._value); if (typeof this.config.onInput === 'function') { @@ -1319,82 +1304,6 @@ class MarkdownEditor { requestAnimationFrame(() => { this._syncing = false; }); } - // ============ 语法高亮编辑区(v0.1.14) ============ - - _highlightEditor() { - if (!this.highlightLayer || !this.config.syntaxHighlight) return; - // rAF 节流,避免高频更新 - if (this._hlRaf) return; - this._hlRaf = requestAnimationFrame(() => { - this._hlRaf = null; - this._doHighlight(); - }); - } - - _doHighlight() { - if (!this.highlightLayer || this.highlightLayer.hidden || this._mode === 'preview') return; - const text = this._value || ''; - if (!text) { this.highlightLayer.innerHTML = ''; return; } - if (text.length > 50000) { this.highlightLayer.innerHTML = escapeHTML(text) + '\n'; return; } - - let html = escapeHTML(text); - this._positionHighlightLayer(); - - // 正则按优先级:先匹配更具体的模式,避免被泛模式吞掉 - // 1. 图片(先于链接) - html = html.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '$&'); - // 2. 链接 - html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$&'); - // 3. 行内代码(先于粗体/斜体,避免 `**` 被误匹配) - html = html.replace(/`([^`]+)`/g, '$&'); - // 4. 粗体 **text** / __text__ - html = html.replace(/(\*\*|__)(.+?)\1/g, '$&'); - // 5. 删除线 - html = html.replace(/~~(.+?)~~/g, '$&'); - // 6. 斜体 *text* / _text_(在粗体之后,避免 ** 被拆成两个斜体) - html = html.replace(/(?$&'); - html = html.replace(/(?$&'); - // 7. 标题(行级) - html = html.replace(/^(#{1,6})\s+(.+)$/gm, '$&'); - // 8. 列表标记 - html = html.replace(/^(\s*[-*+]|\d+\.)\s/gm, '$&'); - // 9. 引用 - html = html.replace(/^(>)\s?/gm, '$&'); - // 10. 水平线 - html = html.replace(/^([-*_]{3,})\s*$/gm, '$&'); - - this.highlightLayer.innerHTML = html + '\n'; - // 同步滚动 - if (this.textarea) this.highlightLayer.scrollTop = this.textarea.scrollTop; - } - - /** 切换语法高亮(v0.1.14) */ - toggleSyntaxHighlight() { - this.config.syntaxHighlight = !this.config.syntaxHighlight; - if (this.textarea) { - this.textarea.classList.toggle('me-textarea-highlight', this.config.syntaxHighlight); - } - if (this.highlightLayer) { - this.highlightLayer.hidden = !this.config.syntaxHighlight; - } - if (this.config.syntaxHighlight) { - this._positionHighlightLayer(); - this._doHighlight(); - } - return this; - } - - _positionHighlightLayer() { - if (!this.highlightLayer) return; - // 动态设置左边距:有行号时对齐行号宽度,无行号时从 0 开始 - if (this.gutter && this.config.lineNumbers && this.gutter.style.display !== 'none') { - const w = this.gutter.getBoundingClientRect().width; - this.highlightLayer.style.left = w + 'px'; - } else { - this.highlightLayer.style.left = '0'; - } - } - _updateWordCount() { if (!this.config.wordCount || !this.statusEl) return; const text = this._value || ''; @@ -1781,7 +1690,6 @@ class MarkdownEditor { if (this._renderRaf) cancelAnimationFrame(this._renderRaf); if (this._historyTimer) clearTimeout(this._historyTimer); if (this._outlineTimer) clearTimeout(this._outlineTimer); - if (this._hlRaf) cancelAnimationFrame(this._hlRaf); this._cleanups.forEach((fn) => { try { fn(); } catch (_) {} }); this._cleanups = []; diff --git a/src/styles.js b/src/styles.js index f7837ce..d6e1394 100644 --- a/src/styles.js +++ b/src/styles.js @@ -132,31 +132,6 @@ const generateCSS = () => { /* ============ 编辑区内层(v0.1.7) ============ */ .me-editor-inner { display: flex; height: 100%; overflow: hidden; position: relative; } - /* 语法高亮叠加层(v0.1.14) */ - .me-highlight-layer { - position: absolute; top: 0; right: 0; bottom: 0; - padding: 16px 18px; margin: 0; border: 0; outline: 0; overflow: hidden; - font-family: var(--md-mono); font-size: 13.5px; line-height: 1.7; - white-space: pre-wrap; word-wrap: break-word; - pointer-events: none; background: var(--md-textarea-bg); - color: var(--md-text); z-index: 0; - } - /* textarea 在高亮模式下透明背景,露出下方高亮层 */ - .me-textarea-highlight { - background: transparent !important; - } - /* 隐藏高亮层(语法高亮关闭时) */ - .me-highlight-layer[hidden] { display: none; } - .mh-heading { color: var(--md-accent); font-weight: 700; } - .mh-bold { color: var(--md-text); font-weight: 700; } - .mh-italic { font-style: italic; } - .mh-strike { color: var(--md-muted); text-decoration: line-through; } - .mh-code { background: var(--md-code-bg); border-radius: 3px; padding: 0 2px; } - .mh-link { color: var(--md-accent); text-decoration: underline; } - .mh-image { color: #8b5cf6; } - .mh-list { color: var(--md-accent); font-weight: 600; } - .mh-quote { color: var(--md-muted); } - .mh-hr { color: var(--md-muted); } .me-gutter { flex: 0 0 auto; min-width: 36px;