OverviewFilesCommitsIssuesDocsReleasesPeers

keet-deobfuscated / @holepunchto / keet-editor / src / extensions / file-uploader.js

101 lines · javascript ref:
import { Node as e } from "@tiptap/core"
import { Plugin as t } from "prosemirror-state"
import { NODE_TYPE as r, NODE_ATTR as n } from "../constants.js"
import { asyncCommand as s } from "./helpers/async-command.js"
const o = (e, t, n) => {
    if (n) {
      if (e.isVideoFile(t)) return r.FILE_VIDEO
      if (e.isImageFile(t)) return r.FILE_IMAGE
    }
    return r.FILE_ANY
  },
  i = async (e, t, s) => {
    try {
      const { state: i, dispatch: a } = e,
        { schema: c, doc: d } = i,
        { fileModule: p, onUpload: l, onUploadError: m } = s,
        f = new Map()
      for (const s of t) {
        const t = window.crypto.randomUUID(),
          o = c.nodes[r.FILE_LOADER].create({ [n.ID]: t })
        ;(a(e.state.tr.insert(d.content.size, o)), f.set(s, t))
      }
      for (let s = t.length - 1; s >= 0; s--) {
        const i = t[s],
          d = await l(i, m)
        if (!d) continue
        const { id: u, file: h } = d
        ;(e.state.doc.descendants((t, s) => {
          if (t.type.name === r.FILE_LOADER && t.attrs[n.ID] === f.get(i)) {
            const { url: r, type: i, name: d, dimensions: l, previews: m } = h,
              f = o(p, h.type, m),
              E = c.nodes[f].create({
                [n.ID]: u,
                src: r,
                type: i,
                name: d,
                alt: d,
                title: d,
                dimensions: l,
                preview: m,
              })
            a(e.state.tr.replaceWith(s, s + t.nodeSize, E))
          }
        }),
          e.focus())
      }
    } catch (e) {
      s.onUploadError?.(e)
    }
  }
export const FileUploader = e.create({
  name: r.FILE_UPLOADER,
  addCommands() {
    const { options: e } = this
    return {
      upload:
        (t) =>
        ({ can: r, chain: n, commands: o, dispatch: a, editor: c, state: d, tr: p, view: l }) => {
          s(() => i(l, t, e))
        },
    }
  },
  addProseMirrorPlugins() {
    const { options: e } = this
    return [
      new t({
        view(t) {
          const r = (r) => {
            if (e?.isFileSharingDisabled?.()) return
            if (e.dropPreventClassNames?.some((e) => r.target.matches(e) || r.target.closest(e)))
              return
            const n = [],
              { items: s } = r.dataTransfer || { items: [] }
            for (let e = 0; e < s.length; e++) {
              const t = s[e]
              t.webkitGetAsEntry()?.isFile && n.push(t.getAsFile())
            }
            if (0 === n.length) return !1
            ;(r.preventDefault(), i(t, n, e))
          }
          return (
            document.addEventListener("drop", r),
            {
              destroy() {
                document.removeEventListener("drop", r)
              },
            }
          )
        },
        props: {
          handlePaste(t, r) {
            const n = [...(r.clipboardData?.files || [])]
            if (!n || 0 === n.length) return !1
            ;(r.preventDefault(), i(t, n, e))
          },
        },
      }),
    ]
  },
})