All files / runtime/src/modules events.ts

100% Statements 84/84
100% Branches 13/13
100% Functions 6/6
100% Lines 84/84

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 851x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 12x 12x 12x 12x 12x 12x 12x 12x 1x 2x 2x 2x 2x 2x 2x 2x 2x 1x 11x 11x 11x 11x 11x 11x 11x 11x 11x 11x 11x 2x 2x 11x 9x 9x 7x 7x 7x 9x 2x 2x 2x 2x 9x 11x 1x 1x 1x 9x 9x 9x 4x 4x 4x 4x 4x 4x 4x 4x 9x 9x 1x 7x 7x 7x 7x 7x 9x 9x 7x 7x 7x  
import { hyphenate } from '@vue/shared'
import { INSVElement } from '../nodes'
import {
  callWithAsyncErrorHandling,
  ComponentInternalInstance
} from '@vue/runtime-core'
 
interface Invoker extends EventListener {
  value: EventValue
}
 
type EventValue = Function | Function[]
 
export function addEventListener(
  el: INSVElement,
  event: string,
  handler: EventListener,
  options: EventListenerOptions = {}
) {
  el.addEventListener(event, handler, options)
}
 
export function removeEventListener(
  el: INSVElement,
  event: string,
  handler: EventListener,
  options: EventListenerOptions = {}
) {
  el.removeEventListener(event, handler)
}
 
export function patchEvent(
  el: INSVElement & { _vei?: Record<string, Invoker | undefined> },
  rawName: string,
  prevValue: EventValue | null,
  nextValue: EventValue | null,
  instance: ComponentInternalInstance | null = null
) {
  // vei = vue event invokers
  const invokers = el._vei || (el._vei = {})
  const existingInvoker = invokers[rawName]
  if (nextValue && existingInvoker) {
    // patch
    existingInvoker.value = nextValue
  } else {
    const [name, options] = parseName(rawName)
    if (nextValue) {
      // add
      const invoker = (invokers[rawName] = createInvoker(nextValue, instance))
      addEventListener(el, name, invoker, options)
    } else if (existingInvoker) {
      // remove
      removeEventListener(el, name, existingInvoker, options)
      invokers[rawName] = undefined
    }
  }
}
 
const optionsModifierRE = /(?:Once|Capture)$/
 
function parseName(name: string): [string, EventListenerOptions | undefined] {
  let options: EventListenerOptions | undefined
  if (optionsModifierRE.test(name)) {
    options = {}
    let m
    while ((m = name.match(optionsModifierRE))) {
      name = name.slice(0, name.length - m[0].length)
      ;(options as any)[m[0].toLowerCase()] = true
      options
    }
  }
  return [hyphenate(name.slice(2)), options]
}
 
function createInvoker(
  initialValue: EventValue,
  instance: ComponentInternalInstance | null
) {
  const invoker: Invoker = (e: Event) => {
    callWithAsyncErrorHandling(invoker.value, instance, 5, [e])
  }
  invoker.value = initialValue
  return invoker
}