<template>
  <div class="editor_root">
    <textarea
      :ref="`${editor_ref}_${randomNum}`"
      :id="`${editor_ref}_${randomNum}`"
      :style="`width: 100%;height: ${height}px;`"
    ></textarea>
  </div>
</template>

<script>
import { compressImg } from "@/utils";
export default {
  props: {
    savefolder: {
      type: String,
      default: function () {
        return "";
      }
    },
    content: {
      type: String,
      default: function () {
        return "";
      }
    },
    editor_ref: {
      type: String,
      default: function () {
        return "myCkeditor";
      }
    },
    content_index: {
      type: Number,
      default: 0
    },
    placeholder: {
      type: String,
      default: "请输入内容"
    },
    height: {
      type: Number,
      default: 150
    }
  },
  data() {
    return {
      randomNum: `${Math.ceil(Math.random() * 10000)}_${Date.now()}`,
      myCkeditor: null,
      imgsObj: {},
      editorHtml: "",
      editorTimer: null
    };
  },
  watch: {
    content: {
      handler(newHtml) {
        if (newHtml && this.editorHtml !== newHtml) {
          this.setContent(newHtml);
        }
      },
      immediate: true
    }
  },
  mounted() {
    this.initCkeditor();
  },
  beforeDestroy() {
    clearTimeout(this.editorTimer);
    this.editorTimer = null;
    if (this.myCkeditor) {
      this.myCkeditor.destroy();
    }
    this.myCkeditor = null;
  },
  methods: {
    setContent(content = "") {
      if (this.myCkeditor && this.myCkeditor.status === "ready") {
        if (this.editorHtml !== content) {
          this.myCkeditor.setData(content);
          let range = this.myCkeditor.createRange();
          range.moveToElementEditEnd(range.root);
          this.myCkeditor.getSelection().selectRanges([range]);
          range.scrollIntoView();
          this.editorHtml = content;
          this.editorContentChange();
        }
      } else {
        if (this.editorTimer) {
          clearTimeout(this.editorTimer);
          this.editorTimer = null;
        }
        this.editorTimer = setTimeout(() => {
          this.setContent(content);
        }, 100);
      }
    },
    editorContentChange() {
      this.$nextTick(() => {
        if (this.myCkeditor && this.myCkeditor.document.getBody().$) {
          let newHtml = this.myCkeditor.document.getBody().getHtml();
          let newText = this.myCkeditor.document.getBody().getText();
          this.editorHtml = newHtml;
          this.$emit("change", newHtml, newText, this.content_index);
        }
      });
    },
    elementFilter(el) {
      if (el.name === "img") {
        let imgSrc = el.attributes.src;
        if (imgSrc && el.attributes.role !== "presentation") {
          if (
            imgSrc.indexOf("http://") > -1 ||
            imgSrc.indexOf("https://") > -1
          ) {
            if (imgSrc.indexOf(this.$api.showImageUrl) == -1) {
              this.imgsObj[imgSrc] = "";
            }
          }
        }
      } else {
        if (!el.isEmpty && el.children && el.children.length > 0) {
          el.children.forEach((element) => {
            this.elementFilter(element);
          });
        }
      }
    },
    initCkeditor() {
      let that = this;
      that.myCkeditor = window.CKEDITOR.replace(
        that.$refs[`${this.editor_ref}_${this.randomNum}`],
        {
          height: that.height,
          customSavefolder: that.savefolder,
          filebrowserImageUploadUrl: that.$api.baseImageUrl,
          editorplaceholder: that.placeholder // 占位文本
        }
      );
      that.myCkeditor.on("instanceReady", function () {
        that.myCkeditor.dataProcessor.htmlFilter.addRules({
          elements: {
            $: function (el) {
              that.elementFilter(el);
            }
          }
        });
        that.myCkeditor.on("afterPaste", function () {
          let newImgsPromiseArr = [];
          for (const imgSrc in that.imgsObj) {
            if (!that.imgsObj[imgSrc] && imgSrc) {
              newImgsPromiseArr.push(that.changeImageUrl(imgSrc));
            }
          }
          if (newImgsPromiseArr.length > 0) {
            Promise.all(newImgsPromiseArr).then((newImgs) => {
              let oldhtml = "";
              if (that.myCkeditor && that.myCkeditor.document.getBody().$) {
                oldhtml = that.myCkeditor.document.getBody().getHtml();
              }
              for (const imgArr of newImgs) {
                if (imgArr && imgArr[0] && imgArr[1]) {
                  oldhtml = oldhtml.replaceAll(
                    imgArr[0].split("?")[0],
                    that.$api.showImageUrl + imgArr[1]
                  );
                }
              }
              let match = oldhtml.match(/data-cke-widget-data="([^"]*)"/g);
              if (match) {
                match.forEach((widgetItem) => {
                  let widgetKey = widgetItem.split('"')[1];
                  let widgetObj = JSON.parse(decodeURIComponent(widgetKey));
                  if (that.imgsObj[widgetObj.src]) {
                    widgetObj.src =
                      that.$api.showImageUrl + that.imgsObj[widgetObj.src];
                  }
                  oldhtml = oldhtml.replaceAll(
                    widgetKey,
                    encodeURIComponent(JSON.stringify(widgetObj))
                  );
                });
              }
              that.setContent(oldhtml);
            });
          }
        });
        that.myCkeditor.on("fileUploadRequest", async function (evt) {
          let fileLoader = evt.data.fileLoader,
            formData = new FormData(),
            xhr = fileLoader.xhr;
          formData.append("savefolder", that.savefolder);
          formData.append("iscover", "0");
          formData.append("isrename", "1");
          let filename = fileLoader.fileName;
          let myFile = fileLoader.file;
          if (myFile instanceof Blob) {
            formData.append(
              "file",
              new window.File([myFile], filename, { type: myFile.type })
            );
          } else {
            try {
              myFile = await compressImg(myFile);
            } catch (error) {
              console.log("compressImg-->", error);
            }
            formData.append("file", myFile);
          }
          let strArr = filename.split(".");
          filename = strArr[0];
          let suffix = strArr[strArr.length - 1];
          suffix = suffix.toLowerCase();
          if (suffix === "png" || suffix === "jpeg" || suffix === "jpg") {
            xhr.open("POST", that.$api.baseImageUrl + "up/upfile", true);
            xhr.send(formData);
          } else {
            that.$Message.warning("请上传png、jpeg、jpg格式的图片");
          }
          evt.stop();
        });
        that.myCkeditor.on("fileUploadResponse", function (evt) {
          let data = evt.data,
            xhr = data.fileLoader.xhr;
          let resolve = JSON.parse(xhr.responseText);
          if (resolve.code === 0) {
            data.url = that.$api.showImageUrl + resolve.obj;
          } else {
            data.message = resolve.msg;
            evt.cancel();
          }
          that.editorContentChange();
          evt.stop();
        });
        that.myCkeditor.on("change", function () {
          that.editorContentChange();
        });
        that.myCkeditor.on("focus", function () {
          that.editorContentChange();
        });
        that.myCkeditor.on("blur", function () {
          that.editorContentChange();
        });
      });
    },
    changeImageUrl(imgSrc) {
      let that = this;
      return new Promise((resolve, reject) => {
        let formData = new FormData();
        formData.append("newpath", that.savefolder);
        formData.append("filepath", imgSrc);
        that
          .axios({
            method: "POST",
            timeout: 1000 * window._config.axiosFileTimeout,
            url: that.$api.baseImageUrl + "dn/down_webfile",
            data: formData,
            headers: {
              "Content-Type": "multipart/form-data"
            }
          })
          .then((res) => {
            if (!res.data.code) {
              that.imgsObj[imgSrc] = res.data.obj;
              resolve([imgSrc, res.data.obj]);
            } else {
              reject();
              that.$Message.error(res.data.msg);
            }
          })
          .catch(() => {
            reject();
          });
      });
    }
  }
};
</script>

<style>
.ivu-message {
  z-index: 999999 !important;
}
</style>
<style scoped>
.editor_root {
  width: 100%;
}
</style>
