PageSourceSearch

https://nextgis.ru/wp-content/themes/nextgisclean_wptheme/main-assets/js/header-menu.js?ver=1.0.0

js nextgis.ru collected 2026-10-01 11:51:57 UTC 6,689 bytes, 199 lines download raw bytes

1document.addEventListener("DOMContentLoaded", () => {
2  // ==================== DESKTOP MENU FUNCTIONALITY ====================
3  const dropdownItems = document.querySelectorAll(".ng-has-dropdown")
4
5  dropdownItems.forEach((item) => {
6    const dropdownMenu = item.querySelector(".ng-dropdown-menu")
7    if (!dropdownMenu) return
8
9    let hoverTimeout
10
11    item.addEventListener("mouseenter", () => {
12      clearTimeout(hoverTimeout)
13
14      // Hide all other dropdown menus
15      dropdownItems.forEach((otherItem) => {
16        if (otherItem !== item) {
17          const otherMenu = otherItem.querySelector(".ng-dropdown-menu")
18          if (otherMenu) {
19            otherMenu.style.opacity = "0"
20            otherMenu.style.visibility = "hidden"
21            otherMenu.style.transform = "translateY(-10px)"
22          }
23        }
24      })
25
26      // Show the current menu
27      dropdownMenu.style.opacity = "1"
28      dropdownMenu.style.visibility = "visible"
29      dropdownMenu.style.transform = "translateY(0)"
30    })
31
32    item.addEventListener("mouseleave", () => {
33      hoverTimeout = setTimeout(() => {
34        dropdownMenu.style.opacity = "0"
35        dropdownMenu.style.visibility = "hidden"
36        dropdownMenu.style.transform = "translateY(-10px)"
37      }, 100)
38    })
39
40    dropdownMenu.addEventListener("mouseenter", () => {
41      clearTimeout(hoverTimeout)
42    })
43
44    dropdownMenu.addEventListener("mouseleave", () => {
45      dropdownMenu.style.opacity = "0"
46      dropdownMenu.style.visibility = "hidden"
47      dropdownMenu.style.transform = "translateY(-10px)"
48    })
49  })
50
51  // ==================== ACCESSIBILITY IMPROVEMENTS ====================
52  const menuLinks = document.querySelectorAll(".ng-menu-link")
53
54  menuLinks.forEach((link) => {
55    link.addEventListener("focus", () => {
56      const parentItem = link.closest(".ng-has-dropdown")
57      if (parentItem) {
58        const dropdownMenu = parentItem.querySelector(".ng-dropdown-menu")
59        if (dropdownMenu) {
60          dropdownMenu.style.opacity = "1"
61          dropdownMenu.style.visibility = "visible"
62          dropdownMenu.style.transform = "translateY(0)"
63        }
64      }
65    })
66
67    link.addEventListener("blur", (event) => {
68      const parentItem = link.closest(".ng-has-dropdown")
69      if (parentItem) {
70        setTimeout(() => {
71          const focusedElement = document.activeElement
72          const isInsideDropdown = parentItem.contains(focusedElement)
73
74          if (!isInsideDropdown) {
75            const dropdownMenu = parentItem.querySelector(".ng-dropdown-menu")
76            if (dropdownMenu) {
77              dropdownMenu.style.opacity = "0"
78              dropdownMenu.style.visibility = "hidden"
79              dropdownMenu.style.transform = "translateY(-10px)"
80            }
81          }
82        }, 100)
83      }
84    })
85  })
86
87  // ==================== MOBILE MENU FUNCTIONALITY ====================
88  const mobileToggle = document.querySelector(".ng-mobile-menu-toggle")
89  const mobileOverlay = document.querySelector(".ng-mobile-menu-overlay")
90  const htmlElement = document.documentElement
91  const bodyElement = document.body
92
93  // Function for getting scrollbar width
94  function getScrollbarWidth() {
95    const scrollDiv = document.createElement("div")
96    scrollDiv.style.cssText = "width: 100px; height: 100px; overflow: scroll; position: absolute; top: -9999px;"
97    document.body.appendChild(scrollDiv)
98    const scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
99    document.body.removeChild(scrollDiv)
100    return scrollbarWidth
101  }
102
103  if (mobileToggle && mobileOverlay) {
104    mobileToggle.addEventListener("click", function (e) {
105      e.preventDefault()
106      e.stopPropagation()
107
108      const isOpening = !this.classList.contains("active")
109
110      if (isOpening) {
111        const scrollbarWidth = getScrollbarWidth()
112        document.documentElement.style.setProperty("--scrollbar-width", scrollbarWidth + "px")
113      }
114
115      this.classList.toggle("active")
116      mobileOverlay.classList.toggle("active")
117      htmlElement.classList.toggle("ng-menu-open")
118      bodyElement.classList.toggle("ng-menu-open")
119
120      if (!isOpening) {
121        document.documentElement.style.removeProperty("--scrollbar-width")
122      }
123    })
124
125    // Close menu on overlay click (but not on menu content)
126    mobileOverlay.addEventListener("click", (e) => {
127      if (e.target === mobileOverlay) {
128        closeMobileMenu()
129      }
130    })
131
132    // Close menu on Escape key
133    document.addEventListener("keydown", (e) => {
134      if (e.key === "Escape" && mobileOverlay.classList.contains("active")) {
135        closeMobileMenu()
136      }
137    })
138
139    function closeMobileMenu() {
140      mobileToggle.classList.remove("active")
141      mobileOverlay.classList.remove("active")
142      htmlElement.classList.remove("ng-menu-open")
143      bodyElement.classList.remove("ng-menu-open")
144      document.documentElement.style.removeProperty("--scrollbar-width")
145
146      // Close all open submenus
147      const activeItems = document.querySelectorAll(".ng-mobile-menu-item.active")
148      activeItems.forEach((item) => {
149        item.classList.remove("active")
150      })
151    }
152  }
153
154  // Mobile submenu functionality
155  const mobileMenuItems = document.querySelectorAll(".ng-mobile-menu-item.ng-has-dropdown")
156
157  mobileMenuItems.forEach((menuItem) => {
158    const menuLink = menuItem.querySelector(".ng-mobile-menu-link")
159    const arrow = menuItem.querySelector(".ng-mobile-dropdown-arrow")
160    const submenu = menuItem.querySelector(".ng-mobile-submenu")
161
162    if (submenu && arrow) {
163      // Create wrapper for better click handling
164      const wrapper = document.createElement("div")
165      wrapper.className = "ng-mobile-menu-item-wrapper"
166
167      // Move link and arrow into wrapper
168      menuItem.insertBefore(wrapper, submenu)
169      wrapper.appendChild(menuLink)
170      wrapper.appendChild(arrow)
171
172      // Handle clicks on the wrapper (entire top area)
173      wrapper.addEventListener("click", (e) => {
174        e.preventDefault()
175        e.stopPropagation()
176
177        // Close other open submenus
178        mobileMenuItems.forEach((otherItem) => {
179          if (otherItem !== menuItem && otherItem.classList.contains("active")) {
180            otherItem.classList.remove("active")
181          }
182        })
183
184        // Toggle current submenu
185        menuItem.classList.toggle("active")
186      })
187
188      // Prevent link navigation for items with submenus
189      if (menuLink) {
190        menuLink.addEventListener("click", (e) => {
191          e.preventDefault()
192        })
193      }
194    }
195  })
196
197  console.log("Mobile menu initialized successfully")
198  console.log("Found mobile menu items with dropdowns:", mobileMenuItems.length)
199})

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.