cooperation/markdown.js

105 lines
2.9 KiB
JavaScript
Raw Permalink Normal View History

2025-01-15 15:10:30 +08:00
import { Marked } from "marked"
2025-01-15 16:35:20 +08:00
import { cursors, Cursor } from "./cursor"
2025-01-15 15:10:30 +08:00
// 示例 Markdown 文本
const markdown = `
# 2333
- [ ] 1111
- [ ] 1111
- [ ] 1111
- [x] 2222
- [ ] 233323
- [ ] 233323
- [ ] 233323
这是一段测试文本
`
const marked = new Marked()
const tokens = marked.lexer(markdown)
// 创建 textarea 接受输入
const textarea = document.createElement("textarea")
Object.assign(textarea.style, {
position: "fixed",
bottom: "10px",
left: "10px",
width: "300px",
height: "100px",
zIndex: "1000",
placeholder: "在这里输入文本或使用方向键调整位置",
})
document.body.appendChild(textarea)
// 处理输入事件
textarea.oninput = () => {
2025-01-16 06:05:50 +08:00
cursors.forEach(cursor => cursor.oninput(textarea))
2025-01-15 15:10:30 +08:00
textarea.value = ""
}
// 处理方向键移动插入点
textarea.onkeydown = (event) => {
2025-01-16 06:05:50 +08:00
cursors.forEach(cursor => cursor.onkeydown({ key: event.key }))
2025-01-15 15:10:30 +08:00
}
// 渲染 Markdown 并监听点击事件
const element = document.createElement("div")
element.innerHTML = marked.parser(tokens)
document.body.appendChild(element)
// 点击事件:记录插入位置
element.onclick = (event) => {
if (event.target.tagName !== "LI") return
const { clientX: x, clientY: y } = event
// 查找点击的文本节点
const textNodes = Array.from(event.target.childNodes).filter(
(node) => node.nodeType === Node.TEXT_NODE
)
const targetNode = textNodes.find((node) => {
const range = document.createRange()
range.selectNodeContents(node)
const rect = range.getBoundingClientRect()
return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom
})
if (!targetNode) return
// 计算插入位置索引
const positions = [...targetNode.textContent].map((_, i) => {
const range = document.createRange()
range.setStart(targetNode, i)
range.setEnd(targetNode, i + 1)
return { index: i, rect: range.getBoundingClientRect() }
})
2025-01-15 19:26:44 +08:00
const closest = positions.reduce((closest, pos) => {
const dist = Math.abs(x - pos.rect.left)
return dist < closest.distance ? { ...pos, distance: dist } : closest
}, { index: -1, distance: Infinity })
2025-01-15 15:10:30 +08:00
const rect = closest.rect
const insertBefore = x < rect.left + rect.width / 2
const insertIndex = closest.index + (insertBefore ? 0 : 1)
// 设置光标的目标节点和插入位置
cursors.forEach(cursor => cursor.setTarget(targetNode, insertIndex))
2025-01-15 16:35:20 +08:00
// 如果是点击多个光标的情况,增加新光标
if (event.ctrlKey || !cursors.length) {
const newCursor = new Cursor(targetNode, insertIndex)
cursors.push(newCursor)
console.log("新增光标")
}
2025-01-15 15:10:30 +08:00
// 更新光标位置
2025-01-16 06:05:50 +08:00
cursors.forEach(cursor => cursor.updatePosition(cursor.getBoundingClientRect()))
2025-01-15 15:10:30 +08:00
// 聚焦输入框
textarea.value = ""
textarea.focus()
}