<template>
	<transition name="contextmenu-submenu-fade">
		<div
			:class="['menu', customClass, commonClass.menu]"
			:style="{left: style.left + 'px', top: style.top + 'px', minWidth: style.minWidth + 'px', zIndex: style.zIndex}"
			@contextmenu.prevent
			ref="menu"
			v-if="visible"
		>
			<div class="menu_body">
				<div
					:class="[
                        commonClass.menuItem,
                        (item.disabled ||  item.children) ? commonClass.unClickableMenuItem : commonClass.clickableMenuItem,
                        (item.children && activeSubmenu.index === index) ? 'menu_item_expand' : null,
                        item.divided ? 'menu_item__divided' : null,
                        item.disabled ? 'menu_item__disabled' :  'menu_item__available',

                    ]"
					:key="item.label"
					@click="(!item.disabled && ! item.children) && itemClick(item)"
					@mouseenter="!item.disabled && enterItem($event,item,index)"
					class="menu_item"
					v-for="(item,index) of itemsShow"
				>
					<div class="menu_item_icon" v-if="hasIcon">
						<i :class="item.icon" v-if="item.icon"></i>
					</div>
					<span class="menu_item_label">{{item.label}}</span>
					<div class="menu_item_expand_icon">{{ item.children ? '▶' : '' }}</div>
				</div>
			</div>
		</div>
	</transition>
</template>

<script>
import Vue from 'vue';
import {
	SUBMENU_X_OFFSET,
	SUBMENU_Y_OFFSET,
	SUBMENU_OPEN_TREND_LEFT,
	SUBMENU_OPEN_TREND_RIGHT,
	COMPONENT_NAME,
} from '../constant';
export default {
	name: COMPONENT_NAME,
	mounted() {
		const windowWidth = document.documentElement.clientWidth;
		const windowHeight = document.documentElement.clientHeight;
		const menu = this.$refs.menu;
		const menuWidth = menu.offsetWidth;
		const menuHeight = menu.offsetHeight;

		(this.openTrend === SUBMENU_OPEN_TREND_LEFT ? this.leftOpen : this.rightOpen)(
			windowWidth,
			windowHeight,
			menuWidth,
		);

		this.style.top = this.position.y;
		if (this.position.y + menuHeight > windowHeight) {
			if (this.position.height === 0) {
				this.style.top = this.position.y - menuHeight;
			} else {
				this.style.top = windowHeight - menuHeight;
			}
			if (this.style.top < 0) {
				this.style.top = 0;
			}
		}
	},
	data: () => ({
		commonClass: {
			menu: null,
			menuItem: null,
			clickableMenuItem: null,
			unClickableMenuItem: null,
		},
		activeSubmenu: {
			index: null,
			instance: null,
		},
		items: [],
		position: {
			x: 0,
			y: 0,
			width: 0,
			height: 0,
		},
		style: {
			left: 0,
			top: 0,
			zIndex: 2,
			minWidth: 150,
		},
		customClass: null,
		visible: true, // 默认打开
		openTrend: SUBMENU_OPEN_TREND_RIGHT,
	}),
	computed: {
		hasIcon() {
			return this.itemsShow.some(v => v.icon);
		},
		itemsShow() {
			return this.items.filter(v => !v.hidden);
		},
	},
	methods: {
		leftOpen(windowWidth, windowHeight, menuWidth) {
			this.style.left = this.position.x - menuWidth;
			this.openTrend = SUBMENU_OPEN_TREND_LEFT;
			if (this.style.left < 0) {
				this.openTrend = SUBMENU_OPEN_TREND_RIGHT;
				if (this.position.width === 0) {
					this.style.left = 0;
				} else {
					this.style.left = this.position.x + this.position.width;
				}
			}
		},
		rightOpen(windowWidth, windowHeight, menuWidth) {
			this.style.left = this.position.x + this.position.width;
			this.openTrend = SUBMENU_OPEN_TREND_RIGHT;
			if (this.style.left + menuWidth > windowWidth) {
				this.openTrend = SUBMENU_OPEN_TREND_LEFT;
				if (this.position.width === 0) {
					this.style.left = windowWidth - menuWidth;
				} else {
					this.style.left = this.position.x - menuWidth;
				}
			}
		},
		enterItem(e, item, index) {
			if (!this.visible) {
				return;
			}
			if (this.activeSubmenu.instance) {
				if (this.activeSubmenu.index === index) {
					return;
				} else {
					this.activeSubmenu.instance.close();
					this.activeSubmenu.instance = null;
					this.activeSubmenu.index = null;
				}
			}
			if (!item.children) {
				return;
			}
			const menuItemClientRect = e.target.getBoundingClientRect();
			const SubmenuConstructor = Vue.component(COMPONENT_NAME);
			this.activeSubmenu.index = index;
			this.activeSubmenu.instance = new SubmenuConstructor();
			this.activeSubmenu.instance.items = item.children;
			this.activeSubmenu.instance.openTrend = this.openTrend;
			this.activeSubmenu.instance.commonClass = this.commonClass;
			this.activeSubmenu.instance.position = {
				x: menuItemClientRect.x + SUBMENU_X_OFFSET,
				y: menuItemClientRect.y + SUBMENU_Y_OFFSET,
				width: menuItemClientRect.width - 2 * SUBMENU_X_OFFSET,
				height: menuItemClientRect.width,
			};
			this.activeSubmenu.instance.style.minWidth =
				typeof item.minWidth === 'number' ? item.minWidth : this.style.minWidth;
			this.activeSubmenu.instance.style.zIndex = this.style.zIndex;
			this.activeSubmenu.instance.customClass =
				typeof item.customClass === 'string' ? item.customClass : this.customClass;
			this.activeSubmenu.instance.$mount();
			document.body.appendChild(this.activeSubmenu.instance.$el);
		},
		itemClick(item) {
			if (!this.visible) {
				return;
			}
			if (item && !item.disabled && !item.hidden && typeof item.onClick === 'function') {
				item.onClick();
				return;
			}
		},
		close() {
			if (this.activeSubmenu.instance) {
				this.activeSubmenu.instance.close();
				this.activeSubmenu.instance = null;
				this.activeSubmenu.index = null;
			}
			this.visible = false;
			this.$destroy();
			if (this.$el.parentNode) {
				this.$el.parentNode.removeChild(this.$el);
			}
		},
	},
};
</script>

<style scoped>
.menu {
	position: fixed;
	box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
	background: #fff;
	border-radius: 4px;
	padding: 8px 0;
}
.menu_body {
	display: block;
}
.menu_item {
	list-style: none;
	line-height: 32px;
	padding: 0 16px;
	margin: 0;
	font-size: 13px;
	outline: 0;
	display: flex;
	align-items: center;
	transition: 0.2s;
	border-bottom: 1px solid #00000000;
}
.menu_item__divided {
	border-bottom-color: #ebeef5;
}
.menu_item .menu_item_icon {
	margin-right: 8px;
	width: 13px;
}
.menu_item .menu_item_label {
	flex: 1;
}
.menu_item .menu_item_expand_icon {
	margin-left: 16px;
	font-size: 6px;
	width: 10px;
}
.menu_item__available {
	color: #606266;
	cursor: pointer;
}
.menu_item__available:hover {
	background: #ecf5ff;
	color: #409eff;
}
.menu_item__disabled {
	color: #c0c4cc;
	cursor: not-allowed;
}
.menu_item_expand {
	background: #ecf5ff;
	color: #409eff;
}
</style>

<style>
.contextmenu-submenu-fade-enter-active,
.contextmenu-submenu-fade-leave-active {
	transition: opacity 0.1s;
}
.contextmenu-submenu-fade-enter,
.contextmenu-submenu-fade-leave-to {
	opacity: 0;
}
</style>