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()
|
|
|
|
}
|
|
|
|
|