// Context import { context } from './context'; import { openOverlay, closeOverlay, updateOverlay, removeOverlay } from './overlay'; // Utils import { on, off, preventDefault } from '../../utils/dom/event'; import { removeNode } from '../../utils/dom/node'; import { getScroller } from '../../utils/dom/scroll'; // Mixins import { TouchMixin } from '../touch'; import { PortalMixin } from '../portal'; import { CloseOnPopstateMixin } from '../close-on-popstate'; export var popupMixinProps = { // Initial rendering animation transitionAppear: Boolean, // whether to show popup value: Boolean, // whether to show overlay overlay: Boolean, // overlay custom style overlayStyle: Object, // overlay custom class name overlayClass: String, // whether to close popup when overlay is clicked closeOnClickOverlay: Boolean, // z-index zIndex: [Number, String], // prevent body scroll lockScroll: { type: Boolean, default: true }, // whether to lazy render lazyRender: { type: Boolean, default: true } }; export function PopupMixin(options) { if (options === void 0) { options = {}; } return { mixins: [TouchMixin, CloseOnPopstateMixin, PortalMixin({ afterPortal: function afterPortal() { if (this.overlay) { updateOverlay(); } } })], provide: function provide() { return { vanPopup: this }; }, props: popupMixinProps, data: function data() { this.onReopenCallback = []; return { inited: this.value }; }, computed: { shouldRender: function shouldRender() { return this.inited || !this.lazyRender; } }, watch: { value: function value(val) { var type = val ? 'open' : 'close'; this.inited = this.inited || this.value; this[type](); if (!options.skipToggleEvent) { this.$emit(type); } }, overlay: 'renderOverlay' }, mounted: function mounted() { if (this.value) { this.open(); } }, /* istanbul ignore next */ activated: function activated() { if (this.shouldReopen) { this.$emit('input', true); this.shouldReopen = false; } }, beforeDestroy: function beforeDestroy() { removeOverlay(this); if (this.opened) { this.removeLock(); } if (this.getContainer) { removeNode(this.$el); } }, /* istanbul ignore next */ deactivated: function deactivated() { if (this.value) { this.close(); this.shouldReopen = true; } }, methods: { open: function open() { /* istanbul ignore next */ if (this.$isServer || this.opened) { return; } // cover default zIndex if (this.zIndex !== undefined) { context.zIndex = this.zIndex; } this.opened = true; this.renderOverlay(); this.addLock(); this.onReopenCallback.forEach(function (callback) { callback(); }); }, addLock: function addLock() { if (this.lockScroll) { on(document, 'touchstart', this.touchStart); on(document, 'touchmove', this.onTouchMove); if (!context.lockCount) { document.body.classList.add('van-overflow-hidden'); } context.lockCount++; } }, removeLock: function removeLock() { if (this.lockScroll && context.lockCount) { context.lockCount--; off(document, 'touchstart', this.touchStart); off(document, 'touchmove', this.onTouchMove); if (!context.lockCount) { document.body.classList.remove('van-overflow-hidden'); } } }, close: function close() { if (!this.opened) { return; } closeOverlay(this); this.opened = false; this.removeLock(); this.$emit('input', false); }, onTouchMove: function onTouchMove(event) { this.touchMove(event); var direction = this.deltaY > 0 ? '10' : '01'; var el = getScroller(event.target, this.$el); var scrollHeight = el.scrollHeight, offsetHeight = el.offsetHeight, scrollTop = el.scrollTop; var status = '11'; /* istanbul ignore next */ if (scrollTop === 0) { status = offsetHeight >= scrollHeight ? '00' : '01'; } else if (scrollTop + offsetHeight >= scrollHeight) { status = '10'; } /* istanbul ignore next */ if (status !== '11' && this.direction === 'vertical' && !(parseInt(status, 2) & parseInt(direction, 2))) { preventDefault(event, true); } }, renderOverlay: function renderOverlay() { var _this = this; if (this.$isServer || !this.value) { return; } this.$nextTick(function () { _this.updateZIndex(_this.overlay ? 1 : 0); if (_this.overlay) { openOverlay(_this, { zIndex: context.zIndex++, duration: _this.duration, className: _this.overlayClass, customStyle: _this.overlayStyle }); } else { closeOverlay(_this); } }); }, updateZIndex: function updateZIndex(value) { if (value === void 0) { value = 0; } this.$el.style.zIndex = ++context.zIndex + value; }, onReopen: function onReopen(callback) { this.onReopenCallback.push(callback); } } }; }