Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: 格式刷无法复制段落缩进等样式 #408

Open
AndroidYzk opened this issue Dec 4, 2024 · 5 comments
Open

Bug: 格式刷无法复制段落缩进等样式 #408

AndroidYzk opened this issue Dec 4, 2024 · 5 comments
Assignees
Labels
bug Something isn't working

Comments

@AndroidYzk
Copy link

问题描述

目前格式刷功能仅复制了文字样式,没有办法复制段落样式和缩进,然后我想自己扩展但一直实现不了功能

wangEditor 版本

wangEditor-next

是否查阅了文档 ?

(文档链接 https://cycleccc.github.io/docs/

最小成本的复现步骤

  • 步骤一 写三段文字
  • 步骤二 把第一段文字设置居中对齐格式并添加缩进 然后点击格式刷
  • 步骤三 选中另一段文字,此时只有字体样式之类的变化了,段落对齐以及缩进没变化
@wjw020206 wjw020206 self-assigned this Dec 5, 2024
@wjw020206
Copy link
Collaborator

好的,我抽时间看一下

@wjw020206 wjw020206 added the bug Something isn't working label Dec 5, 2024
@wjw020206 wjw020206 changed the title 格式刷问题 Bug: 格式刷无法复制段落缩进等样式 Dec 5, 2024
@AndroidYzk
Copy link
Author

好的,我抽时间看一下

好的谢谢,目前我自定义新按钮,似乎是可以实现功能的,但是我不知道怎么扩展原来的格式刷按钮

@AndroidYzk
Copy link
Author

但是我现在又遇到一个问题,就是我自定义新按钮实现了段落格式和缩进格式的复制,但是文本格式的复制却实现不了,不知道是不是哪里冲突了

@wjw020206
Copy link
Collaborator

但是我现在又遇到一个问题,就是我自定义新按钮实现了段落格式和缩进格式的复制,但是文本格式的复制却实现不了,不知道是不是哪里冲突了

方便发一下你的实现代码吗?我参考一下

@AndroidYzk
Copy link
Author

const customFormatPainterMenu = {
key: 'customFormatPainter', // 菜单标识,必须唯一
factory() {
return {
title: '增强格式刷',
tag: 'button',
iconSvg: <svg viewBox="0 0 1024 1024"><path d="M938.666667 85.333333a85.333333 85.333333 0 0 1 0 170.666667h-85.333334v170.666667a170.666667 170.666667 0 0 1-170.666666 170.666666h-85.333334v256h85.333334a85.333333 85.333333 0 0 1 85.333333 85.333334v85.333333H170.666667v-85.333333a85.333333 85.333333 0 0 1 85.333333-85.333334h85.333333V597.333333H256a170.666667 170.666667 0 0 1-170.666667-170.666666V256H85.333333a85.333333 85.333333 0 0 1 0-170.666667h853.333334z"></path></svg>,
copiedStyles: null,
getValue(editor) {
console.log('getValue被调用')
const selection = window.getSelection()
if (!selection.rangeCount) return false

    const range = selection.getRangeAt(0)
    const container = range.commonAncestorContainer

    let paragraphElement = container
    while (paragraphElement && !['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6'].includes(paragraphElement.nodeName)) {
      paragraphElement = paragraphElement.parentElement
    }
    const sourceHtml = paragraphElement.innerHTML

    const paragraphStyle = paragraphElement ? window.getComputedStyle(paragraphElement) : {}

    const getTextStyles = (element) => {
      const styles = []
      const walker = document.createTreeWalker(element, NodeFilter.SHOW_ELEMENT)
      let currentNode = walker.currentNode

      while (currentNode) {
        if (currentNode !== paragraphElement) {
          const computedStyle = window.getComputedStyle(currentNode)
          styles.push({
            tag: currentNode.tagName.toLowerCase(),
            style: {
              fontSize: computedStyle.fontSize,
              fontFamily: computedStyle.fontFamily,
              fontWeight: computedStyle.fontWeight,
              color: computedStyle.color,
              backgroundColor: computedStyle.backgroundColor,
            }
          })
        }
        currentNode = walker.nextNode()
      }
      return styles
    }

    return {
      paragraph: {
        textAlign: paragraphStyle.textAlign,
        textIndent: paragraphStyle.textIndent,
        lineHeight: paragraphStyle.lineHeight,
        marginLeft: paragraphStyle.marginLeft,
        marginRight: paragraphStyle.marginRight,
        paddingLeft: paragraphStyle.paddingLeft,
        paddingRight: paragraphStyle.paddingRight,
        backgroundColor: paragraphStyle.backgroundColor,
      },
      sourceHtml,
      textStyles: getTextStyles(paragraphElement)
    }
  },
  isActive(editor) {
    return this.copiedStyles !== null
  },
  isDisabled(editor) {
    const selection = window.getSelection()
    return !selection || !selection.rangeCount
  },
  exec(editor, value) {
    console.log('exec被调用')
    if (this.isDisabled(editor)) return
    if (!this.copiedStyles) {
      const selection = window.getSelection()
      const range = selection.getRangeAt(0)
      const container = range.commonAncestorContainer
      let paragraphElement = container
      while (paragraphElement && !['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6'].includes(paragraphElement.nodeName)) {
        paragraphElement = paragraphElement.parentElement
      }

      const allParagraphs = editor.getEditableContainer().getElementsByTagName('P')
      const sourceIndex = Array.from(allParagraphs).indexOf(paragraphElement)

      this.copiedStyles = {
        ...this.getValue(editor),
        sourceIndex
      }
      console.log('复制的样式:', this.copiedStyles)
      document.body.style.cursor = 'copy'
    } else {
      try {
        const selection = window.getSelection()
        if (selection.rangeCount) {
          const range = selection.getRangeAt(0)
          const container = range.commonAncestorContainer

          let paragraphElement = container
          while (paragraphElement && !['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6'].includes(paragraphElement.nodeName)) {
            paragraphElement = paragraphElement.parentElement
          }

          if (paragraphElement) {
            const allParagraphs = editor.getEditableContainer().getElementsByTagName('P')
            const targetIndex = Array.from(allParagraphs).indexOf(paragraphElement)

            if (targetIndex === this.copiedStyles.sourceIndex) {
              console.log('不能应用到源段落')
              return
            }

            const tempDiv = document.createElement('div')
            tempDiv.innerHTML = editor.getHtml()

            const targetParagraph = tempDiv.getElementsByTagName('P')[targetIndex]

            if (targetParagraph) {

              if (this.copiedStyles.paragraph) {
                const paragraphStyleStr = Object.entries(this.copiedStyles.paragraph)
                  .filter(([key, value]) => value && value !== 'initial' && value !== '0px')
                  .map(([key, value]) => {
                    if (key === 'textIndent') {
                      return `text-indent: 2em`
                    }
                    if (key === 'backgroundColor' && value === 'rgba(0, 0, 0, 0)') {
                      return ''
                    }
                    return `${key.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`)}: ${value}`
                  })
                  .filter(Boolean)
                  .join('; ')

                if (paragraphStyleStr) {
                  targetParagraph.setAttribute('style', paragraphStyleStr)
                }
              }

              if (this.copiedStyles.sourceHtml) {
                const sourceTemplate = document.createElement('div')
                sourceTemplate.innerHTML = this.copiedStyles.sourceHtml

                const targetText = targetParagraph.textContent

                const sourceSpan = sourceTemplate.querySelector('span')
                const sourceStrong = sourceTemplate.querySelector('strong')

                let newHtml = targetText

                if (sourceStrong) {
                  newHtml = `<strong>${newHtml}</strong>`
                }

                if (sourceSpan) {
                  const spanStyle = sourceSpan.getAttribute('style')
                  if (spanStyle) {
                    newHtml = `<span style="${spanStyle}">${newHtml}</span>`
                  }
                }

                targetParagraph.innerHTML = newHtml
              }
              editor.setHtml(tempDiv.innerHTML)

              setTimeout(() => {
                editor.updateView()
                editor.emit('change')
              }, 0)
            }
          }

          // 重置
          this.copiedStyles = null
          document.body.style.cursor = 'default'
        }
      } catch (error) {
        console.error('应用样式时出错:', error)
        this.copiedStyles = null
        document.body.style.cursor = 'default'
      }
    }
  }
}

}

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants