Hi,
I am trying to achieve something like the “Comments” plugin in the collaboration demo but with Marks instead.
So given a document -
{
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "abcd"
}
]
},
{
"type": "paragraph"
},
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "efg"
}
]
}
]
}
-
When I select the text from “cd” to “ef” and apply “Bold”, the text parts get the marks applied. If I write new content in middle (the empty paragraph) - How do I apply the bold mark to that as well automatically?
-
How do I achieve the same when a new line is inserted between 2 mark nodes?
Do I need to scan through the previous and next nodes to figure out what mark needs to be applied or is there a direct way to achieve this? Goal is to keep the mark continuous (Like in Google Docs, if you create a comment - You can edit that comment. add new lines etc and it keeps everything under the comment. You can move out of the comment when you click on the end)
Update - I created a very rough plugin to iterate and find the previous and next text nodes - Check their marks - Match the attributes of the marks - Extract the common marks and then ensureMarks
appendTransaction (tr, oldState, newState) {
let pos = newState.tr.selection.from - 1
// eslint-disable-next-line no-unused-vars
let previousNode = null
let nextNode = null
while (pos > 0) {
let prevNode = newState.tr.doc.nodeAt(pos)
if (prevNode) {
if (!prevNode.isText && prevNode.firstChild && prevNode.firstChild.isText) {
previousNode = prevNode.firstChild
break
} else if (prevNode.isText) {
previousNode = prevNode
break
}
}
pos = pos - 1
}
pos = newState.tr.selection.to + 1
// console.log(newState.tr.doc.nodeSize)
while (pos < newState.tr.doc.nodeSize - 2) {
let nextnode = newState.tr.doc.nodeAt(pos)
if (nextnode) {
if (!nextnode.isText && nextnode.firstChild && nextnode.firstChild.isText) {
nextNode = nextnode.firstChild
break
} else if (nextnode.isText) {
nextNode = nextnode
break
}
}
pos = pos + 1
}
if (!previousNode || !nextNode) {
return
}
let marks1 = previousNode.marks
let marks2 = nextNode.marks
let carryOnMarks = []
if (newState.schema.marks.highlight.isInSet(marks1) && newState.schema.marks.highlight.isInSet(marks2)) {
console.log('Same Mark Found in sibling nodes')
marks1.map(mark1 => {
if (mark1.attrs['highlight-id']) {
let idHighlight = mark1.attrs['highlight-id']
let flag = false
marks2.map(({ attrs }) => {
if (attrs['highlight-id']) {
if (idHighlight === attrs['highlight-id']) {
flag = true
}
return false
}
})
if (flag) {
carryOnMarks.push(mark1)
}
}
return false
})
return newState.tr.ensureMarks(carryOnMarks)
}
}
})
Not sure if this is really the way to go about it… It seems to be working but am not sure yet…
Well - That didn’t go down so well.
I ended up creating a plugin which -
- Finds all the inline nodes with the relevant mark with attr (id)
- Build a range for each specific mark
- Figure out if the range of the mark is broken (has inline nodes that don’t have the mark)
- Fix broken ranges using appendTransaction to dispatch addMark for each of the broken range
The use case was to get the comments done with marks to enable undo/redo and keep them part of the document with collaboration. I read whatever I could find on this quite actively discussed topic of “Comments with Marks” - Too early to say if it’s working properly or not - but any suggestions whether this would be a viable model or not would be awesome! (In case I missed something - still quite new to Prosemirror)
Thanks!