<template>
  <div class="rich-text-editor cc-editor">
    <quill-editor
      :id="editorId"
      :content="content"
      ref="QuillEditor"
      @change="onEditorChange"
      :options="options"
    ></quill-editor>
    <input
      style="display: none"
      :id="uniqueInputId"
      type="file"
      name="fileinput"
      @change="uploadImg"
    />
    <el-progress
      :percentage="percentage"
      :stroke-width="2"
      :show-text="false"
    ></el-progress>
  </div>
</template>

<script>
// 文档：https://github.com/surmon-china/vue-quill-editor
import ajax from "../utils/ajax";
import Quill from "quill";
import Delta from "quill-delta";
import { quillEditor } from "vue-quill-editor";
import "quill/dist/quill.snow.css";
import ImageResize from "quill-image-resize-module";
Quill.register("modules/imageResize", ImageResize);

export default {
  name: "rich-text-editor",
  props: {
    value: String,
    // upload
    action: {
      type: String,
      required: true
    },
    headers: {
      type: Object,
      default() {
        return {};
      }
    },
    withCredentials: {
      type: Boolean,
      default: false
    },
    data: {
      type: Object
    },
    name: {
      type: String,
      default: "file"
    },
    maxSize: {
      type: Number,
      default: 2 * 1024
    },
    rendFileUrl: {
      type: Function,
      default(fileInfo) {
        return fileInfo;
      }
    },
    onUploadSuccess: {
      type: Function,
      default() {
        return {};
      }
    },
    onUploadError: {
      type: Function,
      default() {
        return {};
      }
    }
  },
  components: {
    quillEditor
  },
  data() {
    return {
      content: "",
      iframeSrc: "",
      options: {
        placeholder: "请输入内容",
        modules: {
          toolbar: [
            ["bold", "italic", "underline", "strike"],
            ["blockquote", "code-block"],
            [{ list: "ordered" }, { list: "bullet" }],
            [{ script: "sub" }, { script: "super" }],
            [{ indent: "-1" }, { indent: "+1" }, { direction: "rtl" }],
            [{ size: ["small", false, "large", "huge"] }],
            [{ header: [1, 2, 3, 4, 5, 6, false] }],
            [{ color: [] }, { background: [] }, { align: [] }],
            ["clean", "link", "image"]
          ],
          imageResize: true,
          history: {
            delay: 1000,
            maxStack: 50,
            userOnly: false
          }
        }
      },
      percentage: 0,
      uniqueInputId: "",
      uploadImages: [],
      editorId: "",
      // math-modal
      src: "",
      mathModalIsShow: false
    };
  },
  computed: {
    editor() {
      return this.$refs.QuillEditor.quill;
    }
  },
  watch: {
    value(val) {
      this.content = val;
    }
  },
  mounted() {
    const serno = Math.random()
      .toString(16)
      .slice(-8);
    this.editorId = "rich-text-editor-" + serno;
    this.uniqueInputId = "file-input-" + serno;

    this.registImageHandle();
    this.registPasteEvent();
    this.content = this.value;
  },
  methods: {
    registPasteEvent() {
      const inputBox = this.$el.querySelector(".ql-editor");
      inputBox.addEventListener("paste", e => {
        e.preventDefault();
        let items = e.clipboardData ? e.clipboardData.items : [];
        if (!items || !items.length) return;

        for (let i = 0; i < items.length; i++) {
          let item = items[i];
          if (
            item &&
            item.kind === "string" &&
            item.type.match(/^text\/plain/i)
          ) {
            this.textPasteHandle(item);
            break;
          } else if (
            item &&
            item.kind === "file" &&
            item.type.match(/^image\//i)
          ) {
            this.imgPasteHandle(item);
            break;
          }
        }
      });
    },
    textPasteHandle(item) {
      item.getAsString(content => {
        this.insertText(content);
      });
    },
    imgPasteHandle(item) {
      let file = item.getAsFile();

      // 展示文件
      // const reader = new FileReader();
      // reader.onload = e => {
      //   this.insertImg(e.target.result);
      // };
      // reader.readAsDataURL(file);

      this.upload(file)
        .then(rep => {
          const fileUrl = this.rendFileUrl(rep);
          this.insertImg(fileUrl);
          this.onUploadSuccess(fileUrl);
        })
        .catch(error => {
          this.onUploadError(error);
        });
    },
    registImageHandle() {
      let that = this;
      let imgHandler = async state => {
        if (state) {
          let fileInput = document.getElementById(that.uniqueInputId);
          fileInput.click();
        }
      };
      that.editor.getModule("toolbar").addHandler("image", imgHandler);
    },
    onEditorChange() {
      this.$emit("input", this.content);
    },
    uploadImg() {
      let file = document.getElementById(this.uniqueInputId).files[0];
      this.upload(file)
        .then(rep => {
          const fileUrl = this.rendFileUrl(rep);
          this.insertImg(fileUrl);
          this.onUploadSuccess(fileUrl);
        })
        .catch(error => {
          this.onUploadError(error);
        });
    },
    getSelectionIndex() {
      this.editor.focus();
      const selectionRange = this.editor.getSelection();
      if (selectionRange && selectionRange.length)
        this.editor.deleteText(selectionRange.index, selectionRange.length);

      return selectionRange ? selectionRange.index : 0;
    },
    insertText(content) {
      const index = this.getSelectionIndex();
      this.editor.insertEmbed(index, "text", content, "user");
    },
    insertImg(url, alt) {
      const index = this.getSelectionIndex();
      let delta = this.editor.insertEmbed(index, "image", url, "user");
      this.editor.setSelection(index + 1);
      if (alt) {
        let retain = delta.ops[0].retain;
        this.editor.updateContents(
          new Delta().retain(retain).retain(1, { alt })
        );
      }
    },
    base64ToBlob(base64Str) {
      var bytes = atob(base64Str.split(",")[1]);
      let arr = new Uint8Array(bytes.length);
      for (let i = 0; i < bytes.length; i++) {
        arr[i] = bytes.charCodeAt(i);
      }
      return new Blob([arr], { type: "image/png" });
    },
    upload(file) {
      if (file.size > this.maxSize * 1024) {
        return Promise.reject({ msg: "图片过大，请重新编辑!" });
      }
      return new Promise((resolve, reject) => {
        ajax({
          headers: this.headers,
          withCredentials: this.withCredentials,
          file: file,
          data: this.data,
          filename: this.name,
          action: this.action,
          onProgress: e => {
            this.percentage = e.percent || 0;
            if (this.percentage === 100) {
              setTimeout(() => {
                this.percentage = 0;
              }, 300);
            }
          },
          onSuccess: res => {
            resolve(res);
          },
          onError: (err, response) => {
            reject({ err, response });
          }
        });
      });
    }
  }
};
</script>
