<template>
  <div :class="{fullscreen:fullscreen}" class="tinymce-container" :style="{width:containerWidth}">
    <textarea :id="tinymceId" class="tinymce-textarea"></textarea>
    <div class="editor-custom-btn-container" v-if="imageConfig !== null">
      <el-button
        type="primary"
        size="small"
        icon="el-icon-upload"
        @click.stop="dialogVisible = true"
      >上传图片</el-button>
      <el-dialog
        v-if="dialogVisible"
        class="tinymce-container-dialog"
        custom-class="tinymce-container-dialog"
        :visible.sync="dialogVisible"
        width="800px"
        title="上传图片"
        modal-append-to-body
        append-to-body
      >
        <div class="tinymce-container-dialog-body">
          <xd-upload
            style-type="list"
            v-model="imagesList"
            :key="uploadKey"
            :action="imageConfig['action']"
            :qiniu-cdn="imageConfig['qiniuCdn']"
            :size="imageConfig['size']"
            :type="imageConfig['type']"
            :upload-type="imageConfig['uploadType']"
            :sort="imageConfig['sort']"
            :tips="imageConfig['tipsformet']"
            :maxlen="imageConfig['maxlen']"
            :is-material="false"
            :showtype="true"
            :radius="5"
            @success="handleSuccess"
            @onApiSuccessUrl="handleApiSuccessUrl"
            @onGetParamsAndHeader="handleGetParamsAndHeader"
          >
          </xd-upload>
        </div>
        <div class="tinymce-container-dialog-btn">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="handleSubmit">确认</el-button>
        </div>
      </el-dialog>
    </div>
  </div>
</template>

<script>

  /**
   * @description 富文本插件（兼容h5端显示）
   * 依赖于 element-ui
   * 参考网站如下：
   * https://element.eleme.cn/#/zh-CN/component
   * 文档：https://panjiachen.github.io/vue-element-admin-site/feature/component/rich-editor.html#tinymce
   *
   * @property {String} value 富文本默认值 （选填） 默认：空
   * @property {String} id 富文本插件ID （选填） 默认：vue-tinymce-new Date()
   * @property {String} lang 语言 （选填） 默认：zh 目前支持(en,cn,tw)
   * @property {Array} toolbar 工具栏  默认：[], 使用系统默认工具栏
   * @property {Number} height 编辑器高度 （选填） 默认：360 单位：px
   * @property {Number} width 编辑器宽度 （选填） 默认：auto 单位：px
   * @property {imageConfig} 上传文件配置   默认：null 不启用图片上传功能
   *
   * @event {Function} success 成功获得图片对象
   * @event {Function} handleGetParamsAndHeader 当上传开上传图片之前设置请求参数（params和header）
   * @event {Function} onApiSuccessUrl 当使用本地上传图片成功获得后台响应对象时刻，并在success事件之前执行
   *
   */


  import plugins from './XdTinymce/plugins'
  import toolbar from './XdTinymce/toolbar'
  import load from './XdTinymce/dynamicLoadScript'
  import XdUpload from "@/components/XdUpload";

  // why use this cdn, detail see https://github.com/PanJiaChen/tinymce-all-in-one
  //https://www.tiny.cloud/docs-4x/plugins/tinymcespellchecker/#events
  const tinymceCDN = 'https://image.jufubao.cn/tinymce/tinymce.min.js?version=v1.0.1';
  import emitter from 'element-ui/src/mixins/emitter';


  export default {
    name: 'XdTinymce',
    mixins: [emitter],
    components: {
      XdUpload
    },
    props: {
      disabled:{
        type: Boolean,
        default: false
      },
      id: {
        type: String,
        default: function () {
          return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
        }
      },
      lang: {
        type: String,
        default: 'zh',
      },
      value: {
        type: String,
        default: ''
      },
      toolbar: {
        type: Array,
        required: false,
        default() {
          return []
        }
      },
      menubar: {
        type: String,
        default: 'file edit insert view format table'
      },
      height: {
        type: [Number, String],
        required: false,
        default: 360
      },
      width: {
        type: [Number, String],
        required: false,
        default: 'auto'
      },

      //上传图片地址配置
      imageConfig: {
        type:Object|null,
        default: null, //null 不启用上传图片功能
        // default(){
        //   return {
        //     sort: true,
        //     maxlen: 100,
        //     action: 'https://up-z1.qiniup.com',
        //     qiniuCdn: 'http://static.e56buy.com',
        //     size: 5,
        //     tipsformet: '上传文件格式：@imageType@，不超过@size@MB.',
        //     uploadType: 'qiniu', //aliyun , qiniu
        //     type: ['jpg', 'png', 'jpeg']
        //   };
        // }
      }
    },
    data() {
      return {
        hasChange: false,
        hasInit: false,
        tinymceId: this.id,
        fullscreen: false,
        languageTypeList: {
          'en': 'en',
          'zh': 'zh_CN',
          'tw': 'zh_TW',
        },

        dialogVisible: false, //是否关闭弹层
        imagesList: {}, //上传图片地址对象
        isFirst: false,
        uploadKey:'uploadKey'
      }
    },
    computed: {
      containerWidth() {
        const width = this.width
        if (/^[\d]+(\.[\d]+)?$/.test(width)) { // matches `100`, `'100'`
          return `${width}px`
        }
        return width
      }
    },
    watch: {
      value(val) {
        if (!this.hasChange && this.hasInit) {
          this.$nextTick(() =>
            window['tinymce'].get(this.tinymceId).setContent(val || ''))
        }
      }
    },
    mounted() {
      this.init()
    },
    activated() {
      if (window['tinymce']) {
        this.initTinymce()
      }
    },
    deactivated() {
      this.destroyTinymce()
    },
    destroyed() {
      this.destroyTinymce()
    },
    methods: {
      /**
       * @description 加载编辑器库文件
       */
      init() {
        load(tinymceCDN, (err) => {
          if (err) {
            this.$message.error(err.message)
            return
          }
          this.initTinymce()
        })
      },

      /**
       * @description 初始化编辑
       */
      initTinymce() {
        const _this = this
        window['tinymce'].init({
          readonly: this.disabled,
          selector: `#${this.tinymceId}`,
          language: this.languageTypeList[this.lang],
          height: this.height,
          body_class: 'panel-body ',
          object_resizing: false,
          toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
          fontsize_formats: "12px 14px 16px 18px 20px 24px 26px 30px 32px 34px 36px 40px 60px",
          menubar: this.menubar,
          plugins: plugins,
          end_container_on_empty_block: true,
          //已设置获取OSS上传参数使用远程上传，否则：使用base64
          paste_data_images: !(typeof _this.handleGetParamsAndHeader  === "function"),
          powerpaste_word_import: 'clean',
          code_dialog_height: 450,
          code_dialog_width: 1000,
          advlist_bullet_styles: 'square',
          advlist_number_styles: 'default',
          imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
          default_link_target: '_blank',
          link_title: false,
          statusbar: false,
          nonbreaking_force_tab: true, // inserting nonbreaking space &nbsp; need Nonbreaking Space Plugin
          init_instance_callback: editor => {
            if (_this.value) {
              editor.setContent(_this.value)
            }
            _this.hasInit = true;
            editor.on('Input Change NodeChange KeyUp', (value) => {
              this.hasChange = true;
              console.log(value.type);
              if(value.type === 'nodechange') {
                if(this.isFirst > 1) {
                  _this.change(editor);
                  _this.update(editor);
                }
                this.isFirst ++ ;
              }

              if(value.type === 'change' || value.type === 'keyup') {
                _this.change(editor);
                _this.update(editor);
              }
            });
          },
          setup(editor) {
            editor.on('init', function () {
              //editor.execCommand("fontName", false, "Arial");
              //editor.target.editorCommands.execCommand("fontName", false, "Arial");
              // editor['getDoc']().body.style.fontSize = '14px';
              //editor['getDoc']().body.style.fontFamily = 'Arial';
              //editor.execCommand("fontSize", false, "12px");
            });

            //粘贴图片文件事件
            editor.on('paste', function(e) {
              let notImage = [];
              let content = e['clipboardContent'] || e['clipboardData'];
              if (content.items && content.items.length > 0) {
                let len =  content.items.length;
                for (let i = 0; i < len; i++) {
                  let item = content.items[i];
                  if(item['kind'] === 'file') {
                    if(typeof item.getAsFile === 'function') {
                      let blob = item.getAsFile(); // 获取粘贴的图片文件
                      if (item.type.indexOf('image/') === 0) {
                        _this.handleGetParamsAndHeader(blob,(ossObj)=>{
                          _this.uploadFile(ossObj.params , blob,(res)=>{
                            let image = _this.getImageFullPath(`/${ossObj.params['key']}`);
                            if(image.indexOf('//') === 0) image = image.replace(/\/\//,'https://');
                            window['tinymce']
                              .get(_this.tinymceId)['insertContent'](`<img style="max-width:100%" class="tinymce-image jfb-tinymce-image" src="${image}">`)
                          },(error)=>{
                          },(canceled)=>{
                          })
                        })
                      }
                      else {
                        notImage.push(blob.name);
                      }
                    }
                  }
                }
              }
              if(notImage.length > 0) {
                _this.$message({
                  message: `当前复制的【${notImage.join('】【')}】不是图片文件`,
                  type: 'warning'
                })
              }
            });

            editor.on('FullscreenStateChanged', (e) => {
              _this.fullscreen = e.state
            })
          },
          convert_urls: false

        })
      },

      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);


      },

      /**
       * @description 销毁插件
       */
      destroyTinymce() {
        const handle = ()=>{
          if (window['tinymce'] && typeof window['tinymce'].get === 'function') {
            const tinymce = window['tinymce'].get(this.tinymceId);
            if (this.fullscreen) {
              tinymce.execCommand('mceFullScreen')
            }
            if (tinymce) {
              tinymce.destroy()
            }
          }
          else{
           setTimeout(()=>{
             handle();
           }, 100)
          }
        };
        handle();
      },

      /**
       * @description 设置富文本编辑内容
       * @param value
       */
      setContent(value) {
        window['tinymce'].get(this.tinymceId).setContent(value)
      },

      /**
       * @description 获取富文本编辑内容
       */
      getContent() {
        window['tinymce'].get(this.tinymceId).getContent()
      },


      /**
       * @description 插入图片地址
       */
      handleSubmit(){
        if(!this.imagesList.length){
          this.$message.error('请选择图片')
          return
        }
        this.imagesList.forEach(v => window['tinymce'].get(this.tinymceId)['insertContent'](`<img style="max-width:100%" class="tinymce-image" src="${v.path || v.url }" >`));
        this.uploadKey = Date.now()
        this.imagesList = {}
        this.dialogVisible = false;
      },


      /**上传图片配置**************************/
      /**
       * @description 上传成功
       */
      handleSuccess(res) {
        this.$emit('success', res)
      },

      /**
       * @description 上传到本地服务器成功返回值时刻触发，设置url字段
       * @param result
       * @param resolve
       */
      handleApiSuccessUrl(result, resolve) {
        this.$emit('onApiSuccessUrl', result, (url) => {
          resolve(url);
        })
      },

      /**
       * @description 单文件上传参数设置
       * @param file
       * @param resolve
       */
      handleGetParamsAndHeader(file, resolve) {
        this.$emit('onGetParamsAndHeader', file, (params) => {
          resolve(params);
        })
      },

      /**上传图片配置**************************/

      /**
       * @description 数据改变事件
       */
      change(editor) {
        this.$emit('input', editor.getContent());
      },


      /**
       * @description 双向绑定数据处理
       */
      update(editor) {
        console.log('update', editor.getContent())
        this.$emit('input', editor.getContent());
        if (this.$parent.$options['componentName'] === 'ElFormItem') {
          this.dispatch('ElFormItem', 'el.form.change', [editor.getContent()]);
          this.dispatch('ElFormItem', 'el.form.blur', [editor.getContent()])
        }
      },
    }
  }
</script>

<style lang="scss" scoped>
  .tinymce-container {
    position: relative;
    line-height: normal;

    & ::v-deep {
      .mce-fullscreen {
        z-index: 10000;
      }

      & .mce-container-body.mce-stack-layout > *:first-child {
        border-bottom: 1px solid #e2e4e7;
      }

      .mce-container-body > *:first-child .mce-flow-layout {
        display: flex;
        justify-content: flex-start;
        align-items: center;
        flex-wrap: wrap;
        margin-right: 90px;
      }


      .mce-container-body > *:last-child {
        .mce-flow-layout {
          margin-right: 0!important;
        }

        .mce-flow-layout-item > div {
          display: flex;
          justify-content: flex-start;
          align-items: center;
          flex-wrap: wrap;
        }
      }

    }

  }

  .tinymce-textarea {
    visibility: hidden;
    z-index: -1;
  }

  .editor-custom-btn-container {
    position: absolute;
    right: 2px;
    top: 4px;
    z-index: 2;

    & ::v-deep {
      & .el-button {
        padding: 5px 10px;
        display: flex;
        justify-content: space-between;
        align-items: center;
      }

      i.el-icon-upload {
        font-size: 16px;
      }
    }
  }

  .fullscreen {
    z-index: 20000;

    & .editor-custom-btn-container {
      z-index: 10000;
      position: fixed;
    }

  }

  .editor-upload-btn {
    display: inline-block;
  }

  ::v-deep #mceu_51, ::v-deep #mceu_52 {
    display: block;
  }

  .tinymce-container-dialog {
    z-index: 10002;



    &-body {
      min-height: 200px;
      padding-bottom: 30px;
    }

    &-btn {
      display: flex;
      justify-content: flex-end;
      align-items: center;
    }

    ::v-deep {
      & .el-dialog__body {
        padding: 20px 20px 20px;
      }
    }

  }

  @media screen and (max-width: 768px) {
    ::v-deep .tinymce-container-dialog {
      width: 95% !important;

      &-body {
        max-height: 60vh;
        padding-bottom: 10px;
        overflow-y: auto;
      }

      & .el-dialog__header {
        padding: 10px;

        & .el-dialog__headerbtn {
          top: 10px;
          right: 10px;
        }

        & .el-dialog__title {
          font-size: 14px;
        }
      }

      & .el-dialog__body {
        padding: 0 10px 15px;
      }

      .xd-upload__list-box > *:nth-child(2n) {
        margin-right: 0;
      }
    }
  }
</style>
