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 = () => {
|
|
|
|
const inputText = textarea.value // 获取用户输入的文本
|
|
|
|
if (!inputText) return
|
|
|
|
|
|
|
|
cursors.forEach(cursor => {
|
|
|
|
if (!cursor.targetNode || cursor.insertIndex === null) return
|
|
|
|
|
|
|
|
// 更新文本节点内容
|
|
|
|
cursor.targetNode.textContent =
|
|
|
|
cursor.targetNode.textContent.slice(0, cursor.insertIndex) +
|
|
|
|
inputText +
|
|
|
|
cursor.targetNode.textContent.slice(cursor.insertIndex)
|
|
|
|
|
|
|
|
// 更新插入位置
|
|
|
|
cursor.insertIndex += inputText.length
|
|
|
|
})
|
|
|
|
|
|
|
|
// 清空输入框
|
|
|
|
textarea.value = ""
|
|
|
|
updateCursors()
|
|
|
|
}
|
|
|
|
|
|
|
|
// 处理方向键移动插入点
|
|
|
|
textarea.onkeydown = (event) => {
|
2025-01-15 16:35:20 +08:00
|
|
|
cursors.filter(cursor => cursor.targetNode && cursor.insertIndex !== null).forEach(cursor => {
|
|
|
|
cursor.move(event.key)
|
|
|
|
updateCursors()
|
2025-01-15 15:10:30 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// 更新所有光标的位置
|
|
|
|
const updateCursors = () => {
|
|
|
|
cursors.forEach(cursor => {
|
|
|
|
if (!cursor.targetNode || cursor.insertIndex === null) {
|
|
|
|
cursor.hide()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// 获取插入点位置
|
|
|
|
const rect = cursor.getBoundingClientRect()
|
|
|
|
|
|
|
|
// 更新光标位置
|
|
|
|
cursor.updatePosition(rect)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// 渲染 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() }
|
|
|
|
})
|
|
|
|
|
|
|
|
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 }
|
|
|
|
)
|
|
|
|
|
|
|
|
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
|
|
|
// 更新光标位置
|
|
|
|
updateCursors()
|
|
|
|
|
|
|
|
// 聚焦输入框
|
|
|
|
textarea.value = ""
|
|
|
|
textarea.focus()
|
|
|
|
}
|
|
|
|
|
|
|
|
// 按删除键移除光标
|
|
|
|
document.addEventListener('keydown', (event) => {
|
|
|
|
if (event.key === 'Delete' && cursors.length > 0) {
|
|
|
|
const cursorToRemove = cursors.pop() // 移除最后一个光标
|
|
|
|
cursorToRemove.remove() // 移除对应的光标元素
|
|
|
|
console.log("移除光标")
|
|
|
|
}
|
|
|
|
})
|