javascript - Tiptap-tillägg för bilder och redigerbara bildtexter


ange bildbeskrivning här

Jag vill implementera bild och redigerbar bildtext med tiptap-tillägg

https://discuss.prosemirror.net/t/figure-and-editable-caption/462
Det fanns ett mycket bra exempel med ProseMirror, men är det svårt att uppnå med tiptap?
Vänligen berätta vilken kod du bör skriva om möjligt.

Jag bifogar koden som jag skrev nedan.
Bilden och bildtexten har lagts till framgångsrikt, men bildtexten kan ännu inte redigeras.

// ./CustomImage.ts
// @ts-ignore
import { Node, Plugin } from 'tiptap'
// @ts-ignore
import { nodeInputRule } from 'tiptap-commands'

const IMAGE_INPUT_REGEX = /!\[(.+|:?)\]\((\S+)(?:(?:\s+)["'](\S+)["'])?\)/

export default class CustomImage extends Node {
  get name () {
    return 'customImage'
  }

  get schema () {
    return {
      attrs: {
        src: {
          default: null
        },
        alt: {
          default: null
        },
        title: {
          default: null
        },
        caption: {
          default: null
        }
      },
      group: 'block',
      selectable: false,
      draggable: true,
      parseDOM: [
        {
          tag: 'figure'
        },
        [
          {
            tag: 'img[src]',
            getAttrs: (dom: any) => ({
              src: dom.getAttribute('src'),
              title: dom.getAttribute('title'),
              alt: dom.getAttribute('alt')
            })
          },
          {
            tag: 'figcaption'
          }
        ]
      ],
      toDOM: (node: any) => [
        'figure',
        [
          'img',
          {
            src: node.attrs.src,
            title: node.attrs.title,
            alt: node.attrs.alt
          }
        ],
        [
          'figcaption',
          {
            contenteditable: 'true'
          },
          node.attrs.caption
        ]
      ]
    }
  }

  commands ({ type }: any) {
    return (attrs: any) => (state: any, dispatch: any) => {
      const { selection } = state
      const position = selection.$cursor ? selection.$cursor.pos : selection.$to.pos
      const node = type.create(attrs)
      const transaction = state.tr.insert(position, node)
      dispatch(transaction)
    }
  }

  inputRules ({ type }: any) {
    return [
      nodeInputRule(IMAGE_INPUT_REGEX, type, (match: any) => {
        const [, alt, src, title] = match
        return {
          src,
          alt,
          title
        }
      })
    ]
  }

  get plugins () {
    return [
      new Plugin({
        props: {
          handleDOMEvents: {
            drop (view: any, event: any) {
              const hasFiles = event.dataTransfer &&
              event.dataTransfer.files &&
              event.dataTransfer.files.length

              if (!hasFiles) {
                return
              }

              const images = Array
                .from(event.dataTransfer.files)
                .filter((file: any) => (/image/i).test(file.type))

              if (images.length === 0) {
                return
              }

              event.preventDefault()

              const { schema } = view.state
              const coordinates = view.posAtCoords({ left: event.clientX, top: event.clientY })

              images.forEach((image: any) => {
                const reader = new FileReader()

                reader.onload = (readerEvent: any) => {
                  const node = schema.nodes.image.create({
                    src: readerEvent.target.result
                  })
                  const transaction = view.state.tr.insert(coordinates.pos, node)
                  view.dispatch(transaction)
                }
                reader.readAsDataURL(image)
              })
            }
          }
        }
      })
    ]
  }
}

Svar #1

Du saknar ett "hål" i figurtexten för att göra det redigerbart. Se https://prosemirror.net/docs/ref/#model.NodeSpec.toDOM. Jag implementerade en av de lösningar som nämns i ProseMirror-tråden; dock kan markören fortfarande gå in och skriva text mellan bilden och figurtexten. Jag skulle rekommendera att använda det sista exemplet med 3 scheman istället.

  get schema() {
    return {
      content: "inline*",
      attrs: {src: {default: ""}, title: {default: ""}},
      group: 'block',
      draggable: true,
      isolating: true,
      parseDOM: [{
        tag: "figure",
        contentElement: "figcaption",
        getAttrs(dom) {
          let img = dom.querySelector("img")
          console.log(img, img.getAttribute('src'), img.getAttribute('alt'));
          return {src: img.getAttribute('src'), title: img.getAttribute('alt')}
        }
      }],
      toDOM: node => ["figure", ["img", node.attrs], ["figurecaption", 0]],
    }
  }