【问题标题】:Tiptap extension for images and editable captions图像和可编辑标题的 Tiptap 扩展
【发布时间】:2019-11-25 00:56:39
【问题描述】:

enter image description here

我想用tiptap扩展实现图像和可编辑标题

https://discuss.prosemirror.net/t/figure-and-editable-caption/462
ProseMirror有一个很好的例子,但是用tiptap很难实现吗?
如果可能的话,请告诉我你应该写什么代码。

我附上我在下面写的代码。
图片和标题已成功添加,但标题无法编辑。

// ./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)
              })
            }
          }
        }
      })
    ]
  }
}

【问题讨论】:

  • 你能用故障或其他编辑器制作一个最低限度的工作示例吗?
  • 这方面有什么进展吗?
  • @kyw 见下文。
  • kyw, Sentient 抱歉回复晚了!如果你能帮助我,我很高兴。

标签: javascript typescript vue.js prose-mirror


【解决方案1】:

您在图形标题中缺少一个“洞”以使其可编辑。见https://prosemirror.net/docs/ref/#model.NodeSpec.toDOM。我实现了提到的 ProseMirror 线程中提到的解决方案之一;但是,光标仍然可以在 image 和 figurecaption 之间输入文本。我建议改用最后一个示例和 3 个模式。

  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]],
    }
  }

【讨论】:

  • 抱歉回复晚了!这个例子与我想做的非常接近。非常感谢你!现在标题中没有值,但是你知道如何将预先指定的值放在这里吗?我想继续编辑。我在上述问题的顶部添加了一个简单的演示 GIF 动画作为链接。
  • @Mmz 预先指定的值是什么意思?你想把 figcaption 中的文字初始化成什么东西吗?
  • 由于每个图像的标题值都预先存储在数据库中,我想将该值设置为每个图像的初始标题值。每个图像的初始标题值是一个字符串,我在粘贴在问题顶部的 GIF 动画中正确输入为“captioncaption11111”。这作为每个图像的初始标题存储在数据库中。这个描述是否告诉你我想做什么?
  • 是的。我认为上面的模式已经做到了。您只需将文档保存为 html 或 json,并使用从 html 或 json 方法加载的 prosemiror 即可。
  • 如果您没有初始文档,那么您可以 1. 将其转换为 prosemiror 可以使用的 html 或 json 格式 2. 创建一个将图形节点初始化到文档中的方法,从这里使用 NodeType create 方法:prosemirror.net/docs/ref/#model.NodeType。看看它如何将 attrs 和 content 作为参数。在上面的示例中,您将 (src, title) 作为 attrs 和 (caption) 作为内容传递。
猜你喜欢
  • 1970-01-01
  • 2016-12-26
  • 1970-01-01
  • 2020-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-09
相关资源
最近更新 更多