<template>
  <section class="AiEditor" :class="{invalid:valid&&!validateState}">
    <ck-editor v-if="sourceEditor" :editor="sourceEditor" v-model="content" :config="editorConfig" @ready="handleReady" @input="$emit('change',repairContent)"/>
  </section>
</template>

<script>
/**
 * 原组件ckeditor封装
 * 修改者:Kubbo
 */
import CKEditor from '@ckeditor/ckeditor5-vue2'
import {UploadAdapter} from "./models";

export default {
  name: "AiEditor",
  components: {ckEditor: CKEditor.component},
  inject: {
    elFormItem: {default: ""},
    elForm: {default: ''},
  },
  model: {
    prop: "value",
    event: "change"
  },
  props: {
    value: {type: String, required: true, default: ""},
    placeholder: {type: String, default: '请输入正文'},
    conf: Object,
    instance: {type: Function, required: true},
    valid: {type: Boolean, default: true},
    text: {default: ""},
    action: {default: "/admin/file/add"},
    params: {default: () => ({})},
    mode: {default: "default"}
  },
  data() {
    return {
      sourceEditor: null,
      editor: null,
      isPasteStyle: true,//粘贴是否携带格式
      content: ""
    }
  },
  computed: {
    validateState() {
      return ['', 'success'].includes(this.elFormItem?.validateState)
    },
    editorConfig() {
      return {
        mediaEmbed: {
          previewsInData: true
        },
        htmlSupport: {
          allow: [{name: /[\s\S]+/, styles: true, classes: true, attributes: true}]
        },
        ...this.conf
      }
    },
    repairContent: v => `<section class="ck-content">${v.content?.replace(/\s0w"/g, '"')?.replace(/srcset/g, 'src')}</section>`
  },
  watch: {
    content(v) {
      v && this.dispatch('ElFormItem', 'el.form.change', [v])
    }
  },
  methods: {
    handleReady(editor) {
      this.editor = editor
      const {instance, action, params} = this
      editor.plugins.get('FileRepository').createUploadAdapter = loader => new UploadAdapter(loader, instance, action, params)
    },
    /**
     * 表单验证
     * @param componentName
     * @param eventName
     * @param params
     */
    dispatch(componentName, eventName, params) {
      let parent = this.$parent || this.$root;
      let name = parent.$options.componentName;

      while (parent && (!name || name !== componentName)) {
        parent = parent.$parent;

        if (parent) {
          name = parent.$options.componentName;
        }
      }
      if (parent) {
        parent.$emit.apply(parent, [eventName].concat(params));
      }
    },
    initValue() {
      let unwatch = this.$watch('value', (v) => {
        const init = v.replace(/<section class="ck-content">(.*)<\/section>/, '$1')
        if (!!this.content) unwatch && unwatch()
        else if (!!init) {
          this.content = init
          unwatch && unwatch()
        }
      }, {immediate: true})
    },
    loadEditor(count = 0) {
      if (!!window?.ClassicEditor) {
        this.sourceEditor = ClassicEditor
        this.initValue()
      } else if (count < 10) {
        setTimeout(() => this.loadEditor(++count), 50)
      } else {
        console.error("无法加载编辑器资源,请联系管理员")
      }
    }
  },
  created() {
    this.$injectLib("https://cdn.cunwuyun.cn/ckeditor.js", () => {
      this.loadEditor()
    })
  }
}
</script>

<style lang="scss" scoped>
.AiEditor {
  ::v-deep.ck-content {
    min-height: 300px;
  }
}
</style>
