Issue details
My expectation: Any
slc = doc.slice(..)
tr.replace(.., slc)
will allways work, if the positions are the same for both commands.
Steps to reproduce
I extended the default schema by a 'tuple' - kind of a table of fixed size: just one row and two columns.
The first cell I call flow-normal and the second cell I call flow-reverse.
I added:
sym_tup_div: {
content: "p_sym_tup_flow_normal p_sym_tup_flow_reverse",
group: "block",
defining: true,
parseDOM: [{tag: "div.symmetry-tuple"}],
toDOM() { return ["div", {class: "symmetry-tuple"}, 0] }
},
span_sym_tup_flow_normal: {
content: "limited_inline*",
defining: true,
parseDOM: [{tag: "span.flow-normal",context: "sym_tup_div/"}],
toDOM() { return ["span", {class: "flow-normal"}, 0] }
},
span_sym_tup_flow_reverse: {
content: "limited_inline*",
defining: true,
parseDOM: [{tag: "span.flow-reverse",context: "sym_tup_div/"}],
toDOM() { return ["span", {class: "flow-reverse"}, 0] }
},
(I would have used a similar nested structure of the basic schema to show how to reproduce the bug, but I think there is no such.)
Then my intention was to have a transform, that when the cursor is inside the flow-normal (first cell) of the tuple, that transform takes the remaining part of the flow-normal and moves that to a new paragraph after. I can achieve that by replacing the whole tuple by one with the shortened flow-normal and a new paragraph after, but I wanted the positions involved in the replace to be as narrow as possible, because the content can also be very large.
So I started slicing the tuple inside the flow-normal resulting in a (2,0) open start/end slice - instead of a (0,0) one. When replacing by my modified (2,0) slice I encountered some trouble and I started debugging my code. Even after a while not finding what is wrong (My before and after tuple positions are correct.), I decided to simply replace by what I slice, without changing it - just for testing. And now I find that not working either.
My expectation to any slc = doc.slice(..) tr.replace(.., slc) was, that it will allways work, at any same positions.
What I do:
Transform.prototype.doMyThing = function() {
let doc = this.doc;
let selection = this.selection;
let tr = this;
const before = ..
const after = ..
const srcSlc = doc.slice(selection.to, after)
tr = tr.replace(selection.from, after, srcSlc)
return tr
}
In my case for testing I move the cursor inside the flow-normal span (not the very start nor the very end) and trigger the transform. So selection.from == selection.to.
It should actually happen nothing, because I replace what is there with what was there before.
srcSlc.toString()
<sym_tup_div(
p_sym_tup_flow_normal("neglegentur pro."),
p_sym_tup_flow_reverse("An alitr ansequat quaerendum nec."))
(2,0)
But I get:
TransformError: Invalid content for node sym_tup_div load.js line 68 > eval:274:19
TransformError http://../moduleserve/load.js line 68 > eval:274
step http://../moduleserve/load.js line 68 > eval:314
replace http://../moduleserve/load.js line 68 > eval:1160
doMyThing myModule.js:1951
..
ProseMirror version
prosemirror-transform 1.2.5
prosemirror-model 1.10.0
(just pulled every module anew and rebuilt)
Affected platforms
Firefox Browser 76.0.1 (64-Bit)
Google Chrome Version 81.0.4044.113 (Official Build) (64-Bit)
Screenshots / Screencast (Optional)
I've started digging a bit into the code where it happens, and I found in model/src/replace.js the close function, which I modified to see what it is exactly complaining about:
function close(node, content) {
if (!node.type.validContent(content)) {
console.log('invalid', node.toString(), content.toString())
throw new ReplaceError("Invalid content for node " + node.type.name)
}
return node.copy(content)
}
The output: invalid
node.toString():
sym_tup_div(
p_sym_tup_flow_normal("Arem apsum dolor sit amet, sea graeci timeam antiopam an, eius ludus ad mei, et case efficiantur neglegentur pro."),
p_sym_tup_flow_reverse("An alitr ansequat quaerendum nec.")
)
content.toString():
<
p_sym_tup_flow_normal("Arem apsum dolor sit amet, sea graeci timeam antiopam an, eius ludus ad mei, et case efficiantur neglegentur pro."),
p_sym_tup_flow_reverse,
p_sym_tup_flow_reverse("An alitr ansequat quaerendum nec.")
From the output of content it is clear to me the content won't fit into the node, because two times p_sym_tup_flow_reverse is not allowed in the schema.
But what is the reason for that empty flow-reverse? The slice is just replaced by itself. - Why can't it just fit where it has been?
On the other hand: If I slice before to after then the slice is:
srcSlc
<sym_tup_div(
p_sym_tup_flow_normal("Arem apsum dolor sit amet, sea graeci timeam antiopam an, eius ludus ad mei, et case efficiantur neglegentur pro."),
p_sym_tup_flow_reverse("An alitr ansequat quaerendum nec."))
(0,0)
and replacing works fine.
I also tried tr.replaceRange(..) instead, but it is the same.
So I finally thought: It is a bug in the framework.