{"version":3,"file":"index.mjs","sources":[""],"sourcesContent":["/**\r\n * Описание пользовательского обработчика события.\r\n */\r\nexport type TEventListener = {\r\n  fn: (event: Event) => void;\r\n};\r\n\r\n\r\n/**\r\n * Данные слушателей события для конкретного элемента.\r\n */\r\nexport type TEventListenerData = {\r\n  options: TEventListenerOptions;\r\n  isListening: boolean;\r\n  callbacks: TEventListener[];\r\n   \r\n  handler?: EventListener;\r\n};\r\n\r\n\r\n/**\r\n * Параметры подписки DOM-слушателя.\r\n */\r\n \r\nexport type TEventListenerOptions = AddEventListenerOptions | null;\r\n\r\n/**\r\n * Набор событий для пакетного заполнения шины.\r\n */\r\nexport type TEventListeners = Record<string, TEventListener[\"fn\"] | {\r\n  fn: TEventListener[\"fn\"];\r\n  options?: TEventListenerOptions;\r\n}>;\r\n\r\n/**\r\n * Основное хранилище подписок Event Bus.\r\n */\r\nexport type TEventStore = Map<string, Map<EventTarget, TEventListenerData>>;\r\n\r\n/**\r\n * Event Bus. Шина для хранения и управления событиями.\r\n * @module EventBus\r\n */\r\nexport class EventBus {\r\n\r\n  store: TEventStore;\r\n\r\n  constructor() {\r\n    this.store = new Map();\r\n  }\r\n\r\n  #removeDomListener(eventName: string, el: EventTarget, data: TEventListenerData) {\r\n    if (data.handler) {\r\n      el.removeEventListener(eventName, data.handler, data.options || undefined);\r\n    }\r\n    data.isListening = false;\r\n    data.handler = undefined;\r\n  }\r\n\r\n  #addEventListener(eventName: string, el?: EventTarget, callback?: TEventListener[\"fn\"]) {\r\n    const isExist = this.isEventExist(eventName);\r\n    const add = (el: EventTarget, data: TEventListenerData) => {\r\n      if (!data.isListening) {\r\n        const handler = this.#handleEvent.bind(this);\r\n        el.addEventListener(eventName, handler, data.options || undefined);\r\n        data.isListening = true;\r\n        data.handler = handler;\r\n      }\r\n    };\r\n    if (isExist) {\r\n      const eventData = this.getMapByEventName(eventName);\r\n      if (!eventData) {\r\n        return;\r\n      }\r\n      eventData.forEach((value, elem) => {\r\n        if (el) {\r\n          if (el === elem) {\r\n            if (callback) {\r\n              value.callbacks.forEach(({ fn }: TEventListener) => {\r\n                if (fn === callback) {\r\n                  add(elem, value);\r\n                }\r\n              });\r\n            } else {\r\n              add(elem, value);\r\n            }\r\n          }\r\n        } else {\r\n          add(elem, value);\r\n        }\r\n      });\r\n    }\r\n  }\r\n\r\n  #removeEventListener(eventName: string, el?: EventTarget, callback?: TEventListener[\"fn\"]) {\r\n    const isExist = this.isEventExist(eventName);\r\n    const remove = (el: EventTarget, data: TEventListenerData) => this.#removeDomListener(eventName, el, data);\r\n    if (isExist) {\r\n      const eventData = this.getMapByEventName(eventName);\r\n      if (!eventData) {\r\n        return;\r\n      }\r\n      eventData.forEach((value, elem) => {\r\n        if (el) {\r\n          if (elem === el) {\r\n            if (callback) {\r\n              value.callbacks.forEach(({ fn }: TEventListener) => {\r\n                if (fn === callback) {\r\n                  remove(el, value);\r\n                }\r\n              });\r\n            } else {\r\n              remove(el, value);\r\n            }\r\n          }\r\n        } else {\r\n          remove(elem, value);\r\n        }\r\n      });\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Подписывается на прослушивание события\r\n   * @param eventName{String=} название события\r\n   * @param el{Node|Element|HTMLElement} элемент\r\n   * @param callback{Function=} обработчик\r\n   */\r\n  subscribe(eventName = \"\", el?: EventTarget, callback?: TEventListener[\"fn\"]) {\r\n    if (eventName) {\r\n      const isExist = this.isEventExist(eventName);\r\n      if (isExist) {\r\n        this.#addEventListener(eventName, el, callback);\r\n      }\r\n    } else {\r\n      this.store.forEach((_value, eventName) => {\r\n        this.#addEventListener(eventName, el, callback);\r\n      });\r\n    }\r\n  }\r\n\r\n  #handleEvent(e: Event) {\r\n    const currentEl = e.currentTarget || e.target;\r\n    if (currentEl) {\r\n      return this.publish(e.type, currentEl, undefined, e);\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Возвращает карту данных для события их хранилища по его имени\r\n   * @param eventName{String} название события\r\n   * @returns {Map<EventTarget, TEventListenerData>|undefined}\r\n   */\r\n  getMapByEventName(eventName: string): Map<EventTarget, TEventListenerData> | undefined {\r\n    return this.store.get(eventName);\r\n  }\r\n\r\n  /**\r\n   * Отменяет подписку на событие\r\n   * @param eventName{String=} название события\r\n   * @param el{Node|Element|HTMLElement=} элемент\r\n   * @param callback{Function=} обработчик\r\n   */\r\n  unsubscribe(eventName = \"\", el?: EventTarget, callback?: TEventListener[\"fn\"]) {\r\n    if (eventName) {\r\n      const isExist = this.isEventExist(eventName);\r\n      if (isExist) {\r\n        this.#removeEventListener(eventName, el, callback);\r\n      }\r\n    } else {\r\n      this.store.forEach((_value, eventName) => {\r\n        this.#removeEventListener(eventName, el, callback);\r\n      });\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Добавляет событие в хранилище\r\n   * @param eventName{String} название события\r\n   * @param data{{ fn: Function, el: Node|Element|HTMLElement, options: EventListenerOptions=, isListening: Boolean= }} данные\r\n   */\r\n   \r\n  add(eventName = \"\", data: { fn?: TEventListener[\"fn\"]; el?: EventTarget; options?: AddEventListenerOptions | null; isListening?: boolean; } = {}) {\r\n    const {\r\n      fn, el, options = null, isListening = false,\r\n    } = data;\r\n    if (!fn || !el) {\r\n      return;\r\n    }\r\n\r\n    if (this.isEventExist(eventName)) {\r\n      const currentEvent = this.getMapByEventName(eventName);\r\n      if (!currentEvent) {\r\n        return;\r\n      }\r\n\r\n      if (currentEvent.has(el)) {\r\n        const currentElListeners = currentEvent.get(el);\r\n        if (currentElListeners) {\r\n          if (!currentElListeners.callbacks.find((listener: TEventListener) => {\r\n            return listener.fn === fn;\r\n          })) {\r\n            currentElListeners.callbacks.push({ fn });\r\n          }\r\n        }\r\n      } else {\r\n        currentEvent.set(el, {\r\n          options,\r\n          isListening,\r\n          callbacks: [ { fn } ],\r\n        });\r\n      }\r\n    } else {\r\n      this.store.set(eventName, new Map([ [ el, {\r\n        options,\r\n        isListening,\r\n        callbacks: [ { fn } ],\r\n      } ] ]));\r\n    }\r\n  }\r\n\r\n  #deleteFromStore(eventName: string) {\r\n    this.store.delete(eventName);\r\n  }\r\n\r\n  /**\r\n   * Возвращает результат проверки существования события в хранилище по имени\r\n   * @param eventName{String} название события\r\n   * @returns {boolean}\r\n   */\r\n  isEventExist(eventName = \"\") {\r\n    return this.store.has(eventName);\r\n  }\r\n\r\n  /**\r\n   * Исполняет событие, вызывая его обработчик\r\n   * @param eventName{String=} название события\r\n   * @param el{Node|Element|HTMLElement=} элемент\r\n   * @param callback{Function=} обработчик\r\n   * @param args{Event=} объект события\r\n   */\r\n  publish(eventName?: string, el?: EventTarget, callback?: TEventListener[\"fn\"], args?: Event) {\r\n    if (eventName) {\r\n      if (this.isEventExist(eventName)) {\r\n        const caller = ({\r\n          currentEl,\r\n          callbacks = [],\r\n          filter = (_item: TEventListener) => true,\r\n          options,\r\n        }: {\r\n          currentEl: EventTarget;\r\n          callbacks?: TEventListener[];\r\n          filter?: (item: TEventListener) => boolean;\r\n          options?: TEventListenerOptions;\r\n        }) => {\r\n          const eventArg = args || new Event(eventName);\r\n          const filteredCallbacks = callbacks.filter(filter);\r\n          filteredCallbacks.forEach(({ fn }: TEventListener) => fn(eventArg));\r\n          if (options?.once && filteredCallbacks.length) {\r\n            if (callback) {\r\n              this.clear(eventName, currentEl, callback);\r\n            } else {\r\n              this.clear(eventName, currentEl);\r\n            }\r\n          }\r\n        };\r\n        const eventData = this.getMapByEventName(eventName);\r\n        if (!eventData) {\r\n          return;\r\n        }\r\n\r\n        eventData.forEach(({ callbacks, options }, elem) => {\r\n          if (el) {\r\n            if (el === elem) {\r\n              if (callback) {\r\n                caller({\r\n                  currentEl: elem,\r\n                  options,\r\n                  callbacks,\r\n                  filter: ({ fn }: TEventListener) => fn === callback,\r\n                });\r\n              } else {\r\n                caller({ currentEl: elem, options, callbacks });\r\n              }\r\n            }\r\n          } else {\r\n            caller({ currentEl: elem, options, callbacks });\r\n          }\r\n        });\r\n      }\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Заполняет хранилище данными из объекта\r\n   * @param el{Node|Element|HTMLElement=} элемент\r\n   * @param listeners{Object} объект событий\r\n   */\r\n  fill(el?: EventTarget, listeners: TEventListeners = {}) {\r\n    if (!el) {\r\n      return;\r\n    }\r\n\r\n    Object.entries(listeners)\r\n      .forEach(([ eventName, params ]) => {\r\n        if (eventName && params) {\r\n          const handlerData = typeof params === \"function\" ? { fn: params, el } : {\r\n            fn: params.fn,\r\n            options: params.options,\r\n            el,\r\n          };\r\n          this.add(eventName, handlerData);\r\n        }\r\n      });\r\n  }\r\n\r\n  /**\r\n   * Очищает хранилище от событий\r\n   * @param eventName{String=} название события\r\n   * @param el{Node|Element|HTMLElement=} элемент\r\n   * @param callback{Function=} обработчик\r\n   */\r\n  clear(eventName?: string, el?: EventTarget, callback?: TEventListener[\"fn\"]) {\r\n    if (eventName) {\r\n      if (this.isEventExist(eventName)) {\r\n        const eventData = this.getMapByEventName(eventName);\r\n        if (!eventData) {\r\n          return;\r\n        }\r\n\r\n        if (el) {\r\n          const currentEvent = eventData.get(el);\r\n          if (!currentEvent) {\r\n            return;\r\n          }\r\n          if (callback) {\r\n            currentEvent.callbacks = currentEvent.callbacks.filter(({ fn }: TEventListener) => fn !== callback);\r\n            if (!currentEvent.callbacks.length) {\r\n              this.#removeDomListener(eventName, el, currentEvent);\r\n              eventData.delete(el);\r\n            }\r\n          } else {\r\n            this.#removeDomListener(eventName, el, currentEvent);\r\n            eventData.delete(el);\r\n          }\r\n        } else {\r\n          this.unsubscribe(eventName);\r\n          eventData.clear();\r\n        }\r\n        if (!eventData.size) {\r\n          this.#deleteFromStore(eventName);\r\n        }\r\n      }\r\n    } else {\r\n      this.unsubscribe();\r\n      this.store.clear();\r\n    }\r\n  }\r\n\r\n}\r\n"],"names":["EventBus","store","constructor","this","Map","removeDomListener","eventName","el","data","handler","removeEventListener","options","undefined","isListening","addEventListener","callback","isExist","isEventExist","add","handleEvent","bind","eventData","getMapByEventName","forEach","value","elem","callbacks","fn","remove","subscribe","_value","e","currentEl","currentTarget","target","publish","type","get","unsubscribe","currentEvent","has","currentElListeners","find","listener","push","set","deleteFromStore","delete","args","caller","filter","_item","eventArg","Event","filteredCallbacks","once","length","clear","fill","listeners","Object","entries","params","handlerData","size"],"mappings":"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"}