fix: 修复代码块语法高亮丢失 + 语言标签注入 + 安全性增强
- 新增 cdnjs.cloudflare.com CSP 白名单,允许加载 highlight.js - 消毒策略放行 span 元素,保留 highlight.js 高亮 class - 详情页和新帖子页引入 highlight.js 库和 GitHub 主题 - 代码块语言选择器默认 text,支持 prev/next 循环切换语言 - 代码块语言标签注入兼容 data-language 和 code class 双来源 - 修复 utils.js defer 导致 common.js 执行时 getCSRFToken 未定义
This commit is contained in:
@ -141,27 +141,34 @@ function setupToolbar() {
|
||||
// ---- 代码块语言选择器 ----
|
||||
const langSelect = document.getElementById('codeLangSelect')
|
||||
if (langSelect) {
|
||||
// 当光标在代码块内时显示语言选择器,移出时隐藏
|
||||
// 阻止 select 获取焦点导致编辑器失焦
|
||||
langSelect.addEventListener('mousedown', (e) => {
|
||||
e.preventDefault()
|
||||
// 手动切换选项
|
||||
const opts = langSelect.options
|
||||
let nextIdx = langSelect.selectedIndex + 1
|
||||
if (nextIdx >= opts.length) nextIdx = 0
|
||||
langSelect.selectedIndex = nextIdx
|
||||
const lang = opts[nextIdx].value
|
||||
// 在编辑器内更新代码块语言属性
|
||||
editor.chain().focus().updateAttributes('codeBlock', { language: lang === 'text' ? null : lang }).run()
|
||||
})
|
||||
|
||||
// 当光标在代码块内时显示语言选择器并同步当前语言,移出时隐藏
|
||||
editor.on('selectionUpdate', () => {
|
||||
if (editor.isActive('codeBlock')) {
|
||||
langSelect.style.display = ''
|
||||
const attrs = editor.getAttributes('codeBlock')
|
||||
langSelect.value = attrs.language || ''
|
||||
langSelect.value = attrs.language || 'text'
|
||||
} else {
|
||||
langSelect.style.display = 'none'
|
||||
}
|
||||
})
|
||||
|
||||
// 语言切换
|
||||
langSelect.addEventListener('change', () => {
|
||||
const lang = langSelect.value
|
||||
editor.chain().focus().updateAttributes('codeBlock', { language: lang || null }).run()
|
||||
editor.commands.focus()
|
||||
})
|
||||
}
|
||||
|
||||
// ---- 代码块语言标签注入 ----
|
||||
// 为每个 <pre> 注入语言标签 DOM 元素(因为 CSS ::before 在 overflow:auto 容器中不可靠)
|
||||
// Tiptap CodeBlockLowlight 在 pre 上输出 data-language 属性,同时 code 上有 language-xxx class
|
||||
function injectCodeLangLabels() {
|
||||
const editorEl = document.querySelector('#editor-container .tiptap')
|
||||
if (!editorEl) return
|
||||
@ -170,16 +177,22 @@ function setupToolbar() {
|
||||
const old = pre.querySelector('.code-lang-label')
|
||||
if (old) old.remove()
|
||||
|
||||
const lang = pre.getAttribute('data-language')
|
||||
if (lang) {
|
||||
const label = document.createElement('div')
|
||||
label.className = 'code-lang-label'
|
||||
label.textContent = lang
|
||||
pre.insertBefore(label, pre.firstChild)
|
||||
pre.style.paddingTop = '32px'
|
||||
} else {
|
||||
pre.style.paddingTop = ''
|
||||
// 从 pre 的 data-language 或 code 的 class 中获取语言
|
||||
let lang = pre.getAttribute('data-language')
|
||||
if (!lang) {
|
||||
const code = pre.querySelector('code')
|
||||
if (code) {
|
||||
const match = code.className.match(/language-(\w+)/)
|
||||
if (match) lang = match[1]
|
||||
}
|
||||
}
|
||||
lang = lang || 'text'
|
||||
|
||||
const label = document.createElement('div')
|
||||
label.className = 'code-lang-label'
|
||||
label.textContent = lang
|
||||
pre.insertBefore(label, pre.firstChild)
|
||||
pre.style.paddingTop = '32px'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user