PageSourceSearch

https://www.123.ie/themes/custom/theme123/js/navigation.js?tkf3tj

js 123.ie collected 2026-09-24 18:36:46 UTC 17,898 bytes, 499 lines download raw bytes

1(function (Drupal, $) {
2  Drupal.behaviors.mainMenuA11y = {
3    attach: function (context) {
4      function getFocusableElements($container) {
5        return $container
6          .find('a[href]:not([tabindex="-1"]), button:not([disabled]), input, select, textarea, [tabindex="0"]')
7          .filter(':visible');
8      }
9      function trapFocus($container) {
10        $container.on('keydown.focusTrap', function (e) {
11          // 1. Filter for Tab key immediately
12          if (e.key !== 'Tab') return;
13
14          const $focusable = getFocusableElements($(this));
15
16          if ($focusable.length === 0) return;
17
18          const $first = $focusable.first();
19          const $last = $focusable.last();
20
21          if (e.shiftKey) {
22            if ($(document.activeElement).is($first)) {
23              e.preventDefault();
24              $last.focus();
25            }
26          }
27          else {
28            if ($(document.activeElement).is($last)) {
29              e.preventDefault();
30              $first.focus();
31            }
32          }
33        });
34      }
35      function releaseFocus($container) {
36        $container.off('keydown.focusTrap');
37      }
38      // Mobile menu accordion L1
39      if (!window.matchMedia('(min-width: 1200px)').matches) {
40        /* =========================================================
41        * Helpers
42        * ======================================================= */
43
44        function toggleSubmenu($submenu, open) {
45          $submenu.toggleClass('mobile-menu--active', open).attr('aria-hidden', String(!open)).prop('hidden', !open);
46        }
47
48        function closeAllLevel3() {
49          $('.first-child-level-link').removeClass('js-active');
50          $('.sub-menu--level3.mobile').css('height', 0)
51          .attr('aria-hidden', 'true')
52          .prop('hidden', true);
53
54        }
55
56        /* =========================================================
57        * L1 – Mobile Menu Toggle
58        * ======================================================= */
59
60        $(once('main-header__mobile-toggle', '.main-header__mobile-toggle', context))
61          .each(function () {
62            const $toggle = $(this);
63            const $mainContent = $('.main-content');
64
65            $toggle.on('click', function () {
66              const isOpen = !$toggle.hasClass('js-active');
67
68              $toggle
69                .toggleClass('js-active', isOpen)
70                .attr('aria-expanded', isOpen);
71
72              $('body').toggleClass('js-no-scroll', isOpen);
73              $mainContent.toggleClass('menu-hover', isOpen);
74
75              const $navWrap = $toggle.parents('.main-header__main-nav-wrap');
76              const $nav = $navWrap.find('.main-nav');
77
78              $navWrap.toggleClass('js-active', isOpen);
79
80              $nav.slideToggle(300, function () {
81                if (isOpen) {
82                  // trapFocus($nav);
83                  getFocusableElements($nav).first().focus();
84                } else {
85                  // releaseFocus($nav);
86                  $toggle.focus();
87                }
88              });
89            });
90          });
91
92        /* =========================================================
93        * L2 – Second Level Submenu
94        * ======================================================= */
95
96        $(once('main-menu-level2', '.main-menu--first > li > button', context))
97          .each(function () {
98
99            $(this).on('click keydown', function (e) {
100              if (e.type === 'keydown' && e.key !== 'Escape') return;
101
102              const $this = $(this);
103              const $submenu = $this.siblings('.main-menu--second');
104              const willOpen = !$submenu.hasClass('mobile-menu--active');
105              // ESC → close L2 only
106              if (e.key === 'Escape') {
107                e.preventDefault();
108                e.stopPropagation();
109
110                $this.attr('aria-expanded', 'false');
111                toggleSubmenu($submenu, false);
112                $this.parent().removeClass('js-active');
113
114                closeAllLevel3();
115                $this.focus();
116                if (willOpen && $('.main-header__mobile-toggle').hasClass('js-active')) {
117                  const $l1Toggle = $('.main-header__mobile-toggle');
118                  $l1Toggle.trigger('click').focus();
119                }
120                return;
121              }
122
123
124              $this.attr('aria-expanded', willOpen);
125              toggleSubmenu($submenu, willOpen);
126              $this.parent().toggleClass('js-active', willOpen);
127
128              closeAllLevel3();
129            });
130          });
131
132        /* =========================================================
133        * L3 – Third Level Submenu
134        * ======================================================= */
135
136        $(once('main-menu-level3', '.first-child-level-link .sub-child', context))
137          .each(function () {
138
139          $(this).on('click keydown', function (e) {
140
141            if (e.type === 'keydown' && e.key !== 'Escape') return;
142
143            if (e.type === 'click' && window.matchMedia('(max-width: 1199px)').matches) {
144              e.preventDefault();
145            }
146
147            const $toggle = $(this);
148            const $parentLi = $toggle.parent('.first-child-level-link');
149            const $parentL1 = $toggle.closest('li.main-link');
150            const $submenu = $parentLi.children('.sub-menu--level3.mobile');
151
152            const willOpen = !$parentLi.hasClass('js-active');
153
154            // ESC → close L3 only
155            if (e.key === 'Escape') {
156              e.preventDefault();
157              e.stopPropagation();
158
159              $parentLi.removeClass('js-active');
160              toggleSubmenu($submenu, false);
161              $submenu.css('height', 0);
162
163              $toggle.attr('aria-expanded', 'false').focus();
164              if (willOpen) {
165                $parentL1.children('.main-link-trigger').trigger('click').focus();
166              }
167
168              return;
169            }
170
171
172            closeAllLevel3();
173
174            if (willOpen) {
175              $parentLi.addClass('js-active');
176              toggleSubmenu($submenu, true);
177
178              let totalHeight = 0;
179              $submenu.find('.last-link').each(function () {
180                totalHeight += $(this).outerHeight(true);
181              });
182
183              $submenu.css('height', totalHeight);
184            } else {
185              $parentLi.removeClass('js-active');
186              toggleSubmenu($submenu, false);
187              $submenu.css('height', 0);
188            }
189
190            $toggle.attr('aria-expanded', willOpen);
191          });
192        });
193
194        $(once('main-menu-level3-2', '.main-menu--second .subsection-single-link-wrapper .last-link  > a', context))
195          .each(function () {
196            $(this).on('keydown', function (e) {
197              if (e.type === 'keydown' && e.key !== 'Escape') return;
198              e.preventDefault();
199              e.stopPropagation();
200              $(this).closest('li.main-link').children('.main-link-trigger').trigger('click').focus();
201            });
202        });
203        $(once('main-menu-level3-3','#main-navigation .main-menu--second .my123-menu-icon  ul.dropdown li > a', context))
204          .each(function () {
205            $(this).on('keydown', function (e) {
206              if (e.type === 'keydown' && e.key !== 'Escape') return;
207              e.preventDefault();
208              e.stopPropagation();
209              $(this).closest('li.header-right--mymenu.main-link').children('.mobile-trigger').trigger('click').focus();
210            });
211        });
212
213        $(once('main-menu-level3-4','#search-block-form input', context))
214          .each(function () {
215            $(this).on('keydown', function (e) {
216              if (e.type === 'keydown' && e.key !== 'Escape') return;
217              e.preventDefault();
218              e.stopPropagation();
219              $(this).closest('li.header-right--search.main-link').children('.mobile-trigger').trigger('click').focus();
220            });
221        });
222
223        /* =========================================================
224        * L4 – Fourth Level Submenu Toggle
225        * ======================================================= */
226
227        $(once('main-menu-level4', '.sub-menu--level3.mobile .last-link', context))
228          .each(function () {
229
230          $(this).on('keydown', function (e) {
231            if (e.type === 'keydown' && e.key !== 'Escape') return;
232            e.preventDefault();
233            e.stopPropagation();
234            const $toggle = $(this);
235            const $parentMenu = $toggle.parent('.sub-menu--level3.mobile');
236            const $parentLi = $parentMenu.parent('.first-child-level-link');
237            $parentLi.children('.sub-child').attr('aria-expanded', 'false').focus();
238            $parentLi.removeClass('js-active');
239            toggleSubmenu($parentMenu, false);
240            $parentMenu.css('height', 0);
241            return;
242          });
243        });
244      }
245      else {
246        const link = $('.first-child-level-link');
247        const mainContent = $('.main-content');
248        const icon = $('.triangle-icon');
249        let previousLinkData = null;
250
251        const windowHeight = window.innerHeight;
252        const isMobile = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry|IEMobile)/);
253
254        if (windowHeight < 800 && !isMobile) {
255          $('.subsection-first-level-wrapper').addClass('small-screens');
256        }
257
258        const resetHoverState = () => {
259          link.removeClass('is-hover');
260          $('.main-image').show();
261          $('.subsection-menu-image-wrapper .sub-image div').removeClass('is-hover');
262          $('.subsection-second-level-links > ul').removeClass('is-hover');
263        };
264        $(once('main-menu-level2-desktop', '.first-child-level-link', context))
265          .each(function () {
266          $(this).on('mouseenter keydown click', function(e) {
267
268            if (e.type === 'click') {
269              let anchortag = $(this).children('button.sub-child').data('target')
270              let anchorLink = ""
271              const isMobile =  /Mobi|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Windows Phone|webOS/i.test(navigator.userAgent) ||  (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
272              const hasDesktopAnchor = $(this).children('a').length > 0;
273              if (!isMobile && !hasDesktopAnchor) {
274                anchortag = $(this).children('button.sub-child').attr('aria-controls')
275                anchorLink = $(`#${anchortag}`).find('a').first().attr('href')
276              }
277              else {
278                anchorLink = $(`#${anchortag}`).attr('href')
279              }
280              if(anchorLink && anchorLink !== "#") {
281                window.location.href = anchorLink;
282              }
283              return;
284            }
285
286            const linkData = $(this).data('target');
287            if (e.type === 'keydown') {
288              if (e.key === 'Tab') {
289                if(!$(`#${linkData}`).hasClass('is-hover'))return;
290                e.preventDefault();
291                e.stopPropagation();
292                $(`#${linkData}, li.${linkData}`).addClass('is-hover');
293                $(`#${linkData}`).find('a')
294                $(`#${linkData}`).find('a').eq(1).focus()
295                trapFocus($(`#${linkData}`))
296              }
297              if (e.key === 'Tab') {
298              }
299              if (e.key !== 'Enter' && e.key !== ' ') return;
300              e.preventDefault();
301              e.stopPropagation();
302              releaseFocus($(this))
303              $(`li.${linkData}`).children('.sub-child').attr('aria-expanded', 'true')
304              // $(this).blur();
305              setTimeout(() => {
306                  $(this).children('.sub-child').focus();
307              }, 50);
308              if (previousLinkData === linkData) {
309                resetHoverState();
310                previousLinkData = null;
311                $(`li.${linkData}`).children('.sub-child').attr('aria-expanded', 'false')
312                setTimeout(() => {
313                    $(this).children('.sub-child').focus();
314                }, 50);
315                return;
316              }
317            }
318
319            if (!linkData) return;
320
321            if (previousLinkData && previousLinkData !== linkData) {
322              $(`#${previousLinkData}-image`).removeClass('is-hover');
323              $(`#${previousLinkData}, .${previousLinkData}`).removeClass('is-hover');
324            }
325
326            previousLinkData = linkData;
327
328            $('.main-image').hide();
329            $(`#${linkData}-image`).addClass('is-hover');
330            $(`#${linkData}, li.${linkData}`).addClass('is-hover');
331            $(`#${linkData}`).attr('aria-hidden', 'false');
332          });
333        });
334
335        $('.subsection-links-container').on('mouseleave', () => {
336          resetHoverState();
337          previousLinkData = null;
338        });
339        $(once('main-menu-level3-desktop', '.sub-menu--level3.desktop', context))
340          .each(function () {
341          $(this).on('keydown', function(e) {
342            if (e.type === 'keydown' && e.key !== 'Escape') return;
343            e.preventDefault();
344            e.stopPropagation();
345            releaseFocus($(this))
346            resetHoverState();
347            previousLinkData = null;
348            const id = $(this).prop('id')
349            const parentMenu = $(this).closest('.subsection-links-container').children('ul')
350            trapFocus(parentMenu)
351
352            $(`li.${id}`).children('.sub-child').attr('aria-expanded', 'false').focus()
353          });
354        });
355
356
357        $('.main-menu.main-menu--first').hover(
358          () => mainContent.attr('aria-expanded', 'true'),
359          () => mainContent.attr('aria-expanded', 'false')
360        );
361        // Adding support for focus as well
362        const $menu = $('.main-menu--first', context);
363
364        var mainHeader = $('.main-header');
365
366        $menu.on('focusin', () => {
367          mainContent.attr('aria-expanded', 'true');
368          mainHeader.addClass('is-hover');
369        });
370
371        $menu.on('focusout', () => {
372          mainContent.attr('aria-expanded', 'false'),
373          mainHeader.removeClass('is-hover');
374        });
375
376        $('.header-menu-list').hover(
377          function() {
378
379            $('.main-link').hover(function() {
380              const linkData = $(this).data('target');
381              if (previousLinkData !== linkData) {
382                if (previousLinkData) {
383                  $(`.${previousLinkData}`).removeClass('is-hover');
384                }
385                previousLinkData = linkData;
386              }
387              $(`.${linkData}`).addClass('is-hover');
388              mainHeader.addClass('is-hover');
389
390            });
391          },
392          function() {
393            $('.main-link li').removeClass('is-hover');
394          }
395        );
396
397        function moveIcon() {
398          const link = $(this);
399          const position = link.position();
400          const width = link.width();
401
402          icon.css({
403            left: position.left + (width / 2) - (icon.width() / 2)
404          });
405        }
406
407        $('.main-link').on('mouseenter focusin', moveIcon);
408        const triggers = $menu.find('.main-link-trigger');
409
410        /* ----------------------------
411        * Utilities
412        * ---------------------------- */
413
414        function closeAll() {
415
416          $menu.find('[aria-hidden="false"]').attr('aria-hidden', 'true');
417          $menu.find('.is-hover').removeClass('is-hover');
418          triggers.attr('aria-expanded', 'false');
419          $menu.find('li[aria-expanded="true"]').attr('aria-expanded', 'false');
420        }
421
422        function openMenu($btn) {
423          const panelId = $btn.attr('aria-controls');
424          if (!panelId) return;
425
426          closeAll();
427
428          $btn.attr('aria-expanded', 'true');
429          $btn.closest('li').attr('aria-expanded', 'true');
430          $('#' + panelId).attr('aria-hidden', 'false');
431          const targetMenuList = $('#' + panelId).find('.subsection-links-container').children('ul')
432          trapFocus(targetMenuList)
433        }
434
435        function toggleMenu($btn) {
436          const panelId = $btn.attr('aria-controls');
437          if (!panelId) return;
438
439          const expanded = $btn.attr('aria-expanded') === 'true';
440          $('#' + panelId).prop('hidden', expanded);
441          expanded ? closeAll() : openMenu($btn);
442        }
443
444        /* ----------------------------
445        * Top-level keyboard
446        * ---------------------------- */
447
448        triggers.on('keydown', function (e) {
449          const $current = $(this);
450          const index = triggers.index(this);
451          if (e.code === 'Space' || e.key === ' ') {
452            e.preventDefault();
453            toggleMenu($current);
454          }
455          switch (e.key) {
456            case 'Enter':
457              e.preventDefault();
458              toggleMenu($current);
459              break;
460            case 'ArrowDown':
461              e.preventDefault();
462              openMenu($current);
463              break;
464
465            case 'ArrowRight':
466              e.preventDefault();
467              closeAll();
468              triggers.eq((index + 1) % triggers.length).focus();
469              break;
470
471            case 'ArrowLeft':
472              e.preventDefault();
473              closeAll();
474              triggers.eq((index - 1 + triggers.length) % triggers.length).focus();
475              break;
476
477            case 'Escape':
478              e.preventDefault();
479              closeAll();
480              $current.focus();
481              break;
482          }
483        });
484
485        /* ----------------------------
486        * ESC anywhere inside menu
487        * ---------------------------- */
488        $menu.on('keydown', function (e) {
489          if (e.key === 'Escape') {
490            console.log("escape")
491            triggers.filter('[aria-expanded="true"]').focus();
492            closeAll();
493          }
494        });
495      }
496    }
497  };
498
499})(Drupal, jQuery);

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.