/** * Helpers to implement event handler IDL attributes. */ import type EventTarget from './EventTarget' import type { EventCallback } from './EventTarget' type EventHandler = Readonly<{ handleEvent: EventCallback }> type EventHandlerAttributeMap = Map const EVENT_HANDLER_CONTENT_ATTRIBUTE_MAP_KEY = Symbol('eventHandlerAttributeMap') function getEventHandlerAttributeMap( target: EventTarget ): EventHandlerAttributeMap | null | undefined { return (target as any)[EVENT_HANDLER_CONTENT_ATTRIBUTE_MAP_KEY] } function setEventHandlerAttributeMap(target: EventTarget, map: EventHandlerAttributeMap | null) { ;(target as any)[EVENT_HANDLER_CONTENT_ATTRIBUTE_MAP_KEY] = map } export function getEventHandlerAttribute(target: EventTarget, type: string): EventCallback | null { const listener = getEventHandlerAttributeMap(target)?.get(type) return listener != null ? listener.handleEvent : null } export function setEventHandlerAttribute( target: EventTarget, type: string, callback: EventCallback | null | undefined ): void { let map = getEventHandlerAttributeMap(target) if (map != null) { const currentListener = map.get(type) if (currentListener) { target.removeEventListener(type, currentListener) map.delete(type) } } if ( callback != null && (typeof callback === 'function' || typeof (callback as any) === 'object') ) { const listener: EventHandler = { handleEvent: callback as EventCallback, } try { target.addEventListener(type, listener) if (map == null) { map = new Map() setEventHandlerAttributeMap(target, map) } map.set(type, listener) } catch (_e) { // Assigning incorrect listener does not throw in setters. } } if (map != null && map.size === 0) { setEventHandlerAttributeMap(target, null) } }