Good way to map slices or fragments

In my view I am intercepting transformPasted handler for some custom bahavior of image (and other media) nodes. What I need to do is walk the passed in Slice to the handler and map all image nodes (as well as other media nodes) with a couple of attributes altered.

What I really wished I could do was something like:

slice.map((node) => {
  if (node.type.name === "image") {
    return schema.nodes.image.create({ ...node.attrs, overrittenAttr, })
  }

  return node;
});

which would walk all the nodes and their descendant nodes in the slice apply the function and return a new slice.

I created my own map function:

function mapFragment(fragment: Fragment, fn: (node: Node) => Node): Fragment {
  let mapped = Fragment.empty;

  fragment.forEach((node) => {
    const content = mapFragment(node.content, fn);

    mapped = mapped.addToEnd(fn(node).copy(content));
  });

  return mapped;
}

This works for my purpose. However I wonder if there is a better way to do this using methods provided by ProseMirror.

Hi, I use the approach you describe for transformCopied handler. My use case is that I have open/collapse detail node implementation.

transformCopied: (slice, view) => {

    let newSlice = new Slice(Fragment.empty, slice.openStart, slice.openEnd);

    slice.content.forEach(node => {
        if (node.type.name === 'togglelist') {
            const toggleIcon = view.state.schema.nodes.toggleicon.createAndFill({ status: "show" });
            const newContent = Fragment.from(toggleIcon).append(node.content);
            node = node.copy(newContent);
        }

        // Append the node to the new slice, whether it's a toggleList or not
        newSlice = new Slice(newSlice.content.append(Fragment.from(node)), slice.openStart, slice.openEnd);
    });

    return newSlice;
},
1 Like