import Quill from 'quill'
import Delta from 'quill-delta'
import 'quill/dist/quill.snow.css'
import {
  walk,
  getTextFromHtml,
  isUndef,
  checkSmmFormatData,
  formatGetNodeGeneralization,
  nodeRichTextToTextWithWrap,
  getNodeRichTextStyles,
  htmlEscape,
  compareVersion
} from '../utils'
import { CONSTANTS, richTextSupportStyleList } from '../constants/constant'
import MindMapNode from '../core/render/node/MindMapNode'
import { Scope } from 'parchment'

let extended = false

// 扩展quill的字体列表
let fontFamilyList = [
  '宋体, SimSun, Songti SC',
  '微软雅黑, Microsoft YaHei',
  '楷体, 楷体_GB2312, SimKai, STKaiti',
  '黑体, SimHei, Heiti SC',
  '隶书, SimLi',
  'andale mono',
  'arial, helvetica, sans-serif',
  'arial black, avant garde',
  'comic sans ms',
  'impact, chicago',
  'times new roman',
  'sans-serif',
  'serif'
]

// 扩展quill的字号列表
let fontSizeList = new Array(100).fill(0).map((_, index) => {
  return index + 'px'
})

// 富文本编辑插件
class RichText {
  constructor({ mindMap, pluginOpt }) {
    this.mindMap = mindMap
    this.pluginOpt = pluginOpt
    this.textEditNode = null
    this.showTextEdit = false
    this.quill = null
    this.range = null
    this.lastRange = null
    this.pasteUseRange = null
    this.node = null
    this.isInserting = false
    this.styleEl = null
    this.cacheEditingText = ''
    this.isCompositing = false
    this.textNodePaddingX = 6
    this.textNodePaddingY = 4
    this.initOpt()
    this.extendQuill()
    this.appendCss()
    this.bindEvent()

    this.handleDataToRichTextOnInit()
  }

  // 绑定事件
  bindEvent() {
    this.onCompositionStart = this.onCompositionStart.bind(this)
    this.onCompositionUpdate = this.onCompositionUpdate.bind(this)
    this.onCompositionEnd = this.onCompositionEnd.bind(this)
    this.handleSetData = this.handleSetData.bind(this)
    window.addEventListener('compositionstart', this.onCompositionStart)
    window.addEventListener('compositionupdate', this.onCompositionUpdate)
    window.addEventListener('compositionend', this.onCompositionEnd)
    this.mindMap.on('before_update_data', this.handleSetData)
    this.mindMap.on('before_set_data', this.handleSetData)
  }

  // 解绑事件
  unbindEvent() {
    window.removeEventListener('compositionstart', this.onCompositionStart)
    window.removeEventListener('compositionupdate', this.onCompositionUpdate)
    window.removeEventListener('compositionend', this.onCompositionEnd)
    this.mindMap.off('before_update_data', this.handleSetData)
    this.mindMap.off('before_set_data', this.handleSetData)
  }

  // 插入样式
  appendCss() {
    this.mindMap.appendCss(
      'richText',
      `
      .smm-richtext-node-wrap {
        word-break: break-all;
        user-select: none;
      }
      `
    )
    let cssText = `
      .${CONSTANTS.EDIT_NODE_CLASS.RICH_TEXT_EDIT_WRAP} {
        overflow: hidden;
        padding: 0;
        height: auto;
        line-height: 1.2;
        -webkit-user-select: text;
      }
      
      .ql-container {
        height: auto;
        font-size: inherit;
      }

      .ql-container.ql-snow {
        border: none;
      }
    `
    this.styleEl = document.createElement('style')
    this.styleEl.type = 'text/css'
    this.styleEl.innerHTML = cssText
    document.head.appendChild(this.styleEl)
  }

  // 处理选项参数
  initOpt() {
    if (
      this.pluginOpt.fontFamilyList &&
      Array.isArray(this.pluginOpt.fontFamilyList)
    ) {
      fontFamilyList = this.pluginOpt.fontFamilyList
    }
    if (
      this.pluginOpt.fontSizeList &&
      Array.isArray(this.pluginOpt.fontSizeList)
    ) {
      fontSizeList = this.pluginOpt.fontSizeList
    }
  }

  // 扩展quill编辑器
  extendQuill() {
    if (extended) {
      return
    }
    extended = true

    this.extendFont([])

    // 扩展quill的字号列表
    const SizeAttributor = Quill.import('attributors/class/size')
    SizeAttributor.whitelist = fontSizeList
    Quill.register(SizeAttributor, true)

    const SizeStyle = Quill.import('attributors/style/size')
    SizeStyle.whitelist = fontSizeList
    Quill.register(SizeStyle, true)
  }

  // 扩展字体列表
  extendFont(list = [], cover = false) {
    fontFamilyList = cover ? [...list] : [...fontFamilyList, ...list]

    // 扩展quill的字体列表
    const FontAttributor = Quill.import('attributors/class/font')
    FontAttributor.whitelist = fontFamilyList
    Quill.register(FontAttributor, true)

    const FontStyle = Quill.import('attributors/style/font')
    FontStyle.whitelist = fontFamilyList
    Quill.register(FontStyle, true)
  }

  // 显示文本编辑控件
  showEditText({ node, rect, isInserting, isFromKeyDown, isFromScale }) {
    if (this.showTextEdit) {
      return
    }
    let {
      customInnerElsAppendTo,
      nodeTextEditZIndex,
      textAutoWrapWidth,
      selectTextOnEnterEditText,
      transformRichTextOnEnterEdit,
      openRealtimeRenderOnNodeTextEdit,
      autoEmptyTextWhenKeydownEnterEdit
    } = this.mindMap.opt
    textAutoWrapWidth = node.hasCustomWidth()
      ? node.customTextWidth
      : textAutoWrapWidth
    this.node = node
    this.isInserting = isInserting
    if (!rect) rect = node._textData.node.node.getBoundingClientRect()
    if (!isFromScale) {
      this.mindMap.emit('before_show_text_edit')
    }
    this.mindMap.renderer.textEdit.registerTmpShortcut()
    // 原始宽高
    let g = node._textData.node
    let originWidth = g.attr('data-width')
    let originHeight = g.attr('data-height')
    // 缩放值
    const scaleX = Math.ceil(rect.width) / originWidth
    const scaleY = Math.ceil(rect.height) / originHeight
    // 内边距
    let paddingX = this.textNodePaddingX
    let paddingY = this.textNodePaddingY
    if (!this.textEditNode) {
      this.textEditNode = document.createElement('div')
      this.textEditNode.classList.add('smm-richtext-node-edit-wrap')
      this.textEditNode.style.cssText = `
        position:fixed;
        box-sizing: border-box;
        ${
          openRealtimeRenderOnNodeTextEdit
            ? ''
            : 'box-shadow: 0 0 20px rgba(0,0,0,.5);'
        }
        outline: none;
        word-break: break-all;
        padding: ${paddingY}px ${paddingX}px;
        line-height: 1.2;
      `
      this.textEditNode.addEventListener('click', e => {
        e.stopPropagation()
      })
      this.textEditNode.addEventListener('mousedown', e => {
        e.stopPropagation()
      })
      this.textEditNode.addEventListener('keydown', e => {
        if (this.mindMap.renderer.textEdit.checkIsAutoEnterTextEditKey(e)) {
          e.stopPropagation()
        }
      })
      const targetNode = customInnerElsAppendTo || document.body
      targetNode.appendChild(this.textEditNode)
    }
    this.addNodeTextStyleToTextEditNode(node)
    this.textEditNode.style.marginLeft = `-${paddingX * scaleX}px`
    this.textEditNode.style.marginTop = `-${paddingY * scaleY}px`
    this.textEditNode.style.zIndex = nodeTextEditZIndex
    if (!openRealtimeRenderOnNodeTextEdit) {
      this.textEditNode.style.background =
        this.mindMap.renderer.textEdit.getBackground(node)
    }
    this.textEditNode.style.minWidth = originWidth + paddingX * 2 + 'px'
    this.textEditNode.style.minHeight = originHeight + 'px'
    this.textEditNode.style.left = rect.left + 'px'
    this.textEditNode.style.top = rect.top + 'px'
    this.textEditNode.style.display = 'block'
    this.textEditNode.style.maxWidth = textAutoWrapWidth + paddingX * 2 + 'px'
    this.textEditNode.style.transform = `scale(${scaleX}, ${scaleY})`
    this.textEditNode.style.transformOrigin = 'left top'
    // 节点文本内容
    let nodeText = node.getData('text')
    if (typeof transformRichTextOnEnterEdit === 'function') {
      nodeText = transformRichTextOnEnterEdit(nodeText)
    }
    // 是否是空文本
    const isEmptyText = isUndef(nodeText)
    // 是否是非空的非富文本
    const noneEmptyNoneRichText = !node.getData('richText') && !isEmptyText
    if (isFromKeyDown && autoEmptyTextWhenKeydownEnterEdit) {
      this.textEditNode.innerHTML = ''
    } else if (noneEmptyNoneRichText) {
      // 还不是富文本
      let text = String(nodeText).split(/\n/gim).join('<br>')
      let html = `<p>${text}</p>`
      this.textEditNode.innerHTML = this.cacheEditingText || html
    } else {
      // 已经是富文本
      this.textEditNode.innerHTML = this.cacheEditingText || nodeText
    }
    this.initQuillEditor()
    this.setQuillContainerMinHeight(originHeight)
    this.showTextEdit = true
    // 如果是刚创建的节点，那么默认全选，否则普通激活不全选，除非selectTextOnEnterEditText配置为true
    // 在selectTextOnEnterEditText时，如果是在keydown事件进入的节点编辑，也不需要全选
    this.focus(
      isInserting || (selectTextOnEnterEditText && !isFromKeyDown) ? 0 : null
    )
    this.cacheEditingText = ''
  }

  // 当openRealtimeRenderOnNodeTextEdit配置更新后需要更新编辑框样式
  onOpenRealtimeRenderOnNodeTextEditConfigUpdate(
    openRealtimeRenderOnNodeTextEdit
  ) {
    if (!this.textEditNode) return
    this.textEditNode.style.background = openRealtimeRenderOnNodeTextEdit
      ? 'transparent'
      : this.node
      ? this.mindMap.renderer.textEdit.getBackground(this.node)
      : ''
    this.textEditNode.style.boxShadow = openRealtimeRenderOnNodeTextEdit
      ? 'none'
      : '0 0 20px rgba(0,0,0,.5)'
  }

  // 将指定节点的文本样式添加到编辑框元素上
  addNodeTextStyleToTextEditNode(node) {
    const style = getNodeRichTextStyles(node)
    Object.keys(style).forEach(prop => {
      this.textEditNode.style[prop] = style[prop]
    })
  }

  // 设置quill编辑器容器的最小高度
  setQuillContainerMinHeight(minHeight) {
    document.querySelector(
      '.' + CONSTANTS.EDIT_NODE_CLASS.RICH_TEXT_EDIT_WRAP
    ).style.minHeight = minHeight + 'px'
  }

  // 更新文本编辑框的大小和位置
  updateTextEditNode() {
    if (!this.node) return
    const g = this.node._textData.node
    const rect = g.node.getBoundingClientRect()
    const originWidth = g.attr('data-width')
    const originHeight = g.attr('data-height')
    this.textEditNode.style.minWidth =
      originWidth + this.textNodePaddingX * 2 + 'px'
    this.textEditNode.style.minHeight = originHeight + 'px'
    this.textEditNode.style.left = rect.left + 'px'
    this.textEditNode.style.top = rect.top + 'px'
    this.setQuillContainerMinHeight(originHeight)
  }

  // 删除文本编辑框元素
  removeTextEditEl() {
    if (!this.textEditNode) return
    const targetNode = this.mindMap.opt.customInnerElsAppendTo || document.body
    targetNode.removeChild(this.textEditNode)
  }

  // 获取当前正在编辑的内容
  getEditText() {
    // https://github.com/slab/quill/issues/4509
    return this.quill.container.firstChild.innerHTML.replaceAll(/  +/g, match =>
      '&nbsp;'.repeat(match.length)
    )
    // 去除ql-cursor节点
    // https://github.com/wanglin2/mind-map/commit/138cc4b3e824671143f0bf70e5c46796f48520d0
    // https://github.com/wanglin2/mind-map/commit/0760500cebe8ec4e8ad84ab63f877b8b2a193aa1
    // html = removeHtmlNodeByClass(html, '.ql-cursor')
    // 去除最后的空行
    // return html.replace(/<p><br><\/p>$/, '')
  }

  // 隐藏文本编辑控件，即完成编辑
  hideEditText(nodes) {
    if (!this.showTextEdit) {
      return
    }
    const { beforeHideRichTextEdit } = this.mindMap.opt
    if (typeof beforeHideRichTextEdit === 'function') {
      beforeHideRichTextEdit(this)
    }
    const html = this.getEditText()
    const list = nodes && nodes.length > 0 ? nodes : [this.node]
    const node = this.node
    this.textEditNode.style.display = 'none'
    this.showTextEdit = false
    this.mindMap.emit('rich_text_selection_change', false)
    this.node = null
    this.isInserting = false
    list.forEach(node => {
      this.mindMap.execCommand('SET_NODE_TEXT', node, html, true)
      // if (node.isGeneralization) {
      // 概要节点
      // node.generalizationBelongNode.updateGeneralization()
      // }
      this.mindMap.render()
    })
    this.mindMap.emit('hide_text_edit', this.textEditNode, list, node)
  }

  // 初始化Quill富文本编辑器
  initQuillEditor() {
    this.quill = new Quill(this.textEditNode, {
      modules: {
        toolbar: false,
        keyboard: {
          bindings: {
            enter: {
              key: 'Enter',
              handler: function () {
                // 覆盖默认的回车键，禁止换行
              }
            },
            shiftEnter: {
              key: 'Enter',
              shiftKey: true,
              handler: function (range, context) {
                // 覆盖默认的换行，默认情况下新行的样式会丢失
                const lineFormats = Object.keys(context.format).reduce(
                  (formats, format) => {
                    if (
                      this.quill.scroll.query(format, Scope.BLOCK) &&
                      !Array.isArray(context.format[format])
                    ) {
                      formats[format] = context.format[format]
                    }
                    return formats
                  },
                  {}
                )
                const delta = new Delta()
                  .retain(range.index)
                  .delete(range.length)
                  .insert('\n', lineFormats)
                this.quill.updateContents(delta, Quill.sources.USER)
                this.quill.setSelection(range.index + 1, Quill.sources.SILENT)
                this.quill.focus()
                Object.keys(context.format).forEach(name => {
                  if (lineFormats[name] != null) return
                  if (Array.isArray(context.format[name])) return
                  if (name === 'code' || name === 'link') return
                  this.quill.format(
                    name,
                    context.format[name],
                    Quill.sources.USER
                  )
                })
              }
            },
            tab: {
              key: 9,
              handler: function () {
                // 覆盖默认的tab键
              }
            }
          }
        }
      },
      formats: [
        'bold',
        'italic',
        'underline',
        'strike',
        'color',
        'background',
        'font',
        'size',
        'formula'
      ], // 明确指定允许的格式，不包含有序列表，无序列表等
      theme: 'snow'
    })
    // 拦截复制事件，即Ctrl + c，去除多余的空行
    this.quill.root.addEventListener('copy', event => {
      event.preventDefault()
      const sel = window.getSelection()
      const originStr = sel.toString()
      try {
        const range = sel.getRangeAt(0)
        const div = document.createElement('div')
        div.appendChild(range.cloneContents())
        const text = nodeRichTextToTextWithWrap(div.innerHTML)
        event.clipboardData.setData('text/plain', text)
      } catch (e) {
        event.clipboardData.setData('text/plain', originStr)
      }
    })
    this.quill.on('selection-change', range => {
      // 刚创建的节点全选不需要显示操作条
      if (this.isInserting) return
      this.lastRange = this.range
      this.range = null
      if (range) {
        this.pasteUseRange = range
        let bounds = this.quill.getBounds(range.index, range.length)
        let rect = this.textEditNode.getBoundingClientRect()
        let rectInfo = {
          left: bounds.left + rect.left,
          top: bounds.top + rect.top,
          right: bounds.right + rect.left,
          bottom: bounds.bottom + rect.top,
          width: bounds.width
        }
        let formatInfo = this.quill.getFormat(range.index, range.length)
        let hasRange = false
        if (range.length == 0) {
          hasRange = false
        } else {
          this.range = range
          hasRange = true
        }
        this.mindMap.emit(
          'rich_text_selection_change',
          hasRange,
          rectInfo,
          formatInfo
        )
      } else {
        this.mindMap.emit('rich_text_selection_change', false, null, null)
      }
    })
    this.quill.on('text-change', () => {
      this.mindMap.emit('node_text_edit_change', {
        node: this.node,
        text: this.getEditText(),
        richText: true
      })
    })
    // 拦截粘贴，只允许粘贴纯文本
    // this.quill.clipboard.addMatcher(Node.TEXT_NODE, node => {
    //   let style = this.getPasteTextStyle()
    //   return new Delta().insert(this.formatPasteText(node.data), style)
    // })
    // 剪贴板里只要存在文本就会走这里，所以当剪贴板里是纯文本，或文本+图片都可以监听到和拦截，但是只有纯图片时不会走这里，所以无法拦截
    this.quill.clipboard.addMatcher(Node.ELEMENT_NODE, (node, delta) => {
      let ops = []
      let style = this.getPasteTextStyle()
      delta.ops.forEach(op => {
        // 过滤出文本内容，过滤掉换行
        if (op.insert && typeof op.insert === 'string') {
          ops.push({
            attributes: { ...style },
            insert: this.formatPasteText(op.insert)
          })
        }
      })
      delta.ops = ops
      return delta
    })
    // 拦截图片的粘贴，当剪贴板里是纯图片，或文本+图片都可以拦截到，但是带来的问题是文本+图片时里面的文本也无法粘贴
    this.quill.root.addEventListener(
      'paste',
      e => {
        if (
          e.clipboardData &&
          e.clipboardData.files &&
          e.clipboardData.files.length
        ) {
          e.preventDefault()
        }
      },
      true
    )
  }

  // 获取粘贴的文本的样式
  getPasteTextStyle() {
    // 粘贴的数据使用当前光标位置处的文本样式
    if (this.pasteUseRange) {
      return this.quill.getFormat(
        this.pasteUseRange.index,
        this.pasteUseRange.length
      )
    }
    return {}
  }

  // 处理粘贴的文本内容
  formatPasteText(text) {
    const { isSmm, data } = checkSmmFormatData(text)
    if (isSmm && data[0] && data[0].data) {
      // 只取第一个节点的纯文本
      return getTextFromHtml(data[0].data.text)
    } else {
      return text
    }
  }

  // 正则输入中文
  onCompositionStart() {
    if (!this.showTextEdit) {
      return
    }
    this.isCompositing = true
  }

  // 中文输入中
  onCompositionUpdate() {
    if (!this.showTextEdit || !this.node) return
    this.mindMap.emit('node_text_edit_change', {
      node: this.node,
      text: this.getEditText(),
      richText: true
    })
  }

  // 中文输入结束
  onCompositionEnd() {
    if (!this.showTextEdit) {
      return
    }
    this.isCompositing = false
  }

  // 选中全部
  selectAll() {
    this.quill.setSelection(0, this.quill.getLength())
  }

  // 聚焦
  focus(start) {
    const len = this.quill.getLength()
    this.quill.setSelection(typeof start === 'number' ? start : len, len)
  }

  // 格式化当前选中的文本
  formatText(config = {}, clear = false) {
    if (!this.range && !this.lastRange) return
    const rangeLost = !this.range
    const range = rangeLost ? this.lastRange : this.range
    clear
      ? this.quill.removeFormat(range.index, range.length)
      : this.quill.formatText(range.index, range.length, config)
    if (rangeLost) {
      this.quill.setSelection(this.lastRange.index, this.lastRange.length)
    }
  }

  // 清除当前选中文本的样式
  removeFormat() {
    this.formatText({}, true)
  }

  // 格式化指定范围的文本
  formatRangeText(range, config = {}) {
    if (!range) return
    this.quill.formatText(range.index, range.length, config)
  }

  // 格式化所有文本
  formatAllText(config = {}) {
    this.quill.formatText(0, this.quill.getLength(), config)
  }

  // 将普通节点样式对象转换成富文本样式对象
  normalStyleToRichTextStyle(style) {
    const config = {}
    Object.keys(style).forEach(prop => {
      const value = style[prop]
      switch (prop) {
        case 'fontFamily':
          config.font = value
          break
        case 'fontSize':
          config.size = value + 'px'
          break
        case 'fontWeight':
          config.bold = value === 'bold'
          break
        case 'fontStyle':
          config.italic = value === 'italic'
          break
        case 'textDecoration':
          config.underline = value === 'underline'
          config.strike = value === 'line-through'
          break
        case 'color':
          config.color = value
          break
        default:
          break
      }
    })
    return config
  }

  // 将富文本样式对象转换成普通节点样式对象
  richTextStyleToNormalStyle(config) {
    const data = {}
    Object.keys(config).forEach(prop => {
      const value = config[prop]
      switch (prop) {
        case 'font':
          data.fontFamily = value
          break
        case 'size':
          data.fontSize = parseFloat(value)
          break
        case 'bold':
          data.fontWeight = value ? 'bold' : 'normal'
          break
        case 'italic':
          data.fontStyle = value ? 'italic' : 'normal'
          break
        case 'underline':
          data.textDecoration = value ? 'underline' : 'none'
          break
        case 'strike':
          data.textDecoration = value ? 'line-through' : 'none'
          break
        case 'color':
          data.color = value
          break
        default:
          break
      }
    })
    return data
  }

  // 判断一个对象是否包含了富文本支持的样式字段
  isHasRichTextStyle(obj) {
    const keys = Object.keys(obj)
    for (let i = 0; i < keys.length; i++) {
      const key = keys[i]
      if (richTextSupportStyleList.includes(key)) {
        return true
      }
    }
    return false
  }

  // 检查指定节点是否存在自定义的富文本样式
  checkNodeHasCustomRichTextStyle(node) {
    const nodeData = node instanceof MindMapNode ? node.getData() : node
    for (let i = 0; i < richTextSupportStyleList.length; i++) {
      if (nodeData[richTextSupportStyleList[i]] !== undefined) {
        return true
      }
    }
    return false
  }

  // 转换数据后的渲染操作
  afterHandleData() {
    // 清空历史数据，并且触发数据变化
    this.mindMap.command.clearHistory()
    this.mindMap.command.addHistory()
    this.mindMap.render()
  }

  // 插件实例化时处理思维导图数据，转换为富文本数据
  handleDataToRichTextOnInit() {
    // 处理数据，转成富文本格式
    if (this.mindMap.renderer.renderTree) {
      // 如果已经存在渲染树了，那么直接更新渲染树，并且触发重新渲染
      this.handleSetData(this.mindMap.renderer.renderTree)
      this.afterHandleData()
    } else if (this.mindMap.opt.data) {
      this.handleSetData(this.mindMap.opt.data)
    }
  }

  // 将所有节点转换成非富文本节点
  transformAllNodesToNormalNode() {
    const renderTree = this.mindMap.renderer.renderTree
    if (!renderTree) return
    walk(
      renderTree,
      null,
      node => {
        if (node.data.richText) {
          node.data.richText = false
          node.data.text = getTextFromHtml(node.data.text)
        }
        // 概要
        if (node.data) {
          const generalizationList = formatGetNodeGeneralization(node.data)
          generalizationList.forEach(item => {
            item.richText = false
            item.text = getTextFromHtml(item.text)
          })
        }
      },
      null,
      true,
      0,
      0
    )
    this.afterHandleData()
  }

  handleDataToRichText(data) {
    const oldIsRichText = data.richText
    data.richText = true
    data.resetRichText = true
    // 如果原本就是富文本，那么不能转换
    if (!oldIsRichText) {
      data.text = htmlEscape(data.text)
    }
  }

  // 处理导入数据
  handleSetData(data) {
    // 短期处理，为了兼容老数据，长期会去除
    const isOldRichTextVersion =
      !data.smmVersion || compareVersion(data.smmVersion, '0.13.0') === '<'
    const walk = root => {
      if (root.data && (!root.data.richText || isOldRichTextVersion)) {
        this.handleDataToRichText(root.data)
      }
      // 概要
      if (root.data) {
        const generalizationList = formatGetNodeGeneralization(root.data)
        generalizationList.forEach(item => {
          if (!item.richText || isOldRichTextVersion) {
            this.handleDataToRichText(item)
          }
        })
      }
      if (root.children && root.children.length > 0) {
        Array.from(root.children).forEach(item => {
          walk(item)
        })
      }
    }
    walk(data)
    return data
  }

  // 插件被移除前做的事情
  beforePluginRemove() {
    this.transformAllNodesToNormalNode()
    document.head.removeChild(this.styleEl)
    this.unbindEvent()
    this.mindMap.removeAppendCss('richText')
  }

  // 插件被卸载前做的事情
  beforePluginDestroy() {
    document.head.removeChild(this.styleEl)
    this.unbindEvent()
  }
}

RichText.instanceName = 'richText'

export default RichText
