| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- const TIMEOUT = 150
-
- class MegaDropdown {
- constructor(element, options = {}) {
- this._onHover = options.trigger === 'hover' || element.getAttribute('data-trigger') === 'hover'
-
- this._container = MegaDropdown._findParent(element, 'mega-dropdown')
- if (!this._container) return
-
- this._menu = this._container.querySelector('.dropdown-toggle ~ .dropdown-menu')
- if (!this._menu) return
-
- element.setAttribute('aria-expanded', 'false')
-
- this._el = element
- this._bindEvents()
- }
-
- open() {
- if (this._timeout) {
- clearTimeout(this._timeout)
- this._timeout = null
- }
- if (this._focusTimeout) {
- clearTimeout(this._focusTimeout)
- this._focusTimeout = null
- }
-
- if (this._el.getAttribute('aria-expanded') !== 'true') {
- this._triggerEvent('show')
- this._container.classList.add('show')
- this._menu.classList.add('show')
- this._el.setAttribute('aria-expanded', 'true')
- this._el.focus()
- this._triggerEvent('shown')
- }
- }
-
- close(force) {
- if (this._timeout) {
- clearTimeout(this._timeout)
- this._timeout = null
- }
- if (this._focusTimeout) {
- clearTimeout(this._focusTimeout)
- this._focusTimeout = null
- }
-
- if (this._onHover && !force) {
- this._timeout = setTimeout(() => {
- if (this._timeout) {
- clearTimeout(this._timeout)
- this._timeout = null
- }
- this._close()
- }, TIMEOUT)
- } else {
- this._close()
- }
- }
-
- toggle() {
- // eslint-disable-next-line no-unused-expressions
- this._el.getAttribute('aria-expanded') === 'true' ? this.close(true) : this.open()
- }
-
- destroy() {
- this._unbindEvents()
- this._el = null
-
- if (this._timeout) {
- clearTimeout(this._timeout)
- this._timeout = null
- }
-
- if (this._focusTimeout) {
- clearTimeout(this._focusTimeout)
- this._focusTimeout = null
- }
- }
-
- _close() {
- if (this._el.getAttribute('aria-expanded') === 'true') {
- this._triggerEvent('hide')
- this._container.classList.remove('show')
- this._menu.classList.remove('show')
- this._el.setAttribute('aria-expanded', 'false')
- this._triggerEvent('hidden')
- }
- }
-
- _bindEvents() {
- this._elClickEvnt = e => {
- e.preventDefault()
- this.toggle()
- }
- this._el.addEventListener('click', this._elClickEvnt)
-
- this._bodyClickEvnt = e => {
- if (!this._container.contains(e.target) && this._container.classList.contains('show')) {
- this.close(true)
- }
- }
- document.body.addEventListener('click', this._bodyClickEvnt, true)
-
- this._menuClickEvnt = e => {
- if (e.target.classList.contains('mega-dropdown-link')) {
- this.close(true)
- }
- }
- this._menu.addEventListener('click', this._menuClickEvnt, true)
-
- this._focusoutEvnt = () => {
- if (this._focusTimeout) {
- clearTimeout(this._focusTimeout)
- this._focusTimeout = null
- }
-
- if (this._el.getAttribute('aria-expanded') !== 'true') return
-
- this._focusTimeout = setTimeout(() => {
- if (
- document.activeElement.tagName.toUpperCase() !== 'BODY' &&
- MegaDropdown._findParent(document.activeElement, 'mega-dropdown') !== this._container
- ) {
- this.close(true)
- }
- }, 100)
- }
- this._container.addEventListener('focusout', this._focusoutEvnt, true)
-
- if (this._onHover) {
- this._enterEvnt = () => {
- if (window.getComputedStyle(this._menu, null).getPropertyValue('position') === 'static') return
- this.open()
- }
- this._leaveEvnt = () => {
- if (window.getComputedStyle(this._menu, null).getPropertyValue('position') === 'static') return
- this.close()
- }
-
- this._el.addEventListener('mouseenter', this._enterEvnt)
- this._menu.addEventListener('mouseenter', this._enterEvnt)
- this._el.addEventListener('mouseleave', this._leaveEvnt)
- this._menu.addEventListener('mouseleave', this._leaveEvnt)
- }
- }
-
- _unbindEvents() {
- if (this._elClickEvnt) {
- this._el.removeEventListener('click', this._elClickEvnt)
- this._elClickEvnt = null
- }
- if (this._bodyClickEvnt) {
- document.body.removeEventListener('click', this._bodyClickEvnt, true)
- this._bodyClickEvnt = null
- }
- if (this._menuClickEvnt) {
- this._menu.removeEventListener('click', this._menuClickEvnt, true)
- this._menuClickEvnt = null
- }
- if (this._focusoutEvnt) {
- this._container.removeEventListener('focusout', this._focusoutEvnt, true)
- this._focusoutEvnt = null
- }
- if (this._enterEvnt) {
- this._el.removeEventListener('mouseenter', this._enterEvnt)
- this._menu.removeEventListener('mouseenter', this._enterEvnt)
- this._enterEvnt = null
- }
- if (this._leaveEvnt) {
- this._el.removeEventListener('mouseleave', this._leaveEvnt)
- this._menu.removeEventListener('mouseleave', this._leaveEvnt)
- this._leaveEvnt = null
- }
- }
-
- static _findParent(el, cls) {
- if (el.tagName.toUpperCase() === 'BODY') return null
- el = el.parentNode
- while (el.tagName.toUpperCase() !== 'BODY' && !el.classList.contains(cls)) {
- el = el.parentNode
- }
- return el.tagName.toUpperCase() !== 'BODY' ? el : null
- }
-
- _triggerEvent(event) {
- if (document.createEvent) {
- let customEvent
-
- if (typeof Event === 'function') {
- customEvent = new Event(event)
- } else {
- customEvent = document.createEvent('Event')
- customEvent.initEvent(event, false, true)
- }
-
- this._container.dispatchEvent(customEvent)
- } else {
- this._container.fireEvent(`on${event}`, document.createEventObject())
- }
- }
- }
-
- window.MegaDropdown = MegaDropdown
- export { MegaDropdown }
|