import { isDef, isUndef } from 'shared/util'
import { updateListeners } from 'core/vdom/helpers/index'
import { isIE, isFF, supportsPassive, isUsingMicroTask } from 'core/util/index'
import {
RANGE_TOKEN,
CHECKBOX_RADIO_TOKEN
} from 'web/compiler/directives/model'
import { currentFlushTimestamp } from 'core/observer/scheduler'
import { emptyNode } from 'core/vdom/patch'
import type { VNodeWithData } from 'types/vnode'
function normalizeEvents(on) {
if (isDef(on[RANGE_TOKEN])) {
const event = isIE ? 'change' : 'input'
on[event] = [].concat(on[RANGE_TOKEN], on[event] || [])
delete on[RANGE_TOKEN]
}
if (isDef(on[CHECKBOX_RADIO_TOKEN])) {
on.change = [].concat(on[CHECKBOX_RADIO_TOKEN], on.change || [])
delete on[CHECKBOX_RADIO_TOKEN]
}
}
let target: any
function createOnceHandler(event, handler, capture) {
const _target = target
return function onceHandler() {
const res = handler.apply(null, arguments)
if (res !== null) {
remove(event, onceHandler, capture, _target)
}
}
}
const useMicrotaskFix = isUsingMicroTask && !(isFF && Number(isFF[1]) <= 53)
function add(
name: string,
handler: Function,
capture: boolean,
passive: boolean
) {
if (useMicrotaskFix) {
const attachedTimestamp = currentFlushTimestamp
const original = handler
handler = original._wrapper = function (e) {
if (
e.target === e.currentTarget ||
e.timeStamp >= attachedTimestamp ||
e.timeStamp <= 0 ||
e.target.ownerDocument !== document
) {
return original.apply(this, arguments)
}
}
}
target.addEventListener(
name,
handler,
supportsPassive ? { capture, passive } : capture
)
}
function remove(
name: string,
handler: Function,
capture: boolean,
_target?: HTMLElement
) {
;(_target || target).removeEventListener(
name,
handler._wrapper || handler,
capture
)
}
function updateDOMListeners(oldVnode: VNodeWithData, vnode: VNodeWithData) {
if (isUndef(oldVnode.data.on) && isUndef(vnode.data.on)) {
return
}
const on = vnode.data.on || {}
const oldOn = oldVnode.data.on || {}
target = vnode.elm || oldVnode.elm
normalizeEvents(on)
updateListeners(on, oldOn, add, remove, createOnceHandler, vnode.context)
target = undefined
}
export default {
create: updateDOMListeners,
update: updateDOMListeners,
destroy: (vnode: VNodeWithData) => updateDOMListeners(vnode, emptyNode)
}