PageSourceSearch

https://truebluesalon.com/wp-content/themes/ph-base-tailwind/asset…desktop-nav-dropdowns.standard.js?ver=1.0.0

js truebluesalon.com collected 2026-10-04 02:40:25 UTC 8,514 bytes, 234 lines download raw bytes

1jQuery(document).ready(function () {
2  const $navigation = jQuery('header nav');
3  const $menuItemsWithSubmenus = jQuery('#nav-main #menu-primary-1 > li.menu-item-has-children');
4  let openSubmenuTimeout; // To store the timeout ID for opening submenus
5  let closeSubmenuTimeout; // To store the timeout ID for closing submenus
6
7  /**
8   * Initialize Chevrons and add hover effects.
9   */
10  $menuItemsWithSubmenus.each(function () {
11    const $menuItem = jQuery(this);
12    const $menuLink = $menuItem.children('a'); // Get the direct link within the LI
13    // Append the chevron icon to the link
14    $menuLink.append('<span class="submenu-indicator"> <i class="fa-solid fa-chevron-down"></i></span>');
15    // Add classes for styling and targeting
16    $menuLink.addClass('has-submenu-link');
17  });
18
19  /**
20   * Handles mouseover event on a menu item with a submenu.
21   */
22  $menuItemsWithSubmenus.on('mouseover', function () {
23    console.log('su');
24    const $menuItem = jQuery(this);
25    const $subMenu = $menuItem.find('.sub-menu');
26    const $menuLink = $menuItem.children('a');
27    const $chevron = $menuLink.find('.submenu-indicator');
28
29    // Clear any pending close submenu timeouts for this specific item
30    clearTimeout(closeSubmenuTimeout);
31
32    // Close any other open submenus and reset their chevrons/colors
33    $menuItemsWithSubmenus.not($menuItem).each(function() {
34        const $otherSubMenu = jQuery(this).find('.sub-menu.is_open');
35        const $otherMenuLink = jQuery(this).children('a');
36        const $otherChevron = $otherMenuLink.find('.submenu-indicator');
37
38        // Stop current animation and fade out
39        $otherSubMenu.stop(true, true).fadeOut(100, function () {
40            jQuery(this).removeClass('is_open').attr('aria-expanded', 'false');
41        });
42        // Remove active state for other links immediately
43        $otherMenuLink.removeClass('is-active-submenu');
44        $otherChevron.removeClass('rotated');
45    });
46
47    if ($subMenu.length) {
48      // Clear any pending open submenu timeout for the current item
49      clearTimeout(openSubmenuTimeout);
50
51      // Rotate the chevron immediately on mouseover
52      $chevron.addClass('rotated');
53
54      // Set a timeout to show the submenu
55      openSubmenuTimeout = setTimeout(function () {
56        // Only show if the mouse is still over the parent LI AND submenu is not already open
57        if ($menuItem.is(':hover') && !$subMenu.hasClass('is_open')) {
58          $subMenu.addClass('is_open').attr('aria-expanded', 'true').fadeIn(300, function() {
59            // Add active color class AFTER submenu has fully faded in
60            $menuLink.addClass('is-active-submenu');
61          });
62        }
63      }, 200); // Delay before submenu appears
64    }
65  });
66
67  /**
68   * Handles mouseleave event on a menu item with a submenu.
69   */
70  $menuItemsWithSubmenus.on('mouseleave', function () {
71    const $menuItem = jQuery(this);
72    const $subMenu = $menuItem.find('.sub-menu');
73    const $menuLink = $menuItem.children('a');
74    const $chevron = $menuLink.find('.submenu-indicator');
75
76    // Clear any pending open submenu timeouts for this specific item
77    clearTimeout(openSubmenuTimeout);
78
79    // Set a timeout to hide the submenu and remove active classes
80    closeSubmenuTimeout = setTimeout(function () {
81      // Check if the mouse is NO LONGER over the entire parent LI element.
82      if (!$menuItem.is(':hover')) {
83        // Hide the submenu if it's open
84        if ($subMenu.length && $subMenu.hasClass('is_open')) {
85          $subMenu.fadeOut(200, function () {
86            jQuery(this).removeClass('is_open').attr('aria-expanded', 'false');
87            // Remove active color class AFTER submenu has fully faded out
88            $menuLink.removeClass('is-active-submenu');
89          });
90        } else {
91            // If submenu was never open or already closed, just remove chevron rotation
92            $menuLink.removeClass('is-active-submenu'); // Ensure color is removed even if submenu didn't fadeOut
93        }
94        // Remove chevron rotation immediately when mouse leaves
95        $chevron.removeClass('rotated');
96      }
97    }, 300); // Delay before checking if mouse has fully left
98  });
99
100  // Optional: Handle mouseleave from the entire navigation to close any open submenus
101  $navigation.on('mouseleave', function () {
102    // Clear any pending timeouts when leaving the entire nav
103    clearTimeout(openSubmenuTimeout);
104    clearTimeout(closeSubmenuTimeout);
105
106    jQuery('.sub-menu.is_open').fadeOut(200, function () {
107      jQuery(this).removeClass('is_open').attr('aria-expanded', 'false');
108    });
109
110    // Reset all link colors and chevron rotations when leaving the entire navigation
111    $menuItemsWithSubmenus.children('a').removeClass('is-active-submenu');
112    $menuItemsWithSubmenus.find('.submenu-indicator').removeClass('rotated');
113  });
114});
115
116
117// OLD PLAIN JS VERSION:
118
119// (function () {
120//   // Selecting the navigation and top-level menu items with submenus
121//   const navigation = document.querySelector('header nav');
122//   const menuItemsWithSubmenus = document.querySelectorAll('#menu-primary > li.menu-item-has-children > a');
123
124//   /**
125//    * Initializes event listeners for menu items with submenus on mouseover and mouseleave.
126//    */
127//   function initSubmenuTriggers() {
128//     menuItemsWithSubmenus.forEach(menuItem => {
129//       menuItem.addEventListener('mouseover', handleMouseOver);
130//       menuItem.addEventListener('mouseleave', handleMouseLeave);
131//     });
132//   }
133
134//   /**
135//    * Handles mouseover event on a menu item with a submenu.
136//    * @param {MouseEvent} event - The mouseover event object.
137//    */
138//   function handleMouseOver(event) {
139//     const menuItem = event.target.closest('li');
140//     const subMenu = menuItem?.querySelector('.sub-menu');
141
142//     if (subMenu) {
143//       subMenu.classList.add('is_open');
144//       subMenu.setAttribute('aria-expanded', 'true');
145//     }
146//   }
147
148//   /**
149//    * Handles mouseleave event on a menu item with a submenu and the submenu itself.
150//    * @param {MouseEvent} event - The mouseleave event object.
151//    */
152//   function handleMouseLeave(event) {
153//     const menuItem = event.target.closest('li');
154//     const subMenu = menuItem?.querySelector('.sub-menu');
155
156//     if (subMenu) {
157//       // Add a slight delay to allow the user to move the mouse over the submenu
158//       setTimeout(() => {
159//         // Check if the mouse is still within the menu item or the submenu
160//         if (!menuItem.matches(':hover') && !subMenu.matches(':hover')) {
161//           subMenu.classList.remove('is_open');
162//           subMenu.setAttribute('aria-expanded', 'false');
163//         }
164//       }, 100); // Adjust the delay as needed
165//     }
166//   }
167
168//   // Initialize submenu event listeners
169//   initSubmenuTriggers();
170
171//   // Optional: Handle mouseleave from the entire navigation to close any open submenus
172//   navigation?.addEventListener('mouseleave', () => {
173//     document.querySelectorAll('.sub-menu.is_open').forEach(subMenu => {
174//       subMenu.classList.remove('is_open');
175//       subMenu.setAttribute('aria-expanded', 'false');
176//     });
177//   });
178// })();
179
180
181
182
183/*
184(function() {
185// declare the things
186const navigation = document.querySelector('header nav');
187const links = document.querySelectorAll('#nav-main [data-link]');
188
189function initMenuLinks() {
190  links?.forEach(link => {
191    link.addEventListener('mouseover', mouseOver);
192  })
193}
194
195// when hover, open dropdown
196function mouseOver(e) {
197  links.forEach(link => {
198    link.dataset.link = '';
199  })
200  const subnav = e.target.closest('li').querySelector('.is_subnav');
201  if (subnav) e.target.closest('li').addEventListener('mouseleave', mouseOut);
202
203  navigation.addEventListener('mouseleave', mouseOut);
204  if (!subnav) return;
205
206  subnav.classList.add('is_open');
207  subnav.setAttribute('aria-expanded', true);
208}
209
210// when mouse leaves, close dropdown
211function mouseOut(e) {
212  links.forEach(link => {
213    if (link !== e.target.closest('li')) {
214      const subnav = link.closest('li').querySelector('.is_subnav');
215      link.dataset.link = '';
216      if (subnav) {
217        subnav.classList.remove('is_open');
218        subnav.setAttribute('aria-expanded', false);
219      }
220
221    } else {
222      const subnav = link.closest('li').querySelector('.is_subnav');
223      if (subnav) setTimeout( () => {
224        subnav.classList.remove('is_open');
225        subnav.setAttribute('aria-expanded', false);
226      }, 300);
227    }
228  })
229}
230
231// do the stuff
232initMenuLinks();
233})()
234*/

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.