<template>
  <div class="editor">
    <div v-if="userId && userId === 0" class="not-logged">
      <span>{{ $t("post.publishAfterLogin") }}</span>
    </div>
    <label v-if="typeInformation && typeInformation.showTitle">
      <input
        :placeholder="$t('post.pleaseInputPostTitle')"
        class="input-title"
        type="text"
        :value="post && post.title"
        @input="e => onPostContentChange('title', e.target.value)"
      >
    </label>
    <!--问答帖 -->
    <editor-qa
      v-if="typeInformation && typeInformation.type === 5"
      :question="question"
      @paymentTypeChange="value => onQuestionChange('paymentType', value)"
      @isAnonymousChange="value => onQuestionChange('isAnonymous', value)"
      @isOnlookerChange="value => onQuestionChange('isOnlooker', value)"
      @beUserChange="value => onQuestionChange('beUser', value)"
    />
    <!--商品帖 -->
    <editor-product
      v-if="typeInformation && typeInformation.type === 6"
      :product="product"
      @productChange="onProductChange"
    />
    <editor-payment
      v-if="
        typeInformation && typeInformation.showPayment && canCreateThreadPaid
      "
      :payment="payment || {}"
      :type="typeInformation && typeInformation.type"
      :can-upload-attachments="canUploadAttachments"
      @paymentChange="e => onPaymentChange(e.key, e.value)"
    />
    <attachment-upload
      v-if="isPost && canUploadAttachments"
      :file-list="post && post.attachedList"
      :on-upload.sync="onUploadAttached"
      action="/attachments"
      :accept="attachedTypeLimit"
      :limit="99999"
      :type="0"
      :size-limit="attachedSizeLimit"
      @success="files => onPostContentChange('attachedList', files)"
      @remove="files => onPostContentChange('attachedList', files)"
    />
    <Vditor
      v-if="isPost"
      :text-limit="typeInformation && typeInformation.textLimit"
      :text-length="post && post.text && post.text.length"
      :placeholder="typeInformation && typeInformation.placeholder"
      :image-accept="imageTypeLimit"
      :text="post && post.text"
      :show-caller="showCaller"
      :show-topic="showTopic"
      :show-emoji="showEmoji"
      :is-edit="isEdit"
      :on-publish="onPublish"
      :attachment-size-limit="attachedSizeLimit"
      :on-upload-image.sync="onUploadImage"
      @textChange="value => onPostContentChange('text', value)"
      @close="showCaller = false"
      @hideActions="hideActions"
      @onActions="onActions"
      @publish="publish"
    />
    <!--my editor 除了帖子以外，不使用 vditor-->
    <div v-if="!isPost" :class="['container-textarea', editorStyle]">
      <!--bar-->
      <editor-tool-bar
        v-if="editorStyle === 'post'"
        :text-limit="typeInformation && typeInformation.textLimit"
        :text-length="post && post.text && post.text.length"
        :actions="actions"
        :show-emoji="showEmoji"
        :show-topic="showTopic"
        :show-caller="showCaller"
        :resources="resources"
        :on-publish="onPublish"
        :editor-style="editorStyle"
        @publish="publish"
        @selectActions="selectActions"
        @addResource="addResource"
        @hidePop="hideActions"
        @onActions="onActions"
      />
      <label>
        <textarea
          id="textarea"
          :value="post && post.text"
          :class="['input-text', editorStyle]"
          :placeholder="typeInformation ? typeInformation.placeholder : ''"
          :maxlength="post && post.textLimit"
          @input="e => onPostContentChange('text', e.target.value)"
        />
      </label>
      <div>
        <!--uploader type 15 是回答图片-->
        <div v-if="showUploadImg || showUploadVideo" class="resources-list">
          <image-upload
            v-if="showUploadImg"
            :type="typeInformation.type && typeInformation.type === 15 ? 5 : 1"
            :file-list="post && post.imageList"
            :on-upload.sync="onUploadImage"
            action="/attachments"
            :accept="imageTypeLimit"
            :limit="9"
            :size-limit="attachedSizeLimit"
            @success="imageList => onPostContentChange('imageList', imageList)"
            @remove="imageList => onPostContentChange('imageList', imageList)"
          />
          <video-upload
            v-if="showUploadVideo"
            :on-upload-video.sync="onUploadVideo"
            :video-list="post && post.videoList"
            @videoChange="e => onPostContentChange(e.key, e.value)"
          />
        </div>
        <!--bar-->
        <editor-tool-bar
          v-if="editorStyle !== 'post'"
          :text-limit="(typeInformation && typeInformation.textLimit) || 450"
          :text-length="(post && post.text && post.text.length) || 0"
          :actions="actions"
          :show-emoji="showEmoji"
          :show-topic="showTopic"
          :show-caller="showCaller"
          :resources="resources"
          :on-publish="onPublish"
          :editor-style="editorStyle"
          @publish="publish"
          @selectActions="selectActions"
          @addResource="addResource"
          @hidePop="hideActions"
          @onActions="onActions"
        />
      </div>
    </div>
    <caller
      v-if="showCaller && !isPost"
      @close="showCaller = false"
      @selectedCaller="selectActions"
    />
  </div>
</template>

<script>
import handleError from '@/mixin/handleError';

export default {
  name: 'Editor',
  mixins: [handleError],
  props: {
    post: {
      type: Object,
      default: () => {}
    },
    payment: {
      type: Object,
      default: () => {}
    },
    question: {
      type: Object,
      default: () => {}
    },
    product: {
      type: Object,
      default: () => {}
    },
    typeInformation: {
      type: Object,
      default: () => {}
    },
    editResourceShow: {
      type: Object,
      default: () => {}
    },
    isEdit: {
      type: Boolean,
      default: false
    },
    onPublish: {
      type: Boolean,
      default: false
    },
    editorStyle: {
      // post chat comment reply 代表不同的编辑器风格
      type: String,
      default: 'post'
    },
    selector: {
      // 当页面出现多个编辑器时，必须传入 selector (对应的 class name) 作为唯一的选择器，保证 textarea 元素选择正确
      type: String,
      default: 'editor'
    }
  },
  data() {
    return {
      input: {},
      vditor: {},
      selectionStart: 0,
      selectionEnd: 0,
      // 是否显示弹窗
      showEmoji: false,
      showCaller: false,
      showTopic: false,
      showUploadImg: false,
      showUploadVideo: false,
      showUploadAttached: false,

      onUploadImage: false,
      onUploadVideo: false,
      onUploadAttached: false,

      listenerList: ['emoji-list', 'topic-list'],
      actions: [
        { icon: 'emoji', toggle: 'showEmoji', show: false },
        { icon: 'call', toggle: 'showCaller', show: false },
        { icon: 'topic', toggle: 'showTopic', show: false }
      ],
      resources: [
        { icon: 'picture', toggle: 'showUploadImg', show: false },
        { icon: 'video', toggle: 'showUploadVideo', show: false }
        // { icon: 'attached', toggle: 'showUploadAttached', show: false }
      ]
    };
  },
  computed: {
    userId() {
      return this.$store.state.session.userId;
    },
    url() {
      return '/api';
    },
    header() {
      if (process.client) {
        const token = window.localStorage.getItem('access_token');
        return { authorization: `Bearer ${token}` };
      }
      return {};
    },
    textarea() {
      return process.client
        ? document.querySelector(`.${this.selector} #textarea`)
        : '';
    },
    forums() {
      return this.$store.state.site.info.attributes || {};
    },
    canCreateThreadPaid() {
      return this.forums && this.forums.other
        ? this.forums.other.can_create_thread_paid
        : false;
    },
    canUploadAttachments() {
      return this.forums && this.forums.other
        ? this.forums.other.can_upload_attachments
        : false;
    },
    attachedSizeLimit() {
      if (this.forums.set_attach) {
        return this.forums.set_attach.support_max_size * 1024 * 1024;
      }
      return 10485760; // 1024 * 1024 * 10 = 10M (保底值)
    },
    imageTypeLimit() {
      if (this.forums.set_attach) {
        const limitText = this.forums.set_attach.support_img_ext;
        return limitText
          .split(',')
          .map(item => `.${item}`)
          .join(',');
      }
      return '';
    },
    attachedTypeLimit() {
      if (this.forums.set_attach) {
        const limitText = this.forums.set_attach.support_file_ext;
        return limitText
          .split(',')
          .map(item => `.${item}`)
          .join(',');
      }
      return '';
    },
    isPost() {
      // 帖子类型 type 1
      return (this.typeInformation && this.typeInformation.type === 1) || false;
    }
  },
  watch: {
    editResourceShow: {
      handler(val) {
        if (!val) return;
        for (const key in val) this[key] = val[key];
      },
      deep: true,
      immediate: true
    },
    typeInformation: {
      handler(val) {
        if (!val) return;
        this.actions[0].show = val.showEmoji;
        this.actions[1].show = val.showCaller;
        this.actions[2].show = val.showTopic;
        this.resources[0].show = val.showImage;
        this.resources[1].show = val.showVideo;
        // this.resources[2].show = val.showAttached
      },
      deep: true,
      immediate: true
    }
  },
  mounted() {
    this.textarea && this.autoHeight();
    this.emojiListener();
  },
  methods: {
    onPostContentChange(key, value) {
      const _post = Object.assign({}, this.post);
      _post[key] = value;
      this.$emit(`update:post`, _post);
    },
    onPaymentChange(key, value) {
      const _payment = Object.assign({}, this.payment);
      _payment[key] = value;
      this.$emit(`update:payment`, _payment);
    },
    onQuestionChange(key, value) {
      const _question = Object.assign({}, this.question);
      _question[key] = value;
      this.$emit(`update:question`, _question);
    },
    onProductChange(product) {
      const _product = Object.assign({}, product);
      this.$emit(`update:product`, _product);
    },
    autoHeight() {
      if (this.editorStyle === 'chat') return; // 聊天框不需要自动高度
      // 编辑评论时需要改变内容才会触发自动高度，这里判断评论字数超过一定数量时给textarea一个初始高度以防高度不变导致内容无法展示
      if (this.post.text.length > 310) this.textarea.style.height = '180px';
      this.textarea.onkeyup = function() {
        // textarea 自动高度，通过 scrollHeight 赋值给 height
        // 当行数减少是 scrollHeight 只增不减，所以需要先把 height = auto
        // 但是会引起页面滚动条往上滚动，因为 textarea 高度瞬间减少了
        // 所以需要记录 oldScroll 重置滚动条
        const oldScroll = document.scrollingElement.scrollTop;
        this.style.height = 'auto';
        this.style.height = `${this.scrollHeight}px`;
        document.scrollingElement.scrollTop = oldScroll;
      };
    },
    getSelection() {
      this.selectionStart = this.textarea.selectionStart;
      this.selectionEnd = this.textarea.selectionEnd;
    },
    emojiListener() {
      document.addEventListener('click', e => {
        let pass = true;
        const path = e.path || (e.composedPath && e.composedPath());
        path.forEach(item => {
          if (item.classList) {
            if (
              item.classList.contains('emoji-list')
              || item.classList.contains('topic-list')
              || item.classList.contains('editor-bar')
            ) {
              pass = false;
            }
          }
        });
        if (pass) {
          this.showTopic = false;
          this.showEmoji = false;
        }
      });
    },
    onActions(toggle) {
      this.hideActions();
      setTimeout(() => {
        this[toggle] = !this[toggle];
      });
    },
    addResource(toggle) {
      this[toggle] = true;
    },
    selectActions(code) {
      this.getSelection();
      const _text
        = this.post.text.slice(0, this.selectionStart)
        + code
        + this.post.text.slice(this.selectionStart, this.post.text.length);
      this.onPostContentChange('text', _text);
      this.hideActions();
    },
    hideActions() {
      this.showEmoji = false;
      this.showTopic = false;
      this.showCaller = false;
    },
    publish() {
      if (this.onUploadAttached) {
        return this.$message.warning(
          this.$t('post.pleaseWaitForTheAttachedUploadToComplete')
        );
      }
      if (this.onUploadImage) {
        return this.$message.warning(
          this.$t('post.pleaseWaitForTheImageUploadToComplete')
        );
      }
      if (this.onUploadVideo) {
        return this.$message.warning(
          this.$t('post.pleaseWaitForTheVideoUploadToComplete')
        );
      }
      this.$emit('update:onPublish', true);
      this.$emit('publish');
    }
  }
};
</script>

<style lang="scss" scoped>
@import "@/assets/css/variable/color.scss";

/* editor placeholder */
::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, 0.3);
  -webkit-border-radius: 100px;
}
::-webkit-scrollbar-thumb:active {
  font-family: inherit;
  background: rgba(0, 0, 0, 0.4);
  -webkit-border-radius: 100px;
}
::-webkit-input-placeholder {
  /* Chrome/Opera/Safari */
  font-family: inherit;
  font-size: 16px;
  color: #ddd;
}
::-moz-placeholder {
  /* Firefox 19+ */
  font-family: inherit;
  font-size: 16px;
  color: #ddd;
}
:-ms-input-placeholder {
  /* IE 10+ */
  font-family: inherit;
  font-size: 16px;
  color: #ddd;
}
:-moz-placeholder {
  /* Firefox 18- */
  font-family: inherit;
  font-size: 16px;
  color: #ddd;
}

.editor {
  width: 100%;
  margin-top: 20px;
  position: relative;

  > .not-logged {
    position: absolute;
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    background: rgba(255, 255, 255, 0.3);
    z-index: 1000000000;
    color: #8590a6;
    font-size: 20px;
    span {
      transform: translateY(-20px);
    }
  }

  label {
    width: 100%;

    > input {
      width: 100%;
      background: $background-color-editor;
    }

    > .input-title {
      height: 40px;
      padding: 0 15px;
      border-radius: 3px;
      border: 1px solid $border-color-base;
    }

    > .input-text {
      font-family: inherit;
      background: $background-color-editor;
      width: 100%;
      border: none;
      display: block;
      position: relative;
      resize: none;
      line-height: 16px;
      padding: 15px 15px 20px;
      overflow: hidden;
      overscroll-behavior: contain;
      transition: all 100ms linear;
      &.post {
        min-height: 200px;
      }
      &.comment {
        min-height: 120px;
      }
      &.reply {
        min-height: 80px;
      }
      &.chat {
        height: 120px;
        background: #fff;
        overflow: auto;
      }
    }
  }

  > .container-textarea {
    border: 1px solid $border-color-base;
    border-radius: 3px;
    position: relative;
    margin-top: 30px;
    &.reply {
      margin-top: 0;
      margin-left: 60px;
    }
    &.chat {
      margin-top: 0;
    }
    &.comment {
      margin-top: 0;
    }
  }

  .resources-list {
    background: $background-color-grey;
    padding: 20px 20px 30px;
  }
}
</style>
