<template>
  <div id="wangeditor">
    <div ref="editorElem" style="text-align:left"></div>
  </div>
</template>
<script>

  /**
   * @description 编辑器
   * 参考网站如下：
   * https://element.eleme.cn/#/zh-CN/component/installation
   * gxd-helper参考文档：https://www.npmjs.com/package/gxd-helper
   * wangeditor参考文档: //http://www.wangeditor.com/index.html
   * 七牛云参考文档 https://developer.qiniu.com/kodo/1272/form-upload
   *
   * @ntioce qiniu上传时：参数：qiniuCdnUrl，action必选  事件：onQiniuToken 必须实现
   * @ntioce aliyun上传时：参数：qiniuCdnUrl，action必选  事件：onAllParams,onSuccess 必须实现
   *
   * @property {String} action API上传地址 {必选}  备注：type=aliyun时 可以设置为aliyuan即可
   * @property {String} value 设置默认文本数据 {选填} 默认：''
   * @property {String} type 支持图片上传类型 {选填} 默认：'' 其值： all=>API服务上传  qiniu=>七牛云OSS上传  aliyun=> 阿里云OSS上传
   * @property {String} qiniuCdnUrl 七牛云静态资源方法地址 {type=qiniu时，必填}  默认：''
   * @property {Number} zIndex 样式层级关系  {选填}  默认：3000
   * @property {Number} height 编辑器默认高度 {选填}  默认：200
   * @property {String} fileName 上传文件参数名字 {选填}  默认：file
   * @property {String} size 上传文件图片大小 {选填}  默认：5 单位：M
   * @property {Array} uploadType 上传文件类型 {选填} 默认: ['jpg', 'jpeg', 'png', 'gif']
   *
   * @event {Function} onQiniuToken 获取七牛上传upload-token (resolve) (七牛云上传事件) 回调值：resolve(token)
   * @event {Function} onAllParams 获取本地API服务器上传参数 (resolve) (本地API上传事件) 回调值：resolve(params)
   * @event {Function} onSuccess 本地API服务器上传成功事件（response，resolve） (本地API上传事件) 返回值：resolve(url)
   * @event {Function} onOssParams  阿里云OSS服务器上传成功事件（file，resolve） (阿里云OSS服务器事件) 返回值：resolve(ossobject)
   *
   */

  import E from "wangeditor";
  import axios from 'axios';
  import {Loading} from 'element-ui';


  export default {
    name: "XdWangEditor",
    props:{
      value: String,

      type: {
        type:String,
        default: 'all',
      },

      size: {
        type: Number,
        default: 5
      },

      uploadType: {
        type: Array,
        default(){
          return ['jpg', 'jpeg', 'png', 'gif']
        }
      },

      qiniuCdnUrl: {
        type: String,
        default: '',
      },

      zIndex: {
        type: Number,
        default: 3000
      },

      height: {
        type: Number,
        default: 200
      },

      fileName: {
        type: String,
        default: 'file',
      },

      action: {
        type: String,
        required: false
      },
      isImageBase64:{
        type: Boolean,
        default: false
      },
    },
    data() {
      return {
        editor: null, //编辑器对象
        editorContent: '', //编辑器内容
        init: false, //初始化列表
        fid: 0,
        loading: null,
        isFirst: false
      };
    },

    watch: {
      value(val){
        if(!this.init) {
          this.editor.txt.html(val);
          this.init = true;
        }
      }
    },

    created(){
      if(this.type === 'qiniu') {
        if(this.qiniuCdnUrl === '' || this.action === '') {
          throw  new Error('请设置CDN访问地址和Action接口地址')
        }
      }
      else if(this.type === 'all') {
        if (this.action === '') {
          throw  new Error('请设置CDN访问地址和Action接口地址')
        }
      }
    },

    mounted() {
      this.$nextTick(()=>{
        this.editor = new E(this.$refs['editorElem']);
        // 编辑器的事件，每次改变会获取其html内容
        this.editor.config.onchange = (html) => {
          console.log('onchange', html);
          this.editorContent = html;
          this.$emit('input', html);
          this.$emit('change', html);
        };

        this.editor.config.onblur = (html) => {
          console.log('onblur', html);
          if(!this.isFirst) {
            this.isFirst = true;
            return;
          }
          this.editorContent = html;
          this.$emit('input', html);
          this.$emit('blur', html);
        };
        this.editor.config.focus = false;
        this.editor.config.zIndex = this.zIndex;
        this.editor.config.height = this.height;
        this.editor.config.menus = [
          'head',
          'bold',
          'fontSize',
          'fontName',
          'italic',
          'underline',
          'strikeThrough',
          'indent',
          'lineHeight',
          'foreColor',
          'backColor',
          'link',
          'list',
          'todo',
          'justify',
          'quote',
          'image',
          'table',
          'code',
          'splitLine',
          'undo',
          'redo',
        ];

        //====== custom uploadfile ====
        if (this.action) {
          this.editor.config.uploadImgMaxSize = this.size * 1024 * 1024;
          this.editor.config.uploadImgAccept = this.uploadType;
          this.editor.config.customUploadImg = (resultFiles, insertImgFn) => {
            //使用base64处理
            if(this.isImageBase64) {
              resultFiles.map(file=>{
                const reader = new FileReader();
                reader.readAsDataURL(file);
                reader.onload = function() {
                  insertImgFn(reader.result)
                };
              });
            }
            //上传到服务器
            else {
              //系统版本上传功能
              if(typeof this.handleGetParamsAndHeader === 'function') {
                resultFiles.map(file=>{
                  if (file.type.indexOf('image/') === 0) {
                    this.handleGetParamsAndHeader(file,({params})=>{
                      this.uploadFile(params , file,(res)=>{
                          let image = this.getImageFullPath(`/${params['key']}`);
                          if(image.indexOf('//') === 0) image = image.replace(/\/\//,'https://');
                        insertImgFn(image);
                        },(error)=>{

                        },(canceled)=>{

                        })
                    })
                  }
                })
                return;
              }
              if (this.type === 'qiniu') {
                this.loading = Loading.service({});
                this.qiniuAxios(resultFiles, insertImgFn)
              }
              else if(this.type === 'all'){
                this.allAxios(resultFiles, insertImgFn)
              }
              else if(this.type === 'aliyun') {
                this.aliyunAxios(resultFiles, insertImgFn)
              }
            }

          }


          // 配置粘贴文本的内容处理
          this.editor.config.pasteTextHandle = function (pasteStr) {
            // todo 对粘贴的文本进行处理，然后返回处理后的结果
            return pasteStr
          }
        }
        //====== custom uploadfile ====
        this.editor.create(); // 创建富文本实例

        //设置编辑器类容
        this.editor.txt.html(this.value);
      })
    },

    methods:{
      uploadFile(dataObj,file, success, error,canceled){
        let xhr = new XMLHttpRequest();

        //请求完成后执行的操作
        xhr.addEventListener("load", function(evt){
          success();
        }, false);

        //请求error
        xhr.addEventListener("error", error , false);

        //请求中断
        xhr.addEventListener("abort", canceled, false);


        //设置请求参数
        let fd = new FormData();
        fd.append("OSSAccessKeyId", dataObj.OSSAccessKeyId);
        fd.append("Signature", dataObj.signature);
        fd.append("callback", dataObj.callback);
        fd.append("expire", dataObj.expire);
        fd.append("key", dataObj.key);
        fd.append("name", file.name);
        fd.append("policy", dataObj.policy);
        fd.append("file", file);

        //发送请求
        xhr.open("POST", dataObj.action);

        //发送数据
        xhr.send(fd);


      },

      request(data, action = null){
        return axios({
          method: 'post',
          url: action || this.action,
          headers :{
            'Content-Type': 'multipart/form-data'
          },
          data
        })
      },

      aliyunAxios(files, insertImgFn){
        files.map(file=>{

          /**
           * @description res 阿里OSS使用PostObject直接上传
           * 参考：https://help.aliyun.com/document_detail/31988.htm?spm=a2c4g.11186623.0.0.26885d3fh1AjJF#reference-smp-nsw-wdb
           * @param res { Object } 阿里oss对象相关参数对象
           * @param res.OSSAccessKeyId {String} Bucket拥有者的AccessKey ID {必填}
           * @param res.action  {String} 图片上传OSS地址 {必填}
           * @param res.key {String} 上传Object的名称。如果名称包含路径 {必填}
           * @param res.cdnUrl  {String} 图片上传之后访问地址 {必填}
           * @param res.policy {String} Policy规定了请求表单域的合法性。不包含Policy表单域的请求被认为是匿名请求，并只能访问public-read-write的Bucket {必填}
           * @param res.signature  {String} 根据AccessKey Secret和Policy计算的签名信息，OSS验证该签名信息从而验证该Post请求的合法性 {必填}
           * @param res.expire {Date} 过期时间 {选填}
           * @param res.name {String} 文件名称 {选填}
           * @param res.success_action_status  {String} 未指定success_action_redirect表单域时，该表单域指定了上传成功后返回给客户端的状态码 {选填}
           */
          this.$emit('onOssParams', file, (res)=>{
            let formData = new FormData();
            Object.keys(res).map((key) => {
              formData.append(key, res[key]);
            });
            formData.append('file', file);
            this.request(formData, res.action)
              .then(ok=>{
                insertImgFn(res.cdnUrl)
              })
              .catch(res=>{

              })
          })
        })
      },

      /**
       * @description 七牛云上传逻辑
       * @param files
       * @param insertImgFn
       */
      qiniuAxios(files, insertImgFn){
        let len = files.length;
        let status = [];
        this.$emit('onQiniuToken', token=>{
          files.map((file)=>{
            let formData = new FormData();
            formData.append('key', `Xd${this.$xdHelper.randomChar(30)}`);
            formData.append('token', token);
            formData.append('file', file);
            this.request(formData)
              .then(res=>{
                insertImgFn(`${this.qiniuCdnUrl}/${res.data['key']}`);
                status.push(true);
                if(len === status.length) this.loading.close();
              })
              .catch()
          })
        })
      },

      /**
       * @description 本地API上传
       * @param files
       * @param insertImgFn
       */
      allAxios(files, insertImgFn){
        let len = files.length;
        let status = [];
        this.$emit('onAllParams', (params={}) => {
          files.map((file) => {
            let formData = new FormData();
            Object.keys(params).map((key) =>{
              formData.append(key, params[key]);
            });
            formData.append('file', file);
            this.request(formData)
              .then(res => {
                this.$emit('onSuccess', res, url=>{
                  insertImgFn(url);
                  status.push(true);
                  if (len === status.length) this.loading.close();
                })
              })
              .catch()
          })
        })
      }
    }
  }
</script>
<style scoped lang="scss">
  #wangeditor {
    box-shadow:0 0 5px rgba(0,0,0,0.1);

    & ::v-deep .w-e-text-container {
      min-height: 300px !important;
    }

    & ::v-deep .w-e-menu .w-e-panel-container .w-e-up-img-container .w-e-up-btn {
      font-size: 30px;
      margin: 20px;
    }
  }
</style>
