Repository: ueberdosis/tiptap
File: packages/core/src/commands/insertContentAt.ts (TypeScript)

Code before:

    let { from, to } = typeof position === 'number' ? { from: position, to: position } : { from: position.from, to: position.to }

    let isOnlyTextContent = true
    let isOnlyBlockContent = true
    const nodes = isFragment(content) ? content : [content]

    nodes.forEach(node => {
      // check if added node is valid
      node.check()

      isOnlyTextContent = isOnlyTextContent ? node.isText && node.marks.length === 0 : false

      isOnlyBlockContent = isOnlyBlockContent ? node.isBlock : false
    })

    // check if we can replace the wrapping node by
    // the newly inserted content
    // example:
    // replace an empty paragraph by an inserted image
    // instead of inserting the image below the paragraph
    if (from === to && isOnlyBlockContent) {
      const { parent } = tr.doc.resolve(from)
      const isEmptyTextBlock = parent.isTextblock && !parent.type.spec.code && !parent.childCount

      if (isEmptyTextBlock) {
        from -= 1
        to += 1
      }
    }

    let newContent

    // if there is only plain text we have to use `insertText`
    // because this will keep the current marks
    if (isOnlyTextContent) {
      // if value is string, we can use it directly
      // otherwise if it is an array, we have to join it
      if (Array.isArray(value)) {
        newContent = value.map(v => v.text || '').join('')
      } else if (typeof value === 'object' && !!value && !!value.text) {
        newContent = value.text
      } else {
        newContent = value as string
      }

      tr.insertText(newContent, from, to)
    } else {
      newContent = content

      tr.replaceWith(from, to, newContent)

Review comment (suggestion):
This was removed because `commands.clearContent` relies on `setContent` to be able to reset the document to the initial schema. This was early exiting and causing a no-op making `clearContent` not actually clear anything.

This is very old code that wasn't very well documented but after some testing, I'm confident in this not "leading to strange errors". `insertContentAt` is much more robust than when this was written.

I tested inserting empty content into a node and a block and it essentially resulted in a no-op.

Code after:
      parseOptions: {},
      updateSelection: true,
      applyInputRules: false,
      applyPasteRules: false,
      ...options,
    }

    let content: Fragment | ProseMirrorNode

    try {
      content = createNodeFromContent(value, editor.schema, {
        parseOptions: {
          preserveWhitespace: 'full',
          ...options.parseOptions,
        },
        errorOnInvalidContent: options.errorOnInvalidContent ?? editor.options.enableContentCheck,
      })
    } catch (e) {
      return false
    }

    let { from, to } = typeof position === 'number' ? { from: position, to: position } : { from: position.from, to: position.to }

    let isOnlyTextContent = true
    let isOnlyBlockContent = true
    const nodes = isFragment(content) ? content : [content]

    nodes.forEach(node => {
      // check if added node is valid
      node.check()

      isOnlyTextContent = isOnlyTextContent ? node.isText && node.marks.length === 0 : false

      isOnlyBlockContent = isOnlyBlockContent ? node.isBlock : false
    })

    // check if we can replace the wrapping node by
    // the newly inserted content
    // example:
    // replace an empty paragraph by an inserted image
    // instead of inserting the image below the paragraph
    if (from === to && isOnlyBlockContent) {
      const { parent } = tr.doc.resolve(from)
      const isEmptyTextBlock = parent.isTextblock && !parent.type.spec.code && !parent.childCount

      if (isEmptyTextBlock) {
        from -= 1
        to += 1
      }
    }