<template>
	<view v-if="showPopup" class="uni-popup" :class="[popupstyle, isDesktop ? 'fixforpc-z-index' : '']" @touchmove.stop.prevent="clear">
		<view @touchstart="touchstart" >
			<uni-transition key="1" v-if="maskShow" name="mask" mode-class="fade" :styles="maskClass" :duration="duration" :show="showTrans" @click="onTap" />
			<uni-transition key="2" :mode-class="ani" name="content" :styles="transClass" :duration="duration" :show="showTrans" @click="onTap">
				<view class="uni-popup__wrapper" :style="{ backgroundColor: bg }" :class="[popupstyle]" @click="clear"><slot /></view>
			</uni-transition>
		</view>
		<!-- #ifdef H5 -->
		<keypress v-if="maskShow" @esc="onTap" />
		<!-- #endif -->
	</view>
</template>

<script>
// #ifdef H5
import keypress from './keypress.js'
// #endif

/**
 * PopUp 弹出层
 * @description 弹出层组件，为了解决遮罩弹层的问题
 * @tutorial https://ext.dcloud.net.cn/plugin?id=329
 * @property {String} type = [top|center|bottom|left|right|message|dialog|share] 弹出方式
 * 	@value top 顶部弹出
 * 	@value center 中间弹出
 * 	@value bottom 底部弹出
 * 	@value left		左侧弹出
 * 	@value right  右侧弹出
 * 	@value message 消息提示
 * 	@value dialog 对话框
 * 	@value share 底部分享示例
 * @property {Boolean} animation = [ture|false] 是否开启动画
 * @property {Boolean} maskClick = [ture|false] 蒙版点击是否关闭弹窗
 * @property {String}  backgroundColor 					主窗口背景色
 * @property {Boolean} safeArea									是否适配底部安全区
 * @event {Function} change 打开关闭弹窗触发，e={show: false}
 * @event {Function} maskClick 点击遮罩触发
 */

export default {
	name: 'uniPopup',
	components: {
		// #ifdef H5
		keypress
		// #endif
	},
	emits:['change','maskClick'],
	props: {
		// 开启动画
		animation: {
			type: Boolean,
			default: true
		},
		// 弹出层类型，可选值，top: 顶部弹出层；bottom：底部弹出层；center：全屏弹出层
		// message: 消息提示 ; dialog : 对话框
		type: {
			type: String,
			default: 'center'
		},
		// maskClick
		maskClick: {
			type: Boolean,
			default: true
		},
		backgroundColor: {
			type: String,
			default: 'none'
		},
		safeArea:{
			type: Boolean,
			default: true
		}
	},

	watch: {
		/**
		 * 监听type类型
		 */
		type: {
			handler: function(type) {
				if (!this.config[type]) return
				this[this.config[type]](true)
			},
			immediate: true
		},
		isDesktop: {
			handler: function(newVal) {
				if (!this.config[newVal]) return
				this[this.config[this.type]](true)
			},
			immediate: true
		},
		/**
		 * 监听遮罩是否可点击
		 * @param {Object} val
		 */
		maskClick: {
			handler: function(val) {
				this.mkclick = val
			},
			immediate: true
		}
	},
	data() {
		return {
			duration: 300,
			ani: [],
			showPopup: false,
			showTrans: false,
			popupWidth: 0,
			popupHeight: 0,
			config: {
				top: 'top',
				bottom: 'bottom',
				center: 'center',
				left: 'left',
				right: 'right',
				message: 'top',
				dialog: 'center',
				share: 'bottom'
			},
			maskClass: {
				position: 'fixed',
				bottom: 0,
				top: 0,
				left: 0,
				right: 0,
				backgroundColor: 'rgba(0, 0, 0, 0.4)'
			},
			transClass: {
				position: 'fixed',
				left: 0,
				right: 0
			},
			maskShow: true,
			mkclick: true,
			popupstyle: this.isDesktop ? 'fixforpc-top' : 'top'
		}
	},
	computed: {
		isDesktop() {
			return this.popupWidth >= 500 && this.popupHeight >= 500
		},
		bg() {
			if (this.backgroundColor === '' || this.backgroundColor === 'none') {
				return 'transparent'
			}
			return this.backgroundColor
		}
	},
	mounted() {
		const fixSize = () => {
			const { windowWidth, windowHeight, windowTop, safeAreaInsets } = uni.getSystemInfoSync()
			this.popupWidth = windowWidth
			this.popupHeight = windowHeight + windowTop
			// 是否适配底部安全区
			if(this.safeArea){
				this.safeAreaInsets = safeAreaInsets
			}else{
				this.safeAreaInsets = 0
			}
		}
		fixSize()
		// #ifdef H5
		// window.addEventListener('resize', fixSize)
		// this.$once('hook:beforeDestroy', () => {
		// 	window.removeEventListener('resize', fixSize)
		// })
		// #endif
	},
	created() {
		this.mkclick = this.maskClick
		if (this.animation) {
			this.duration = 300
		} else {
			this.duration = 0
		}
		// TODO 处理 message 组件生命周期异常的问题
		this.messageChild = null
		// TODO 解决头条冒泡的问题
		this.clearPropagation = false
	},
	methods: {
		/**
		 * 公用方法，不显示遮罩层
		 */
		closeMask() {
			this.maskShow = false
		},
		/**
		 * 公用方法，遮罩层禁止点击
		 */
		disableMask() {
			this.mkclick = false
		},
		// TODO nvue 取消冒泡
		clear(e) {
			// #ifndef APP-NVUE
			e.stopPropagation()
			// #endif
			this.clearPropagation = true
		},

		open(direction) {
			let innerType = ['top', 'center', 'bottom', 'left', 'right', 'message', 'dialog', 'share']
			if (!(direction && innerType.indexOf(direction) !== -1)) {
				direction = this.type
			}
			if (!this.config[direction]) {
				console.error('缺少类型：', direction)
				return
			}
			this[this.config[direction]]()
			this.$emit('change', {
				show: true,
				type: direction
			})
		},
		close(type) {
			this.showTrans = false
			this.$emit('change', {
				show: false,
				type: this.type
			})
			clearTimeout(this.timer)
			// // 自定义关闭事件
			// this.customOpen && this.customClose()
			this.timer = setTimeout(() => {
				this.showPopup = false
			}, 300)
		},
		// TODO 处理冒泡事件，头条的冒泡事件有问题 ，先这样兼容
		touchstart(){
			this.clearPropagation = false
		},

		onTap() {
			if (this.clearPropagation) {
				// fix by mehaotian 兼容 nvue
				this.clearPropagation = false
				return
			}
			this.$emit('maskClick')
			if (!this.mkclick) return
			this.close()
		},
		/**
		 * 顶部弹出样式处理
		 */
		top(type) {
			this.popupstyle = this.isDesktop ? 'fixforpc-top' : 'top'
			this.ani = ['slide-top']
			this.transClass = {
				position: 'fixed',
				left: 0,
				right: 0,
				backgroundColor: this.bg
			}
			// TODO 兼容 type 属性 ，后续会废弃
			if (type) return
			this.showPopup = true
			this.showTrans = true
			this.$nextTick(() => {
				if (this.messageChild && this.type === 'message') {
					this.messageChild.timerClose()
				}
			})
		},
		/**
		 * 底部弹出样式处理
		 */
		bottom(type) {
			this.popupstyle = 'bottom'
			this.ani = ['slide-bottom']

			this.transClass = {
				position: 'fixed',
				left: 0,
				right: 0,
				bottom: 0,
				paddingBottom: (this.safeAreaInsets && this.safeAreaInsets.bottom) || 0,
				backgroundColor: this.bg
			}
			// TODO 兼容 type 属性 ，后续会废弃
			if (type) return
			this.showPopup = true
			this.showTrans = true
		},
		/**
		 * 中间弹出样式处理
		 */
		center(type) {
			this.popupstyle = 'center'
			this.ani = ['zoom-out', 'fade']
			this.transClass = {
				position: 'fixed',
				/* #ifndef APP-NVUE */
				display: 'flex',
				flexDirection: 'column',
				/* #endif */
				bottom: 0,
				left: 0,
				right: 0,
				top: 0,
				justifyContent: 'center',
				alignItems: 'center'
			}
			// TODO 兼容 type 属性 ，后续会废弃
			if (type) return
			this.showPopup = true
			this.showTrans = true
		},
		left(type) {
			this.popupstyle = 'left'
			this.ani = ['slide-left']
			this.transClass = {
				position: 'fixed',
				left: 0,
				bottom: 0,
				top: 0,
				backgroundColor: this.bg,
				/* #ifndef APP-NVUE */
				display: 'flex',
				flexDirection: 'column'
				/* #endif */
			}
			// TODO 兼容 type 属性 ，后续会废弃
			if (type) return
			this.showPopup = true
			this.showTrans = true
		},
		right(type) {
			this.popupstyle = 'right'
			this.ani = ['slide-right']
			this.transClass = {
				position: 'fixed',
				bottom: 0,
				right: 0,
				top: 0,
				backgroundColor: this.bg,
				/* #ifndef APP-NVUE */
				display: 'flex',
				flexDirection: 'column'
				/* #endif */
			}
			// TODO 兼容 type 属性 ，后续会废弃
			if (type) return
			this.showPopup = true
			this.showTrans = true
		}
	}
}
</script>
<style lang="scss" scoped>
.uni-popup {
	position: fixed;
	/* #ifndef APP-NVUE */
	z-index: 99;
	/* #endif */
	&.top,
	&.left,
	&.right {
		/* #ifdef H5 */
		top: var(--window-top);
		/* #endif */
		/* #ifndef H5 */
		top: 0;
		/* #endif */
	}
	.uni-popup__wrapper {
		/* #ifndef APP-NVUE */
		display: block;
		/* #endif */
		position: relative;
		/* iphonex 等安全区设置，底部安全区适配 */
		/* #ifndef APP-NVUE */
		// padding-bottom: constant(safe-area-inset-bottom);
		// padding-bottom: env(safe-area-inset-bottom);
		/* #endif */
		&.left,
		&.right {
			/* #ifdef H5 */
			padding-top: var(--window-top);
			/* #endif */
			/* #ifndef H5 */
			padding-top: 0;
			/* #endif */
			flex: 1;
		}
	}
}

.fixforpc-z-index {
	/* #ifndef APP-NVUE */
	z-index: 999;
	/* #endif */
}

.fixforpc-top {
	top: 0;
}
</style>
