111

69 阅读1分钟
import { Extension } from '@tiptap/core'
import { Plugin, PluginKey } from 'prosemirror-state'

const mapDataItems = (data, fileMatchRegex) => {
  return Array.from(data)
    .map(item => (item.type.match(fileMatchRegex) ? item.getAsFile() : null))
    .filter(item => item !== null);
};

const mapTextItems = async (data) => {
  const fullSet = Array.from(data),
    plainText = fullSet.find(item => item.type === 'text/plain'),
    richText = fullSet.find(item => item.type === 'text/html');
  return new Promise(resolve => {
    (richText || plainText).getAsString(html => {
      const value = html.replace(/<img[^>]*>/g, '')
      resolve(value)
    })
  })
}

export default Extension.create({
  name: 'CustomPasteRules',

  addOptions: {
    fileMatchRegex: /^image/(gif|jpe?g|a?png|svg|webp|bmp)/i,
    disableImagePaste: false
  },

  addProseMirrorPlugins() {
    const options = this.options,
      renderer = this.options.render?.();

    return [
      new Plugin({
        key: new PluginKey('imagePasteHandler'),
        props: {
          handlePaste(_view, event) {
            if (options.disableImagePaste && renderer?.['onDisabledImagePaste']) {
              mapTextItems(event.clipboardData.items).then(value => {
                if (value) {
                  renderer['onDisabledImagePaste'](value)
                }
              })
              return true
            }

            if (!options.disableImagePaste && renderer?.['onImagePaste'] && event.clipboardData?.items?.length) {
              const files = mapDataItems(event.clipboardData.items, options.fileMatchRegex)
              if (files.length) {
                renderer['onImagePaste'](files)
                return true
              }
            }
            return false
          },

          handleDrop(_view, event) {
            if (!options.disableImagePaste && event.dataTransfer?.files?.length && renderer?.['onImageDrop']) {
              const files = mapDataItems(event.dataTransfer.items, options.fileMatchRegex)
              if (files.length) {
                renderer['onImageDrop'](files)
                return true
              }
            }
            return false
          }
        }
      })
    ]
  }
})