-
-
Notifications
You must be signed in to change notification settings - Fork 362
Description
I'm trying to implement image placeholders for uploading images using node decorations. After lots of debugging, however, it seems like this line from the documentation:
decorations = decorations.map(tr.mapping, tr.doc)
has some issues, as decorations.find().length
is 2 before it and 0 afterwards. This is rather odd as I expect widget decorations to never be deleted (they are not deleted even when doing Ctrl + A
→ Backspace
). However when inserting an image programatically, they are deleted.
As a reproduction, I took dumps of all of the involved variables:
Variable dumps
decorations = {
"children": [
0,
11,
{
"children": [],
"local": [
{
"from": 9,
"to": 9,
"type": {
"side": 0,
"spec": "...",
"toDOM": "..."
}
},
{
"from": 9,
"to": 9,
"type": {
"side": 0,
"spec": "...",
"toDOM": "..."
}
}
]
}
],
"local": []
}
doc = {
"type": "doc",
"content": [
{
"type": "paragraph",
"attrs": {},
"content": [
{
"type": "text",
"text": "Imagesss:"
}
]
},
{
"type": "image",
"attrs": { ... }
}
]
}
mapping = {
"maps": [
{
"ranges": [10, 1, 2],
"inverted": false
}
],
"from": 0,
"to": 1
}
tr.steps = [
{
"stepType": "replace",
"from": 10,
"to": 11,
"slice": {
"content": [
{
"type": "paragraph",
"attrs": {
"textAlign": "left"
}
},
{
"type": "image",
"attrs": { ... }
}
],
"openStart": 1
}
}
]
This is the code that adds the image:
const pos = (ImageKey.getState(state) as DecorationSet).find(undefined, undefined, (spec) => spec.id === id)[0]?.from
if (pos != null) tr.insert(pos, state.schema.nodeFromJSON({ type: "image", attrs } satisfies JSONContent))
And the code that adds the decoration (inside the apply()
function of the plugin state):
if (action.type === "create") {
const placeholder = document.createElement("div")
return decorations.add(tr.doc, [
Decoration.widget(action.pos, placeholder, {
id: action.id,
component: new ImagePlaceholder({ target: placeholder, props: { filename: action.filename } }),
}),
])
}
Am I doing something wrong? I tried debugging the map function of DecorationSet with no luck, code too complex for me :(
Workaround
If anyone else has the same issue, this is the workaround I'm using right now instead of decorations = decorations.map(...)
:
const newDecorations = decorations.map(tr.mapping, tr.doc)
if (newDecorations.find().length === decorations.find().length) {
decorations = newDecorations
}