<template>
  <view
    class="tn-input-class tn-input"
    :class="{
      'tn-input--border': border,
      'tn-input--error': validateState
    }"
    :style="{
      padding: `0 ${border ? 20 : 0}rpx`,
      borderColor: borderColor,
      textAlign: inputAlign
    }"
    @tap.stop="inputClick"
  >
    <textarea
      v-if="type === 'textarea'"
      class="tn-input__input tn-input__textarea"
      :style="[inputStyle]"
      :value="defaultValue"
      :placeholder="placeholder"
      :placeholderStyle="placeholderStyle"
      :disabled="disabled || type === 'select'"
      :maxlength="maxLength"
      :fixed="fixed"
      :focus="focus"
      :autoHeight="autoHeight"
      :selectionStart="elSelectionStart"
      :selectionEnd="elSelectionEnd"
      :cursorSpacing="cursorSpacing"
      :showConfirmBar="showConfirmBar"
      @input="handleInput"
      @blur="handleBlur"
      @focus="onFocus"
      @confirm="onConfirm"
    />
    <input
      v-else
      class="tn-input__input"
      :type="type === 'password' ? 'text' : type"
      :style="[inputStyle]"
      :value="defaultValue"
      :password="type === 'password' && !showPassword"
      :placeholder="placeholder"
      :placeholderStyle="placeholderStyle"
      :disabled="disabled || type === 'select'"
      :maxlength="maxLength"
      :focus="focus"
      :confirmType="confirmType"
      :selectionStart="elSelectionStart"
      :selectionEnd="elSelectionEnd"
      :cursorSpacing="cursorSpacing"
      :showConfirmBar="showConfirmBar"
      @input="handleInput"
      @blur="handleBlur"
      @focus="onFocus"
      @confirm="onConfirm"
    />
    
    <!-- 右边的icon -->
    <view class="tn-input__right-icon tn-flex tn-flex-col-center">
      <!-- 清除按钮 -->
      <view
        v-if="clearable && value !== '' && focused"
        class="tn-input__right-icon__item tn-input__right-icon__clear"
        @tap="onClear"
      >
        <view class="icon tn-icon-close"></view>
      </view>
      <view
        v-else-if="type === 'text' && !focused && showRightIcon && rightIcon !== ''"
        class="tn-input__right-icon__item tn-input__right-icon__clear"
      >
        <view class="icon" :class="[`tn-icon-${rightIcon}`]"></view>
      </view>
      <!-- 显示密码按钮 -->
      <view
        v-if="passwordIcon && type === 'password'"
        class="tn-input__right-icon__item tn-input__right-icon__clear"
        @tap="showPassword = !showPassword"
      >
        <view v-if="!showPassword" class="tn-icon-eye-hide"></view>
        <view v-else class="icon tn-icon-eye"></view>
      </view>
      <!-- 可选项箭头 -->
      <view
        v-if="type === 'select'"
        class="tn-input__right-icon__item tn-input__right-icon__select"
        :class="{
          'tn-input__right-icon__select--reverse': selectOpen
        }"
      >
        <view class="icon tn-icon-up-triangle"></view>
      </view>
    </view>
  </view>
</template>

<script>
  import Emitter from '../../libs/utils/emitter.js'
  
  export default {
    mixins: [Emitter],
    name: 'tn-input',
    props: {
      value: {
        type: [String, Number],
        default: ''
      },
      // 输入框的类型
      type: {
        type: String,
        default: 'text'
      },
      // 输入框文字对齐方式
      inputAlign: {
        type: String,
        default: 'left'
      },
      // 文本框为空时显示的信息
      placeholder: {
        type: String,
        default: ''
      },
      placeholderStyle: {
        type: String,
        default: 'color: #AAAAAA'
      },
      // 是否禁用输入框
      disabled: {
        type: Boolean,
        default: false
      },
      // 可输入文字的最大长度
      maxLength: {
        type: Number,
        default: 255
      },
      // 输入框高度
      height: {
        type: Number,
        default: 0
      },
      // 根据内容自动调整高度
      autoHeight: {
        type: Boolean,
        default: true
      },
      // 键盘右下角显示的文字，仅在text时生效
      confirmType: {
        type: String,
        default: 'done'
      },
      // 输入框自定义样式
      customStyle: {
        type: Object,
        default() {
          return {}
        }
      },
      // 是否固定输入框
      fixed: {
        type: Boolean,
        default: false
      },
      // 是否自动获取焦点
      focus: {
        type: Boolean,
        default: false
      },
      // 当type为password时，是否显示右侧密码图标
      passwordIcon: {
        type: Boolean,
        default: true
      },
      // 当type为 input或者textarea时是否显示边框
      border: {
        type: Boolean,
        default: false
      },
      // 边框的颜色
      borderColor: {
        type: String,
        default: '#dcdfe6'
      },
      // 当type为select时，旋转右侧图标，标记当时select是打开还是关闭
      selectOpen: {
        type: Boolean,
        default: false
      },
      // 是否可清空
      clearable: {
        type: Boolean,
        default: true
      },
      // 光标与键盘的距离
      cursorSpacing: {
        type: Number,
        default: 0
      },
      // selectionStart和selectionEnd需要搭配使用，自动聚焦时生效
      // 光标起始位置
      selectionStart: {
        type: Number,
        default: -1
      },
      // 光标结束位置
      selectionEnd: {
        type: Number,
        default: -1
      },
      // 自动去除两端空格
      trim: {
        type: Boolean,
        default: true
      },
      // 是否显示键盘上方的完成按钮
      showConfirmBar: {
        type: Boolean,
        default: true
      },
      // 是否在输入框内最右边显示图标
      showRightIcon: {
        type: Boolean,
        default: false
      },
      // 最右边图标的名称
      rightIcon: {
        type: String,
        default: ''
      }
    },
    computed: {
      // 输入框样式
      inputStyle() {
        let style = {}
        // 如果没有设置高度，根据不同的类型设置一个默认值
        style.minHeight = this.height ? this.height + 'rpx' : 
          this.type === 'textarea' ? this.textareaHeight + 'rpx' : this.inputHeight + 'rpx'
        
        style = Object.assign(style, this.customStyle)
        
        return style
      },
      // 光标起始位置
      elSelectionStart() {
        return String(this.selectionStart)
      },
      // 光标结束位置
      elSelectionEnd() {
        return String(this.selectionEnd)
      }
    },
    data() {
      return {
        // 默认值
        defaultValue: this.value,
        // 输入框高度
        inputHeight: 70,
        // textarea的高度
        textareaHeight: 100,
        // 标记验证的状态
        validateState: false,
        // 标记是否获取到焦点
        focused: false,
        // 是否预览密码
        showPassword: false,
        // 用于头条小程序，判断@input中，前后的值是否发生了变化，因为头条中文下，按下键没有输入内容，也会触发@input事件
        lastValue: '',
      }
    },
    watch: {
      value(newVal, oldVal) {
        this.defaultValue = newVal
        // 当值发生变化时，并且type为select时，不会触发input事件
        // 模拟input事件
        if (newVal !== oldVal && this.type === 'select') {
          this.handleInput({
            detail: {
              value: newVal
            }
          })
        }
      }
    },
    created() {
      // 监听form-item发出的错误事件，将输入框变成红色
      this.$on("on-form-item-error", this.onFormItemError)
    },
    methods: {
      /**
       * input事件
       */
      handleInput(event) {
        let value = event.detail.value
        // 是否需要去掉空格
        if (this.trim) value = this.$tn.string.trim(value)
        // 原生事件
        this.$emit('input', value)
        // model赋值
        this.defaultValue = value
        // 过一个生命周期再发送事件给tn-form-item，否则this.$emit('input')更新了父组件的值，但是微信小程序上
        // 尚未更新到tn-form-item，导致获取的值为空，从而校验混论
        // 这里不能延时时间太短，或者使用this.$nextTick，否则在头条上，会造成混乱
        setTimeout(() => {
          // 头条小程序由于自身bug，导致中文下，每按下一个键(尚未完成输入)，都会触发一次@input，导致错误，这里进行判断处理
          // #ifdef MP-TOUTIAO
          if (this.$tn.string.trim(value) === this.lastValue) return
          this.lastValue = value
          // #endif
          
          // 发送当前的值到form-item进行校验
          this.dispatch('tn-form-item','on-form-change', value)
        }, 40)
      },
      /**
       * blur事件
       */
      handleBlur(event) {
        let value = event.detail.value
        
        // 由于点击清除图标也会触发blur事件，导致图标消失从而无法点击
        setTimeout(() => {
          this.focused = false
        }, 100)
        
        // 原生事件
        this.$emit('blur', value)
        // 过一个生命周期再发送事件给tn-form-item，否则this.$emit('blur')更新了父组件的值，但是微信小程序上
        // 尚未更新到tn-form-item，导致获取的值为空，从而校验混论
        // 这里不能延时时间太短，或者使用this.$nextTick，否则在头条上，会造成混乱
        setTimeout(() => {
          // 头条小程序由于自身bug，导致中文下，每按下一个键(尚未完成输入)，都会触发一次@input，导致错误，这里进行判断处理
          // #ifdef MP-TOUTIAO
          if (this.$tn.string.trim(value) === this.lastValue) return
          this.lastValue = value
          // #endif
          
          // 发送当前的值到form-item进行校验
          this.dispatch('tn-form-item','on-form-blur', value)
        }, 40)
      },
      // 处理校验错误
      onFormItemError(status) {
        this.validateState = status
      },
      // 聚焦事件
      onFocus(event) {
        this.focused = true
        this.$emit('focus')
      },
      // 点击确认按钮事件
      onConfirm(event) {
        this.$emit('confirm', event.detail.value)
      },
      // 清除事件
      onClear(event) {
        this.$emit('input', '')
      },
      // 点击事件
      inputClick() {
        this.$emit('click')
      }
    }
  }
</script>

<style lang="scss" scoped>
  .tn-input {
    display: flex;
    flex-direction: row;
    position: relative;
    flex: 1;
    
    &__input {
      font-size: 28rpx;
      color: #080808;
      flex: 1;
    }
    
    &__textarea {
      width: auto;
      font-size: 28rpx;
      color: #080808;
      padding: 10rpx 0;
      line-height: normal;
      flex: 1;
    }
    
    &--border {
      border-radius: 6rpx;
      border: 2rpx solid rgba(0, 0, 0, 0.1);
    }
    
    &--error {
      border-color: rgba(0, 0, 0, 0.1)rtant;
    }
    
    &__right-icon {
      line-height: 1;
      .icon {
        color: #AAAAAA;
      }
      
      &__item {
        margin-left: 10rpx;
      }
      
      &__clear {
        .icon {
          font-size: 32rpx;
        }
      }
      
      &__select {
        transition: transform .4s;
        
        .icon {
          font-size: 26rpx;
        }
        
        &--reverse {
          transform: rotate(-180deg);
        }
      }
    }
  }
</style>
