events.js 2.6 KB
import { HAS_PASSIVE_EVENT_SUPPORT } from '../constants/env'
import { ROOT_EVENT_NAME_PREFIX, ROOT_EVENT_NAME_SEPARATOR } from '../constants/events'
import { RX_BV_PREFIX } from '../constants/regex'
import { isObject } from './inspect'
import { kebabCase } from './string'

// --- Utils ---

// Normalize event options based on support of passive option
// Exported only for testing purposes
export const parseEventOptions = options => {
  /* istanbul ignore else: can't test in JSDOM, as it supports passive */
  if (HAS_PASSIVE_EVENT_SUPPORT) {
    return isObject(options) ? options : { capture: !!options || false }
  } else {
    // Need to translate to actual Boolean value
    return !!(isObject(options) ? options.capture : options)
  }
}

// Attach an event listener to an element
export const eventOn = (el, eventName, handler, options) => {
  if (el && el.addEventListener) {
    el.addEventListener(eventName, handler, parseEventOptions(options))
  }
}

// Remove an event listener from an element
export const eventOff = (el, eventName, handler, options) => {
  if (el && el.removeEventListener) {
    el.removeEventListener(eventName, handler, parseEventOptions(options))
  }
}

// Utility method to add/remove a event listener based on first argument (boolean)
// It passes all other arguments to the `eventOn()` or `eventOff` method
export const eventOnOff = (on, ...args) => {
  const method = on ? eventOn : eventOff
  method(...args)
}

// Utility method to prevent the default event handling and propagation
export const stopEvent = (
  event,
  { preventDefault = true, propagation = true, immediatePropagation = false } = {}
) => {
  if (preventDefault) {
    event.preventDefault()
  }
  if (propagation) {
    event.stopPropagation()
  }
  if (immediatePropagation) {
    event.stopImmediatePropagation()
  }
}

// Helper method to convert a component/directive name to a base event name
// `getBaseEventName('BNavigationItem')` => 'navigation-item'
// `getBaseEventName('BVToggle')` => 'toggle'
const getBaseEventName = value => kebabCase(value.replace(RX_BV_PREFIX, ''))

// Get a root event name by component/directive and event name
// `getBaseEventName('BModal', 'show')` => 'bv::modal::show'
export const getRootEventName = (name, eventName) =>
  [ROOT_EVENT_NAME_PREFIX, getBaseEventName(name), eventName].join(ROOT_EVENT_NAME_SEPARATOR)

// Get a root action event name by component/directive and action name
// `getRootActionEventName('BModal', 'show')` => 'bv::show::modal'
export const getRootActionEventName = (name, actionName) =>
  [ROOT_EVENT_NAME_PREFIX, actionName, getBaseEventName(name)].join(ROOT_EVENT_NAME_SEPARATOR)