ignoreMutation (for node views) prevent update of child nodes

#1

For tiptap I use some Vue.js components as node views. To prevent a full re-render of a Vue component whenever an attribute of a node changes, I’ve set ignoreMutation to true. The update method was still called so I could update the Vue component manually.

For some reason this seams to be broken (I think since prosemirror-view 1.9). ProseMirror don’t recognize any changes made in child nodes (contentDOM) of node views with ignoreMutation set to true.

I hope this is a bug. Otherwise, I don’t know how to fix this on my side. :thinking:

#2

Could you be more specific on how you’re using the update method and ignoreMutation here? Specifically, what do you mean by ‘recognizing changes made in child nodes’?

#3

Of course! This is how I define node views (in a simplified way). This worked great until now.

class ComponentView {

  constructor() {
    // get the dom element
    this.dom = this.createDOM()

    // we can define a dom element inside of our vue component as contentDOM
    this.contentDOM = this.vm.$refs.content
  }

  createDOM() {
    // create vue instance
    const Component = Vue.extend(this.component)
    this.vm = new Component({
      propsData: {
        node: this.node,
        decorations: this.decorations,
        // pass a function to update node attrs to this vue component
        updateAttrs: attrs => this.updateAttrs(attrs),
      },
    }).$mount()
    return this.vm.$el
  }

  // whenever the node is updated, we will update our vue component props aswell
  update(node, decorations) {
    Object.entries({ node, decorations }).forEach(([key, value]) => {
      this.vm._props[key] = value
    })

    return true
  }

  updateAttrs(attrs) {
    const transaction = this.view.state.tr.setNodeMarkup(this.getPos(), null, {
      ...this.node.attrs,
      ...attrs,
    })
    this.view.dispatch(transaction)
  }

  // prevent a full re-render of the vue component on update
  // we'll handle prop updates in `update()`
  ignoreMutation() {
    return true
  }

  // disable (almost) all prosemirror event listener for node views
  stopEvent(event) {
    const isPaste = event.type === 'paste'
    const draggable = !!this.extension.schema.draggable

    if (draggable || isPaste) {
      return false
    }

    return true
  }

  destroy() {
    this.vm.$destroy()
  }

}

Whenever I have such a node view it may have children (set as contentDOM). This can be a simple paragraph (not a node view). Whenever I try to type in there, some weird things are happening and dispatchTransaction is never called:

May-10-2019%2022-26-06

#4

Firstly, an update method should always check whether the node it gets is of the proper type, and return false otherwise.

But that’s probably not related to the problem you describe. Your ignoreMutation method will always return true, so DOM mutations in the content will also be ignored. Have you tried checking if the mutation’s target is in the content, and returning true when it is?

#5

Thanks for that hint! That behavior definitely changed in the latest version of prosemirror-view. Even other tools like pubpub editor (react wrapper) doesn’t check anything within ignoreMutation.

But this seems to be working fine for me now:

ignoreMutation(mutation) {
  if (!this.contentDOM) {
    return true
  }
  return !this.contentDOM.contains(mutation.target)
}

Thanks!

#6

Nothing changed. The example you point at is a node view for a leaf node (no contentDOM), which doesn’t have this problem.