const isTouch = typeof window !== 'undefined' && ('ontouchstart' in window || navigator.msMaxTouchPoints > 0) const events = isTouch ? ['touchstart', 'click'] : ['click'] const instances = [] function processArgs(bindingValue) { const isFunction = typeof bindingValue === 'function' if (!isFunction && typeof bindingValue !== 'object') { throw new Error(`v-click-outside: Binding value should be a function or an object, ${typeof bindingValue} given`) } return { handler: isFunction ? bindingValue : bindingValue.handler, middleware: bindingValue.middleware || ((isClickOutside) => isClickOutside), events: bindingValue.events || events } } function onEvent({ el, event, handler, middleware }) { const isClickOutside = event.target !== el && !el.contains(event.target) if (!isClickOutside || !middleware(event, el)) { return } handler(event, el) } function toggleEventListeners({ eventHandlers = [] } = {}, action = 'add') { eventHandlers.forEach(({ event, handler }) => { document[`${action}EventListener`](event, handler) }) } function bind(el, { value }) { const { handler, middleware, events } = processArgs(value) const instance = { el, eventHandlers: events.map((eventName) => ({ event: eventName, handler: (event) => onEvent({ event, el, handler, middleware }) })) } toggleEventListeners(instance, 'add') instances.push(instance) } function update(el, { value }) { const { handler, middleware, events } = processArgs(value) // `filter` instead of `find` for compat with IE const instance = instances.filter((instance) => instance.el === el)[0] toggleEventListeners(instance, 'remove') instance.eventHandlers = events.map((eventName) => ({ event: eventName, handler: (event) => onEvent({ event, el, handler, middleware }) })) toggleEventListeners(instance, 'add') } function unbind(el) { // `filter` instead of `find` for compat with IE const instance = instances.filter((instance) => instance.el === el)[0] toggleEventListeners(instance, 'remove') } const directive = { beforeMount: bind, beforeUpdate: update, beforeUnmount: unbind, instances } export default directive