import PropTypes from '../_util/vue-types' import align from 'dom-align' import addEventListener from '../_util/Dom/addEventListener' import { cloneElement } from '../_util/vnode.js' import isWindow from './isWindow' import clonedeep from 'lodash/cloneDeep' import shallowequal from 'shallowequal' function noop () { } function buffer (fn, ms) { let timer function clear () { if (timer) { clearTimeout(timer) timer = null } } function bufferFn () { clear() timer = setTimeout(fn, ms) } bufferFn.clear = clear return bufferFn } export default { props: { childrenProps: PropTypes.object, align: PropTypes.object.isRequired, target: PropTypes.func.def(noop), monitorBufferTime: PropTypes.number.def(50), monitorWindowResize: PropTypes.bool.def(false), disabled: PropTypes.bool.def(false), visible: PropTypes.bool.def(false), }, data () { this.aligned = false return { } }, mounted () { this.$nextTick(() => { this.prevProps = { ...this.$props } const props = this.$props // if parent ref not attached .... use document.getElementById !this.aligned && this.forceAlign() if (!props.disabled && props.monitorWindowResize) { this.startMonitorWindowResize() } }) }, updated () { this.$nextTick(() => { const prevProps = this.prevProps const props = this.$props let reAlign = false if (!props.disabled && this.visible) { if (prevProps.disabled || !shallowequal(prevProps.align, props.align)) { reAlign = true } else { const lastTarget = prevProps.target() const currentTarget = props.target() if (isWindow(lastTarget) && isWindow(currentTarget)) { reAlign = false } else if (lastTarget !== currentTarget) { reAlign = true } } } if (reAlign) { this.forceAlign() } if (props.monitorWindowResize && !props.disabled) { this.startMonitorWindowResize() } else { this.stopMonitorWindowResize() } this.prevProps = { ...this.$props, align: clonedeep(this.$props.align) } }) }, beforeDestroy () { this.stopMonitorWindowResize() }, methods: { startMonitorWindowResize () { if (!this.resizeHandler) { this.bufferMonitor = buffer(this.forceAlign, this.$props.monitorBufferTime) this.resizeHandler = addEventListener(window, 'resize', this.bufferMonitor) } }, stopMonitorWindowResize () { if (this.resizeHandler) { this.bufferMonitor.clear() this.resizeHandler.remove() this.resizeHandler = null } }, forceAlign () { const props = this.$props if (!props.disabled) { const source = this.$el this.aligned = true this.$listeners.align && this.$listeners.align(source, align(source, props.target(), props.align)) } }, }, render () { const { childrenProps } = this.$props const child = this.$slots.default[0] if (childrenProps) { return cloneElement(child, { props: childrenProps }) } return child }, }