<template>
    <view class="uv-input" :class="inputClass" :style="[wrapperStyle]">
      <view class="uv-input__content">
        <view class="uv-input__content__prefix-icon">
          <slot name="prefix">
            <uv-icon
							v-if="prefixIcon"
              :name="prefixIcon"
              size="18"
              :customStyle="prefixIconStyle"
            ></uv-icon>
          </slot>
        </view>
        <view class="uv-input__content__field-wrapper" @click="clickHandler">
				<!-- 根據uni-app的input組件文檔，H5和APP中只要聲明了password參數(無論true還是false)，type均失效，此時
				為了防止type=number時，又存在password屬性，type無效，此時需要設置password為undefined
			 -->
        	<input
        	  class="uv-input__content__field-wrapper__field"
        	  :style="[inputStyle]"
        	  :type="type"
        	  :focus="focus"
        	  :cursor="cursor"
        	  :value="innerValue"
        	  :auto-blur="autoBlur"
        	  :disabled="disabled || readonly"
        	  :maxlength="maxlength"
        	  :placeholder="placeholder"
        	  :placeholder-style="placeholderStyle"
        	  :placeholder-class="placeholderClass"
        	  :confirm-type="confirmType"
        	  :confirm-hold="confirmHold"
        	  :hold-keyboard="holdKeyboard"
        	  :cursor-spacing="cursorSpacing"
        	  :adjust-position="adjustPosition"
        	  :selection-end="selectionEnd"
        	  :selection-start="selectionStart"
        	  :password="password || type === 'password' || undefined"
            :ignoreCompositionEvent="ignoreCompositionEvent"
        	  @input="onInput"
        	  @blur="onBlur"
        	  @focus="onFocus"
        	  @confirm="onConfirm"
        	  @keyboardheightchange="onkeyboardheightchange"
        	/>
        </view>
        <view
          class="uv-input__content__clear"
          v-if="isShowClear"
          @tap="onClear"
        >
          <uv-icon
            name="close"
            size="11"
            color="#ffffff"
            customStyle="line-height: 12px"
          ></uv-icon>
        </view>
        <view class="uv-input__content__subfix-icon">
          <slot name="suffix">
            <uv-icon
							v-if="suffixIcon"
              :name="suffixIcon"
              size="18"
              :customStyle="suffixIconStyle"
            ></uv-icon>
          </slot>
        </view>
      </view>
    </view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from "./props.js";
	/**
	 * Input 輸入框
	 * @description  此組件為壹個輸入框，默認沒有邊框和樣式，是專門為配合表單組件uv-form而設計的，利用它可以快速實現表單驗證，輸入內容，下拉選擇等功能。
	 * @tutorial https://www.uvui.cn/components/input.html
	 * @property {String | Number}	value					輸入的值
	 * @property {String}			type					輸入框類型，見上方說明 （ 默認 'text' ）
	 * @property {Boolean}			fixed					如果 textarea 是在壹個 position:fixed 的區域，需要顯示指定屬性 fixed 為 true，兼容性：微信小程序、百度小程序、字節跳動小程序、QQ小程序 （ 默認 false ）
	 * @property {Boolean}			disabled				是否禁用輸入框 （ 默認 false ）
	 * @property {String}			disabledColor			禁用狀態時的背景色（ 默認 '#f5f7fa' ）
	 * @property {Boolean}			clearable				是否顯示清除控件 （ 默認 false ）
	 * @property {Boolean}			password				是否密碼類型 （ 默認 false ）
	 * @property {String | Number}	maxlength				最大輸入長度，設置為 -1 的時候不限制最大長度 （ 默認 -1 ）
	 * @property {String}			placeholder				輸入框為空時的占位符
	 * @property {String}			placeholderClass		指定placeholder的樣式類，註意頁面或組件的style中寫了scoped時，需要在類名前寫/deep/ （ 默認 'input-placeholder' ）
	 * @property {String | Object}	placeholderStyle		指定placeholder的樣式，字符串/對象形式，如"color: red;"
	 * @property {Boolean}			showWordLimit			是否顯示輸入字數統計，只在 type ="text"或type ="textarea"時有效 （ 默認 false ）
	 * @property {String}			confirmType				設置右下角按鈕的文字，兼容性詳見uni-app文檔 （ 默認 'done' ）
	 * @property {Boolean}			confirmHold				點擊鍵盤右下角按鈕時是否保持鍵盤不收起，H5無效 （ 默認 false ）
	 * @property {Boolean}			holdKeyboard			focus時，點擊頁面的時候不收起鍵盤，微信小程序有效 （ 默認 false ）
	 * @property {Boolean}			focus					自動獲取焦點，在 H5 平臺能否聚焦以及軟鍵盤是否跟隨彈出，取決於當前瀏覽器本身的實現。nvue 頁面不支持，需使用組件的 focus()、blur() 方法控制焦點 （ 默認 false ）
	 * @property {Boolean}			autoBlur				鍵盤收起時，是否自動失去焦點，目前僅App3.0.0+有效 （ 默認 false ）
	 * @property {Boolean}			disableDefaultPadding	是否去掉 iOS 下的默認內邊距，僅微信小程序，且type=textarea時有效 （ 默認 false ）
	 * @property {String ｜ Number}	cursor					指定focus時光標的位置（ 默認 -1 ）
	 * @property {String ｜ Number}	cursorSpacing			輸入框聚焦時底部與鍵盤的距離 （ 默認 30 ）
	 * @property {String ｜ Number}	selectionStart			光標起始位置，自動聚集時有效，需與selection-end搭配使用 （ 默認 -1 ）
	 * @property {String ｜ Number}	selectionEnd			光標結束位置，自動聚集時有效，需與selection-start搭配使用 （ 默認 -1 ）
	 * @property {Boolean}			adjustPosition			鍵盤彈起時，是否自動上推頁面 （ 默認 true ）
	 * @property {String}			inputAlign				輸入框內容對齊方式（ 默認 'left' ）
	 * @property {String | Number}	fontSize				輸入框字體的大小 （ 默認 '15px' ）
	 * @property {String}			color					輸入框字體顏色	（ 默認 '#303133' ）
	 * @property {Function}			formatter			    內容式化函數
	 * @property {String}			prefixIcon				輸入框前置圖標
	 * @property {String | Object}	prefixIconStyle			前置圖標樣式，對象或字符串
	 * @property {String}			suffixIcon				輸入框後置圖標
	 * @property {String | Object}	suffixIconStyle			後置圖標樣式，對象或字符串
	 * @property {String}			border					邊框類型，surround-四週邊框，bottom-底部邊框，none-無邊框 （ 默認 'surround' ）
	 * @property {Boolean}			readonly				是否只讀，與disabled不同之處在於disabled會置灰組件，而readonly則不會 （ 默認 false ）
	 * @property {String}			shape					輸入框形狀，circle-圓形，square-方形 （ 默認 'square' ）
	 * @property {Object}			customStyle				定義需要用到的外部樣式
	 * @property {Boolean}			ignoreCompositionEvent	是否忽略組件內對文本合成系統事件的處理。
	 * @example <uv-input v-model="value" :password="true" suffix-icon="lock-fill" />
	 */
	export default {
		name: "uv-input",
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				// 輸入框的值
				innerValue: "",
				// 是否處於獲得焦點狀態
				focused: false,
				// 過濾處理方法
				innerFormatter: value => value
			}
		},
		created() {
			// #ifdef VUE2
			this.innerValue = this.value;
			// #endif
			// #ifdef VUE3
			this.innerValue = this.modelValue;
			// #endif
		},
		watch: {
			value(newVal){
				this.innerValue = newVal;
			},
			modelValue(newVal){
				this.innerValue = newVal;
			}
		},
		computed: {
			// 是否顯示清除控件
			isShowClear() {
				const { clearable, readonly, focused, innerValue } = this;
				return !!clearable && !readonly && !!focused && innerValue !== "";
			},
			// 組件的類名
			inputClass() {
				let classes = [],
					{ border, disabled, shape } = this;
				border === "surround" &&
					(classes = classes.concat(["uv-border", "uv-input--radius"]));
				classes.push(`uv-input--${shape}`);
				border === "bottom" &&
					(classes = classes.concat([
						"uv-border-bottom",
						"uv-input--no-radius",
					]));
				return classes.join(" ");
			},
			// 組件的樣式
			wrapperStyle() {
				const style = {};
				// 禁用狀態下，被背景色加上對應的樣式
				if (this.disabled) {
					style.backgroundColor = this.disabledColor;
				}
				// 無邊框時，去除內邊距
				if (this.border === "none") {
					style.padding = "0";
				} else {
					// 由於uni-app的iOS開發者能力有限，導致需要分開寫才有效
					style.paddingTop = "6px";
					style.paddingBottom = "6px";
					style.paddingLeft = "9px";
					style.paddingRight = "9px";
				}
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle));
			},
			// 輸入框的樣式
			inputStyle() {
				const style = {
					color: this.color,
					fontSize: this.$uv.addUnit(this.fontSize),
					textAlign: this.inputAlign
				};
				// #ifndef APP-NVUE
				if(this.disabled || this.readonly) {
					style['pointer-events'] = 'none';
				}
				// #endif
				return style;
			}
		},
		methods: {
			// 在微信小程序中，不支持將函數當做props參數，故只能通過ref形式調用
			setFormatter(e) {
				this.innerFormatter = e
			},
			// 當鍵盤輸入時，觸發input事件
			onInput(e) {
				let { value = "" } = e.detail || {};
				// 格式化過濾方法
				const formatter = this.formatter || this.innerFormatter
				const formatValue = formatter(value)
				// 為了避免props的單向數據流特性，需要先將innerValue值設置為當前值，再在$nextTick中重新賦予設置後的值才有效
				this.innerValue = value
				this.$nextTick(() => {
					this.innerValue = formatValue;
					this.valueChange();
				})
			},
			// 輸入框失去焦點時觸發
			onBlur(event) {
				this.$emit("blur", event.detail.value);
				// H5端的blur會先於點擊清除控件的點擊click事件觸發，導致focused
				// 瞬間為false，從而隱藏了清除控件而無法被點擊到
				this.$uv.sleep(100).then(() => {
					this.focused = false;
				});
				// 嘗試調用uv-form的驗證方法
				this.$uv.formValidate(this, "blur");
			},
			// 輸入框聚焦時觸發
			onFocus(event) {
				this.focused = true;
				this.$emit("focus");
			},
			// 點擊完成按鈕時觸發
			onConfirm(event) {
				this.$emit("confirm", this.innerValue);
			},
			// 鍵盤高度發生變化的時候觸發此事件
			// 兼容性：微信小程序2.7.0+、App 3.1.0+
			onkeyboardheightchange(e) {
				this.$emit("keyboardheightchange",e);
			},
			// 內容發生變化，進行處理
			valueChange() {
				if(this.isClear) this.innerValue = '';
				const value = this.innerValue;
				this.$nextTick(() => {
					this.$emit("input", value);
					this.$emit("update:modelValue", value);
					this.$emit("change", value);
					// 嘗試調用uv-form的驗證方法
					this.$uv.formValidate(this, "change");
				});
			},
			// 點擊清除控件
			onClear() {
				this.innerValue = "";
				this.isClear = true;
				this.$uv.sleep(200).then(res=>{
					this.isClear = false;
				})
				this.$nextTick(() => {
					this.$emit("clear");
					this.valueChange();
				});
			},
			/**
			 * 在安卓nvue上，事件無法冒泡
			 * 在某些時間，我們希望監聽uv-from-item的點擊事件，此時會導致點擊uv-form-item內的uv-input後
			 * 無法觸發uv-form-item的點擊事件，這裏通過手動調用uv-form-item的方法進行觸發
			 */
			clickHandler() {
				// #ifdef APP-NVUE
				if (this.$uv.os() === "android") {
					const formItem = this.$uv.$parent.call(this, "uv-form-item");
					if (formItem) {
						formItem.clickHandler();
					}
				}
				// #endif
			}
		}
	}
</script>

<style lang="scss" scoped>
	$show-border: 1;
	$show-border-surround: 1;
	$show-border-bottom: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-input {
		@include flex(row);
		align-items: center;
		justify-content: space-between;
		flex: 1;
		&--radius,
		&--square {
			border-radius: 4px;
		}
		&--no-radius {
			border-radius: 0;
		}
		&--circle {
			border-radius: 100px;
		}
		&__content {
			flex: 1;
			@include flex(row);
			align-items: center;
			justify-content: space-between;
			&__field-wrapper {
				position: relative;
				@include flex(row);
				margin: 0;
				flex: 1;
				&__field {
					line-height: 26px;
					text-align: left;
					color: $uv-main-color;
					height: 24px;
					font-size: 15px;
					flex: 1;
				}
			}
			&__clear {
				width: 20px;
				height: 20px;
				border-radius: 100px;
				background-color: #c6c7cb;
				@include flex(row);
				align-items: center;
				justify-content: center;
				transform: scale(0.82);
				margin-left: 15px;
			}
			&__subfix-icon {
				margin-left: 4px;
			}
			&__prefix-icon {
				margin-right: 4px;
			}
		}
	}
</style>