How to prevent node deletion?


Hey, I am trying to lock title, subtitle and contents elements down so that they cannot be removed from the document. The structure of the document looks like this


So I tried to lock the elements like this:

class Title/Subtitle/Contents extends Textblock {
   get locked() { return true }


This way, if I selected text crossing from title to subtitle or from subtitle into contents and his backspace/delete, it would not merge the elements. Unfortunately, I could still delete the each of the three element itself by selecting it and then hitting backspace/delete.

So I changed it to this:

class Title/Subtitle/Contents extends Textblock {
   get locked() { return true }
   get selectable() { return false }


This worked in the sense that I could no longer select the elements, so there was no (easy) way to delete them. Unfortunately if I selected text all the way from title title node to the contents node, it will still delete the subtitle node (the middle node). Any suggestions? (Adding “locked” to the Doc node is something I already tried).


Should they be able edit the title and subtitle but not delete them? I did try something like

Title.register("command", {
   name: "deleteTitle",
   label: "don't touch",
   run: {
       let (from,to) = pm.selection
       return !Pos.samePath(from.path, to.path) || pm.doc.path(from.path).size == 0
  keys: ["Backspace(1)", "Mod-Backspace(1)"]

I ranked it 1 to catch the backspace first. It did inhibit deletion across nodes although an empty node could still be deleted even though it can be empty. Not sure about that.


@peteb: Yes, they should be able to edit the contents of all parts, but not be able to delete them. I think the locked attribute was supposed to solve that. It just seems that something is missing or that I’m not fully understanding how to use it. I moved it to the doc node now and removed it from those elements that need to contain more that just inline text, because otherwise I wasn’t able to change paragraph to headline to code, etc. . Still not quite working as I expected.


This is one of the use cases for locked nodes, which have not been implemented yet. Until they are, there isn’t really a good solution for this.


gotcha. Ok, will wait.


is there a solution for this already ? I am trying to find a way to make it impossible to delete a node using the keyboard (still want to be able to delete it by programmatically dispatching a transaction though).


I think filterTransaction would be the best way to do this.


Hi @marijn,

If I implement the deletion of the node via filterTransaction, what properties of the transaction/state parameters should let me know if the action is “deletion” of a node. I am inspecting the properties of the transaction object inside filterTransaction and so far the info I could use is .docChanged and if the steps array contains any ReplaceStep which affects the nodes that are supposed to be non-deletable. Am I on the right path?


You’ll want to look at each step, find the deleted regions in its step map (with forEach), and check the document before the step to see whether it contains the type of node you want to prevent deletion of in such a range.