# How to async modify pasted stuff

**URL:** <https://discuss.prosemirror.net/t/how-to-async-modify-pasted-stuff/5379>\
**Category:** Uncategorized\
**Created:** [March 30, 2023, 1:00pm UTC](https://discuss.prosemirror.net/t/how-to-async-modify-pasted-stuff/5379 "2023-03-30T13:00:24Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![nulo](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/nulo/32/3213_2.png) [@nulo](https://discuss.prosemirror.net/u/nulo)\
**Post date:** [March 30, 2023, 1:00pm UTC](https://discuss.prosemirror.net/t/how-to-async-modify-pasted-stuff/5379/1 "2023-03-30T13:00:24Z")

</div>

I’m using ProseMirror to build an editor for [our CMS](https://sutty.coop.ar/en). When pasting multimedia, it should check whether it’s already hosted by the CMS, and if that’s not true, it should fetch the media and re-upload it to the CMS to keep it self-contained.

So far, I got this:

```typescript
// Sube los multimedia que no están todavía en ActiveStorage.
export const autoUploadPlugin = new Plugin({
  appendTransaction(_, __, newState) {
    let tr = newState.tr;

    let multimediaToCheck: { node: ProsemirrorNode; pos: number }[] = [];
    newState.doc.descendants((node, pos) => {
      if (node.type.name === "multimedia")
        multimediaToCheck.push({ node, pos });
    });

    for (const { node, pos } of multimediaToCheck) {
      if (!node.attrs.src.startsWith(activeStorageEndpoint)) {
        const point = insertPoint(
          newState.doc,
          pos,
          newState.schema.nodes.multimedia
        );
        const id = {};
        tr.setMeta(placeholderPlugin, { add: { id, pos: point } }).delete(
          pos,
          pos + 1
        );

        fetch(node.attrs.src)
          // TODO: handlear
          .then((res) => res.blob())
          .then(async (blob) => {
            const url = await uploadFile(blob);

            const placeholderPos = findPlaceholder(newState, id);
            // si se borró el placeholder, no subir imágen
            if (placeholderPos == null) return;

            const node = newState.schema.nodes.multimedia.createChecked({
              src: url,
              kind: mimeToKind(blob.type),
            });

            // ###### this clearly doesn't work because we don't have `view` here.
            view.dispatch(
              view.state.tr
                .replaceWith(placeholderPos, placeholderPos, node)
                .setMeta(placeholderPlugin, { remove: { id } })
            );
          })
          .catch((err) => console.error("No pude fetchear el src", err));
      }
    }

    return tr;
  },
});

```

Instead, I am considering handling this in a [`handlePaste`](https://prosemirror.net/docs/ref/#view.EditorProps.handlePaste). However, this won’t work when other methods (like dropping) are used. I think this might be fine though, but I’m not sure. Is there a way to do this with `appendTransaction` or something similar? Is using `handlePaste` reasonable?

---

<div class="post-metadata">

**Author:** ![marijn](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/marijn/32/15_2.png) [@marijn](https://discuss.prosemirror.net/u/marijn)\
**Post date:** [March 30, 2023, 2:49pm UTC](https://discuss.prosemirror.net/t/how-to-async-modify-pasted-stuff/5379/2 "2023-03-30T14:49:29Z")

</div>

There’s also `handleDrop`, and together with `handlePaste` that should cover the ways in which external content is inserted into the editor. `transformPasted` can be used to transform content read by both of these.

---

<div class="post-metadata">

**Author:** ![nulo](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/nulo/32/3213_2.png) [@nulo](https://discuss.prosemirror.net/u/nulo)\
**Post date:** [March 30, 2023, 6:17pm UTC](https://discuss.prosemirror.net/t/how-to-async-modify-pasted-stuff/5379/3 "2023-03-30T18:17:28Z")

</div>

I ended up using neither of those, because

- In `handlePaste` it’s unclear to me what I’m supposed to implement as it "overrides the behaviour of pasting`
- In `transformPasted` I don’t know the position of where it is being pasted to set the placeholder.

Instead, I implemented it using [`PluginSpec.view`](https://prosemirror.net/docs/ref/#state.PluginSpec.view) which seems to work great, is that ok?

---

<div class="post-metadata">

**Author:** ![nghihua](https://discuss.prosemirror.net/letter_avatar_proxy/v4/letter/n/71e660/32.png) [@nghihua](https://discuss.prosemirror.net/u/nghihua)\
**Post date:** [November 28, 2023, 10:21am UTC](https://discuss.prosemirror.net/t/how-to-async-modify-pasted-stuff/5379/4 "2023-11-28T10:21:55Z")

</div>

Hi there. I am implementing something similar myself. Could you share how you did it with PluginSpec.view? 😀 Thanks a ton!

---

<div class="post-metadata">

**Author:** ![nulo](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/nulo/32/3213_2.png) [@nulo](https://discuss.prosemirror.net/u/nulo)\
**Post date:** [November 28, 2023, 12:52pm UTC](https://discuss.prosemirror.net/t/how-to-async-modify-pasted-stuff/5379/5 "2023-11-28T12:52:08Z")

</div>

Check out the implementation: [src/uploads/auto-upload.ts · 38deef1faff294be691db294574b585fefe3481f · sutty / Editor · GitLab](https://0xacab.org/sutty/editor/-/blob/38deef1faff294be691db294574b585fefe3481f/src/uploads/auto-upload.ts)
