Skip to content

Instantly share code, notes, and snippets.

@marijnh
Last active December 23, 2023 08:08
Show Gist options
  • Save marijnh/cee01b30b1890a5947c0 to your computer and use it in GitHub Desktop.
Save marijnh/cee01b30b1890a5947c0 to your computer and use it in GitHub Desktop.
Word highlighting in ProseMirror
import {Pos} from "../src/model"
function rangeFromTransform(tr) {
let from, to
for (let i = 0; i < tr.steps.length; i++) {
let step = tr.steps[i], map = tr.maps[i]
let stepFrom = map.map(step.from || step.pos, -1).pos
let stepTo = map.map(step.to || step.pos, 1).pos
from = from ? map.map(from, -1).pos.min(stepFrom) : stepFrom
to = to ? map.map(to, 1).pos.max(stepTo) : stepTo
}
return {from, to}
}
function findOffset(marks, pos) {
// FIXME could use a binary search
for (let i = 0; i < marks.length; i++)
if (marks[i].from.cmp(pos) >= 0) return i
return marks.length
}
export function highlightWord(pm, word) {
let marks = []
function markTextblock(node, path, dest) {
node.forEach((child, start, end) => {
// FIXME doesn't detect the word when it spans a mark boundary
if (child.isText) for (let pos = child.text.indexOf(word); pos != -1; pos = child.text.indexOf(word, pos + word.length)) {
let from = new Pos(path.slice(), start + pos)
dest.push(pm.markRange(from, from.move(word.length), {className: "found"}))
}
})
}
pm.doc.nodesBetween(null, null, (node, path) => {
if (node.isTextblock) {
markTextblock(node, path, marks)
return false
}
})
pm.on("transform", tr => {
let {from, to} = rangeFromTransform(tr)
from = new Pos(from.path, 0); to = new Pos(to.path, tr.doc.path(to.path).size)
marks = marks.filter(m => m.from)
let start = findOffset(marks, from), end = findOffset(marks, to)
for (let i = start; i < end; i++) pm.removeRange(marks[i])
let newMarks = marks.slice(0, start)
pm.doc.nodesBetween(from, to, (node, path) => {
if (node.isTextblock) {
// FIXME clear old marks
markTextblock(node, path, newMarks)
return false
}
})
marks = newMarks.concat(marks.slice(end))
})
}
@kofifus
Copy link

kofifus commented Mar 13, 2017

very useful thx!
can this be updated to latest PM ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment