<template>
	<view v-if="visibleSync" class="tn-popup-class tn-popup" :style="[customStyle, popupStyle, { zIndex: elZIndex - 1}]"
		hover-stop-propagation>
		<!-- mask -->
		<view class="tn-popup__mask" :class="[{'tn-popup__mask--show': showPopup && mask}]"
			:style="{zIndex: elZIndex - 2}" @tap="maskClick" @touchmove.stop.prevent="() => {}" hover-stop-propagation>
		</view>
		<!-- 弹框内容 -->
		<view class="tn-popup__content" :class="[
        mode !== 'center' ? backgroundColorClass : '',
        safeAreaInsetBottom ? 'tn-safe-area-inset-bottom' : '',
        'tn-popup--' + mode,
        showPopup ? 'tn-popup__content--visible' : '',
        zoom && mode === 'center' ? 'tn-popup__content__center--animation-zoom' : ''
      ]" :style="[contentStyle]" @tap="modeCenterClose" @touchmove.stop.prevent @tap.stop.prevent>
			<!-- 居中时候的内容 -->
			<view v-if="mode === 'center'" class="tn-popup__content__center_box" :class="[backgroundColorClass]"
				:style="[centerStyle]" @touchmove.stop.prevent @tap.stop.prevent>
				<!-- 关闭按钮 -->
				<view v-if="closeBtn" class="tn-popup__close"
					:class="[`tn-icon-${closeBtnIcon}`, `tn-popup__close--${closeBtnPosition}`]"
					:style="[closeBtnStyle, {zIndex: elZIndex}]" @tap="close"></view>
				<scroll-view scroll-y class="tn-popup__content__scroll-view">
					<slot></slot>
				</scroll-view>
			</view>

			<!-- 除居中外的其他情况 -->
			<scroll-view scroll-y v-else class="tn-popup__content__scroll-view">
				<slot></slot>
			</scroll-view>
			<!-- 关闭按钮 -->
			<view v-if="mode !== 'center' && closeBtn" class="tn-popup__close"
				:class="[`tn-popup__close--${closeBtnPosition}`]" :style="{zIndex: elZIndex}" @tap="close">
				<view :class="[`tn-icon-${closeBtnIcon}`]" :style="[closeBtnStyle]"></view>
			</view>
		</view>
	</view>
</template>

<script>
	import componentsColorMixin from '../../libs/mixin/components_color.js'
	export default {
		mixins: [componentsColorMixin],
		name: 'tn-popup',
		props: {
			value: {
				type: Boolean,
				default: false
			},
			// 弹出方向
			// left/right/top/bottom/center
			mode: {
				type: String,
				default: 'left'
			},
			// 是否显示遮罩
			mask: {
				type: Boolean,
				default: true
			},
			// 抽屉的宽度（mode=left/right）,高度（mode=top/bottom）
			length: {
				type: [Number, String],
				default: 'auto'
			},
			// 宽度，只对左，右，中部弹出时起作用，单位rpx，或者"auto"
			// 或者百分比"50%"，表示由内容撑开高度或者宽度，优先级高于length参数
			width: {
				type: String,
				default: ''
			},
			// 高度，只对上，下，中部弹出时起作用，单位rpx，或者"auto"
			// 或者百分比"50%"，表示由内容撑开高度或者宽度，优先级高于length参数
			height: {
				type: String,
				default: ''
			},
			// 是否开启动画，只在mode=center有效
			zoom: {
				type: Boolean,
				default: true
			},
			// 是否开启底部安全区适配，开启的话，会在iPhoneX机型底部添加一定的内边距
			safeAreaInsetBottom: {
				type: Boolean,
				default: false
			},
			// 是否可以通过点击遮罩进行关闭
			maskCloseable: {
				type: Boolean,
				default: true
			},
			// 用户自定义样式
			customStyle: {
				type: Object,
				default () {
					return {}
				}
			},
			// 显示圆角的大小
			borderRadius: {
				type: Number,
				default: 0
			},
			// zIndex
			zIndex: {
				type: Number,
				default: 0
			},
			// 是否显示关闭按钮
			closeBtn: {
				type: Boolean,
				default: false
			},
			// 关闭按钮的图标
			closeBtnIcon: {
				type: String,
				default: 'close'
			},
			// 关闭按钮显示的位置
			// top-left/top-right/bottom-left/bottom-right
			closeBtnPosition: {
				type: String,
				default: 'top-right'
			},
			// 关闭按钮图标颜色
			closeIconColor: {
				type: String,
				default: '#AAAAAA'
			},
			// 关闭按钮图标的大小
			closeIconSize: {
				type: Number,
				default: 30
			},
			// 给一个负的margin-top，往上偏移，避免和键盘重合的情况，仅在mode=center时有效
			negativeTop: {
				type: Number,
				default: 0
			},
			// marginTop，在mode = top,left,right时生效，避免用户使用了自定义导航栏，组件把导航栏遮挡了
			marginTop: {
				type: Number,
				default: 0
			},
			// 此为内部参数，不在文档对外使用，为了解决Picker和keyboard等融合了弹窗的组件
			// 对v-model双向绑定多层调用造成报错不能修改props值的问题
			popup: {
				type: Boolean,
				default: true
			},
		},
		computed: {
			// 处理使用了自定义导航栏时被遮挡的问题
			popupStyle() {
				let style = {}
				if ((this.mode === 'top' || this.mode === 'left' || this.mode === 'right') && this.marginTop) {
					style.marginTop = this.$tn.string.getLengthUnitValue(this.marginTop, 'px')
				}

				return style
			},
			// 根据mode的位置，设定其弹窗的宽度(mode = left|right)，或者高度(mode = top|bottom)
			contentStyle() {
				let style = {}
				// 如果是左边或者上边弹出时，需要给translate设置为负值，用于隐藏
				if (this.mode === 'left' || this.mode === 'right') {
					style = {
						width: this.width ? this.$tn.string.getLengthUnitValue(this.width) : this.$tn.string
							.getLengthUnitValue(this.length),
						height: '100%',
						transform: `translate3D(${this.mode === 'left' ? '-100%' : '100%'}, 0px, 0px)`
					}
				} else if (this.mode === 'top' || this.mode === 'bottom') {
					style = {
						width: '100%',
						height: this.height ? this.$tn.string.getLengthUnitValue(this.height) : this.$tn.string
							.getLengthUnitValue(this.length),
						transform: `translate3D(0px, ${this.mode === 'top' ? '-100%': '100%'}, 0px)`
					}
				}
				style.zIndex = this.elZIndex
				// 如果设置了圆角的值，添加弹窗的圆角
				if (this.borderRadius) {
					switch (this.mode) {
						case 'left':
							style.borderRadius = `0 ${this.borderRadius}rpx ${this.borderRadius}rpx 0`
							break
						case 'top':
							style.borderRadius = `0 0 ${this.borderRadius}rpx ${this.borderRadius}rpx`
							break
						case 'right':
							style.borderRadius = `${this.borderRadius}rpx 0 0 ${this.borderRadius}rpx`
							break
						case 'bottom':
							style.borderRadius = `${this.borderRadius}rpx ${this.borderRadius}rpx 0 0`
							break
					}
					style.overflow = 'hidden'
				}

				if (this.backgroundColorStyle && this.mode !== 'center') {
					style.backgroundColor = this.backgroundColorStyle
				}

				return style
			},
			// 中部弹窗的样式
			centerStyle() {
				let style = {}
				style.width = this.width ? this.$tn.string.getLengthUnitValue(this.width) : this.$tn.string
					.getLengthUnitValue(this.length)
				// 中部弹出的模式，如果没有设置高度，就用auto值，由内容撑开
				style.height = this.height ? this.$tn.string.getLengthUnitValue(this.height) : 'auto'
				style.zIndex = this.elZIndex
				if (this.negativeTop) {
					style.marginTop = `-${this.$tn.string.getLengthUnitValue(this.negativeTop)}`
				}
				if (this.borderRadius) {
					style.borderRadius = `${this.borderRadius}rpx`
					style.overflow = 'hidden'
				}
				if (this.backgroundColorStyle) {
					style.backgroundColor = this.backgroundColorStyle
				}
				return style
			},
			// 关闭按钮样式
			closeBtnStyle() {
				let style = {}
				if (this.closeIconColor) {
					style.color = this.closeIconColor
				}
				if (this.closeIconSize) {
					style.fontSize = this.closeIconSize + 'rpx'
				}

				return style
			},
			elZIndex() {
				return this.zIndex ? this.zIndex : this.$tn.zIndex.popup
			}
		},
		data() {
			return {
				timer: null,
				visibleSync: false,
				showPopup: false,
				closeFromInner: false
			}
		},
		watch: {
			value(val) {
				if (val) {
					// console.log(this.visibleSync);
					if (this.visibleSync) {
						this.visibleSync = false
						return
					}
					this.open()
				} else if (!this.closeFromInner) {
					this.close()
				}
				this.closeFromInner = false
			}
		},
		mounted() {
			// 组件渲染完成时，检查value是否为true，如果是，弹出popup
			this.value && this.open()
		},
		methods: {
			// 点击遮罩
			maskClick() {
				if (!this.maskCloseable) return
				this.close()
			},
			open() {
				this.change('visibleSync', 'showPopup', true)
			},
			// 关闭弹框
			close() {
				// 标记关闭是内部发生的，否则修改了value值，导致watch中对value检测，导致再执行一遍close
				// 造成@close事件触发两次
				this.closeFromInner = true
				this.change('showPopup', 'visibleSync', false)
			},
			// 中部弹出时，需要.tn-drawer-content将内容居中，此元素会铺满屏幕，点击需要关闭弹窗
			// 让其只在mode=center时起作用 
			modeCenterClose() {
				if (this.mode != 'center' || !this.maskCloseable) return
				this.close()
			},
			// 关闭时先通过动画隐藏弹窗和遮罩，再移除整个组件
			// 打开时，先渲染组件，延时一定时间再让遮罩和弹窗的动画起作用
			change(param1, param2, status) {
				// 如果this.popup为false，意味着为picker，actionsheet等组件调用了popup组件
				if (this.popup === true) {
					this.$emit('input', status)
				}
				this[param1] = status
				if (status) {
					// #ifdef H5 || MP
					this.timer = setTimeout(() => {
						this[param2] = status
						this.$emit(status ? 'open' : 'close')
						clearTimeout(this.timer)
					}, 10)
					// #endif
					// #ifndef H5 || MP
					this.$nextTick(() => {
						this[param2] = status
						this.$emit(status ? 'open' : 'close')
					})
					// #endif
				} else {
					this.timer = setTimeout(() => {
						this[param2] = status
						this.$emit(status ? 'open' : 'close')
						clearTimeout(this.timer)
					}, 250)
				}
			}
		}
	}
</script>

<style lang="scss" scoped>
	.tn-popup {
		/* #ifndef APP-NVUE */
		display: block;
		/* #endif */
		position: fixed;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		overflow: hidden;
		z-index: 29091 !important;

		&__content {
			/* #ifndef APP-NVUE */
			display: block;
			/* #endif */
			position: absolute;
			transition: all 0.25s linear;

			&--visible {
				transform: translate3D(0px, 0px, 0px) !important;

				&.tn-popup--center {
					transform: scale(1);
					opacity: 1;
				}
			}

			&__center_box {
				min-width: 100rpx;
				min-height: 100rpx;
				/* #ifndef APP-NVUE */
				display: block;
				/* #endif */
				position: relative;
				background-color: #FFFFFF;
			}

			&__scroll-view {
				width: 100%;
				height: 100%;
			}

			&__center--animation-zoom {
				transform: scale(1.15);
			}
		}

		&__scroll_view {
			width: 100%;
			height: 100%;
		}

		&--left {
			top: 0;
			bottom: 0;
			left: 0;
			background-color: #FFFFFF;
		}

		&--right {
			top: 0;
			bottom: 0;
			right: 0;
			background-color: #FFFFFF;
		}

		&--top {
			left: 0;
			right: 0;
			top: 0;
		}

		&--bottom {
			left: 0;
			right: 0;
			bottom: 0;
			background-color: #FFFFFF;
		}

		&--center {
			display: flex;
			flex-direction: column;
			bottom: 0;
			top: 0;
			left: 0;
			right: 0;
			justify-content: center;
			align-items: center;
			opacity: 0;
		}

		&__close {
			position: absolute;

			&--top-left {
				top: 30rpx;
				left: 30rpx;
			}

			&--top-right {
				top: 30rpx;
				right: 30rpx;
			}

			&--bottom-left {
				bottom: 30rpx;
				left: 30rpx;
			}

			&--bottom-right {
				bottom: 30rpx;
				right: 30rpx;
			}
		}

		&__mask {
			width: 100%;
			height: 100%;
			position: fixed;
			top: 0;
			left: 0;
			right: 0;
			border: 0;
			background-color: $tn-mask-bg-color;
			transition: 0.25s linear;
			transition-property: opacity;
			opacity: 0;

			&--show {
				opacity: 1;
			}
		}
	}
</style>