PageSourceSearch

https://hk-misija-dortmund.de/wp-content/themes/flib/templates/hea…?ver=85120206ead2745fba9a965df04c2131

js hk-misija-dortmund.de collected 2026-10-02 23:39:49 UTC 23,333 bytes, 753 lines download raw bytes

1document.addEventListener('DOMContentLoaded', function () {
2    maxTopNavWidth();
3    realignSubMenu1();
4    menuMaxHeight();
5    pullContent();
6    initializeMenuKeyboardNavigation();
7});
8window.addEventListener('resize', function () {
9    maxTopNavWidth();
10    realignSubMenu1();
11    menuMaxHeight();
12    pullContent();
13});
14window.addEventListener('scroll', function () {
15    menuMaxHeight();
16});
17
18/**
19 * Initialize keyboard navigation for menu buttons
20 * Prevents .open class from being applied during keyboard navigation
21 */
22function initializeMenuKeyboardNavigation() {
23    // Find all menu buttons with onclick handlers
24    const menuButtons = document.querySelectorAll('.menu button[onclick*="openSubMenu"]');
25    
26    menuButtons.forEach(button => {
27        // Add keyboard event listener to prevent .open class during keyboard navigation
28        button.addEventListener('keydown', function(event) {
29            if (event.key === 'Enter' || event.key === ' ') {
30                // Mark this button as activated by keyboard
31                this.setAttribute('data-keyboard-activated', 'true');
32                // Remove the attribute after a short delay to reset for next interaction
33                setTimeout(() => {
34                    this.removeAttribute('data-keyboard-activated');
35                }, 100);
36            }
37        });
38    });
39}
40
41/**
42 * maxTopNavWidth
43 * 
44 * Calculates the maximum width of the top navigation and sets it
45 * 
46 * @return void
47 */
48function maxTopNavWidth() {
49    let header = $('header');
50    if (header.hasClass('full')) {
51        let headerContentInner = header.find('.header-content .header-content-inner');
52        let nav = headerContentInner.find('.menucolumn .menu-wrapper.desktop .menu');
53        let topNav = headerContentInner.children('.topnav');
54        let menuStartPosX = nav.offset().left;
55        let screenWidth = $(window).width();
56        let topNavMaxWidth = screenWidth - menuStartPosX;
57        topNav.css('width', topNavMaxWidth);
58    }
59}
60
61/**
62 * 
63 * toggleSearchDialog
64 * 
65 * Toggles the search dialog in the header
66 * 
67 * @param {*} element The element that was clicked
68 * @returns void
69 */
70function toggleSearchDialog(element) {
71    // If the url contains ?s= and the passed element contains the class="addsearchvariant" and the body contains the class="search-results" do not open the search dialog
72    if (window.location.search.includes('?s=') && element.classList.contains('addsearchvariant') && document.body.classList.contains('search-results')) {
73        // Try to find the search input on the site .addsearch-searchfield input type="search" and focus it
74        let searchInput = document.querySelector('.addsearch-searchfield input[type="search"]');
75        if (searchInput) {
76            searchInput.focus();
77        }
78        // Return to prevent opening the dialog
79        return;
80    }
81
82    let searchWrapper = element.closest('.top-search-wrapper');
83    if (!searchWrapper) {
84        return;
85    }
86
87    let searchDialog = searchWrapper.querySelector('#searchdialog');
88
89    if (searchDialog.open) {
90        searchDialog.close();
91        searchWrapper.classList.remove('open');
92    } else {
93        searchDialog.show();
94        searchWrapper.classList.add('open');
95    }
96
97    // Close by clicking outside the dialog and with the Escape key
98    document.addEventListener('click', function (event) {
99        if (!searchWrapper.contains(event.target) && searchDialog.open) {
100            searchDialog.close();
101            searchWrapper.classList.remove('open');
102        }
103    });
104    document.addEventListener('keydown', function (event) {
105        if (event.key === 'Escape' && searchDialog.open) {
106            searchDialog.close();
107            searchWrapper.classList.remove('open');
108        }
109    });
110}
111
112/**
113 * 
114 * togglePortalsDialog
115 * 
116 * Toggles the portals dialog in the header
117 * 
118 * @param {*} element The element that was clicked
119 * @returns void
120 */
121function togglePortalsDialog(element) {
122    let searchWrapper = element.closest('.top-portals-wrapper');
123    if (!searchWrapper) {
124        return;
125    }
126
127    let searchDialog = searchWrapper.querySelector('#portalsdialog');
128
129    if (searchDialog.open) {
130        searchDialog.close(); 
131        searchWrapper.classList.remove('open');
132    } else {
133        searchDialog.show();
134        searchWrapper.classList.add('open');
135    }
136
137    // Close by clicking outside the dialog and with the Escape key
138    document.addEventListener('click', function (event) {
139        if (!searchWrapper.contains(event.target) && searchDialog.open) {
140            searchDialog.close();
141            searchWrapper.classList.remove('open');
142        }
143    });
144    document.addEventListener('keydown', function (event) {
145        if (event.key === 'Escape' && searchDialog.open) {
146            searchDialog.close();
147            searchWrapper.classList.remove('open');
148        }
149    });
150}
151
152
153/**
154 * 
155 * openSubMenu1
156 * 
157 * Opens the first submenu level
158 * 
159 * @param {*} button  The button that was clicked
160 */
161function openSubMenu1(button) {
162    let pageItemButton = $(button);
163    let pageItem = pageItemButton.parent('.page_item');
164    
165    // Check if this was activated by keyboard
166    let isKeyboardActivation = button.hasAttribute('data-keyboard-activated');
167    
168    pageItem.siblings().removeClass('open');
169    
170    // Only apply open class for mouse interactions, not keyboard navigation
171    if (!isKeyboardActivation) {
172        pageItem.toggleClass('open');
173    }
174}
175
176/**
177 * 
178 * openMobileSubMenu1
179 * 
180 * Opens the first submenu level on mobile devices
181 * 
182 * @param {*} button The button that was clicked
183 */
184function openMobileSubMenu1(button) {
185    let pageItemButton = $(button);
186    let pageItem = pageItemButton.parent('.page_item');
187    pageItem.siblings().removeClass('open');
188    pageItem.siblings().children('.submenu').slideUp(150);
189    pageItem.toggleClass('open');
190    if (pageItem.hasClass('open')) {
191        pageItem.children('.submenu').slideDown(150);
192    } else {
193        pageItem.children('.submenu').slideUp(150);
194    }
195}
196
197/**
198 * 
199 * openSubMenu2
200 * 
201 * Opens the second submenu level on desktop devices
202 * 
203 * @param {*} button The button that was clicked
204 */
205function openSubMenu2(button) {
206    let pageItemButton = $(button);
207    let pageItem = pageItemButton.parent('.page_item');
208    let subMenu = pageItemButton.siblings('.submenu');
209    
210    // Check if this was activated by keyboard
211    let isKeyboardActivation = button.hasAttribute('data-keyboard-activated');
212    
213    // Only apply open class for mouse interactions, not keyboard navigation
214    if (!isKeyboardActivation) {
215        pageItem.toggleClass('open');
216        if (pageItem.hasClass('open')) {
217            subMenu.slideDown(150);
218        } else {
219            subMenu.slideUp(150);
220        }
221    }
222}
223
224/**
225 * 
226 * realignSubMenu1
227 * 
228 * Realigns the first submenu level to the right if it runs off the right edge of the menu
229 * 
230 * @returns void
231 */
232function realignSubMenu1() {
233    // find the menu container
234    const menu = document.querySelector('.header-content-inner nav.menu');
235    if (!menu) return;
236  
237    // how far right the menu itself goes
238    const menuRect = menu.getBoundingClientRect();
239    const menuRight = menuRect.left + menuRect.width;
240  
241    // for each top‐level page_item
242    menu.querySelectorAll(':scope > .page_item').forEach(pageItem => {
243      const subMenu = pageItem.querySelector(':scope > .submenu');
244      if (!subMenu) return;
245  
246      // reset any old overflow-logic
247      subMenu.classList.remove('submenu_alignright', 'centered');
248  
249      // if the submenu would run off the right edge, flip it left
250      const rect = subMenu.getBoundingClientRect();
251      if (rect.left + rect.width > menuRight) {
252        subMenu.classList.add('submenu_alignright');
253      }
254  
255      // **always** drop it exactly 27px below the parent
256      subMenu.style.top    = '';
257      subMenu.style.bottom = '-27px';
258    });
259}
260
261/**
262 * 
263 * responsiveMenu
264 * 
265 * Checks if the menu fits into the header and switches between full and burger menu
266 * 
267 * @return void
268 */
269function responsiveMenu() {
270    let menuType = '';
271    let windowWidth = $(window).width();
272    $(window).on('load', function () {
273        menuType = checkMenuSizes(menuType);
274    });
275    $(window).resize(function () {
276        if (windowWidth != $(window).width()) {
277            windowWidth = $(window).width();
278            menuType = checkMenuSizes(menuType);
279        }
280    });
281}
282/* Responsive Menu */
283responsiveMenu();
284
285/**
286 * 
287 * checkMenuSizes
288 * 
289 * Checks if the menu fits into the header and switches between full and burger menu
290 * Trigger: Inline in the header-content.php when the font is loaded, when the page is fully loaded, window.resize()
291 * 
292 * @param {*} menuType 
293 * @returns string menuType 
294 */
295function checkMenuSizes(menuType) {
296    const header = document.querySelector('header');
297    header.classList.remove('burger');
298
299    const headerContentInner = document.querySelector('.header-content-inner');
300    const headerContentInnerWidth = headerContentInner.offsetWidth - 60;
301
302    const menuCalcMaxWidth = (headerContentInnerWidth * 0.82) - 90 + 5;
303
304    const menu = headerContentInner.querySelector('.menu-wrapper.desktop .menu');
305    let menuInnerWidth = 0;
306
307    const pageItems = Array.from(menu.children).filter(el => el.classList.contains('page_item'));
308
309    pageItems.forEach((item) => {
310        const itemWidth = Math.ceil(item.offsetWidth);
311        menuInnerWidth += itemWidth;
312    });
313
314    if (menuInnerWidth < 800) {
315        menuInnerWidth = 800;
316    }
317
318    // Force mobile menu at 1200px or below
319    if (window.innerWidth <= 1200 || parseInt(menuInnerWidth) > parseInt(menuCalcMaxWidth)) {
320        menuType = switchMenu(menuType, 'burger');
321        header.classList.add('burger');
322        document.querySelectorAll('.search-menu').forEach(el => el.style.display = 'flex');
323        
324        // Update tabindex when switching to burger mode
325        updateNavigationTabindex();
326    } else {
327        menuType = switchMenu(menuType, 'full');
328        document.querySelectorAll('.search-menu').forEach(el => el.style.display = 'none');
329        
330        // Update tabindex when switching to full mode  
331        updateNavigationTabindex();
332    }
333
334    return menuType;
335}
336
337/**
338 * 
339 * switchMenu
340 * 
341 * Switches between the full and burger menu
342 * 
343 * @param {*} menuType The current menu type
344 * @param {*} targetType The target menu type
345 * @returns string menuType
346 */
347function switchMenu(menuType, targetType) {
348    if (menuType !== targetType) {
349        let header = $('header');
350        let desktopMenu = header.find('.menu-wrapper.desktop .menu');
351        if (targetType == 'burger') {
352            desktopMenu.css('max-width', desktopMenu.outerWidth());
353        } else {
354            desktopMenu.css('max-width', 'inherit');
355        }
356        header.removeClass('burger');
357        header.removeClass('full');
358        header.addClass(targetType);
359        menuType = targetType;
360        pullContent();
361    }
362    return menuType;
363}
364
365/**
366 * pullContent
367 * 
368 * Function to pull the content down to the header if the header is full
369 * 
370 * @return void
371 */
372function pullContent() {
373    // If body does not contain the class "is-template1" exit function early
374    if (!document.body.classList.contains('is-template1')) {
375        return;
376    }
377
378    setTimeout(function () {
379        let header = $('header');
380        let headerPlaceholder = document.getElementsByClassName('header-placeholder')[0];
381        if (header.hasClass('full')) {
382            let headerHeight = header.outerHeight();
383            let firstPageElement = $('.page-element-1');
384            if (firstPageElement.length > 0) {
385                let firstPageElementClasses = firstPageElement.attr('class').split(" ");
386                let pageElementsOfEffect = [
387                    'slider',
388                    'video_slider',
389                    'header_image',
390                    'slider_2'
391                ];
392
393                $(pageElementsOfEffect).each(function (key, value) {
394                    if (firstPageElementClasses.indexOf(value) >= 0) {
395                        header.css('margin-bottom', -headerHeight);
396                        if (headerPlaceholder) {
397                            headerPlaceholder.style.marginBottom = -headerHeight + "px";
398                        }               
399                    }
400                });
401            }
402        } else {
403            header.css('margin-bottom', 0);
404        }
405    }, 150);
406}
407
408/**
409 * 
410 * openMobileMenu
411 * 
412 * Opens the mobile menu and toggles the menu wrapper
413 * 
414 * @param {*} button The button that was clicked
415 * 
416 * @return void
417 */
418function openMobileMenu(button) {
419    let burgerButton = document.querySelector('.logo-search-menu .burger');
420
421    // toggle open class on button
422    burgerButton.classList.toggle('open');
423
424    const menuWrapper = document.querySelector('.menu-wrapper.mobile');
425    const menu = menuWrapper.querySelector('.menu');
426
427    menuWrapper.classList.toggle('open');
428
429    if (menuWrapper.classList.contains('open')) {
430        menu.style.display = 'flex';
431        menu.style.transition = 'max-height 0.15s ease-in-out';
432        menu.style.maxHeight = menu.scrollHeight + 'px';
433    } else {
434        menu.style.transition = 'max-height 0.15s ease-in-out';
435        menu.style.maxHeight = '0';
436        setTimeout(() => {
437            menu.style.display = 'none';
438        }, 150);
439    }
440
441    menuMaxHeight();
442}
443
444/**
445 * 
446 * updateNavigationTabindex
447 * 
448 * Updates tabindex for mobile and desktop navigation based on menu mode
449 * When in burger mode: mobile items get tabindex="0", desktop items get tabindex="-1"
450 * When in full mode: mobile items get tabindex="-1", desktop items get tabindex="0"
451 * 
452 * @return void
453 */
454function updateNavigationTabindex() {
455    const header = document.querySelector('header');
456    const isBurgerMode = header && header.classList.contains('burger');
457    
458    // Find mobile menu items
459    const mobileMenuItems = document.querySelectorAll('.menu-wrapper.mobile .menu a, .menu-wrapper.mobile .menu button');
460    
461    // Find desktop menu items  
462    const desktopMenuItems = document.querySelectorAll('.menu-wrapper.desktop .menu a, .menu-wrapper.desktop .menu button');
463    
464    // Update mobile menu items
465    mobileMenuItems.forEach(item => {
466        item.setAttribute('tabindex', isBurgerMode ? '0' : '-1');
467    });
468    
469    // Update desktop menu items (opposite of mobile)
470    desktopMenuItems.forEach(item => {
471        item.setAttribute('tabindex', isBurgerMode ? '-1' : '0');
472    });
473}
474
475/**
476 * 
477 * openMobileSearch
478 * 
479 * Opens the mobile search and toggles the search wrapper
480 * 
481 * @param {*} button The button that was clicked
482 */
483function openMobileSearch(button) {
484    // If the url contains ?s= and the passed button contains the class="addsearchvariant" and the body contains the class="search-results" do not open the search dialog
485    if (window.location.search.includes('?s=') && button.classList.contains('addsearchvariant') && document.body.classList.contains('search-results')) {
486        // Try to find the search input on the site .addsearch-searchfield input type="search" and focus it
487        let searchInput = document.querySelector('.addsearch-searchfield input[type="search"]');
488        if (searchInput) {
489            searchInput.focus();
490        }
491        // Return to prevent opening the dialog
492        return;
493    }
494
495    const mobilesearch = button.closest('.mobilesearch');
496    // Find **either** the #searchform **or** the AddSearch wrapper:
497    const searchContainer = mobilesearch.querySelector('#searchform, .addsearch-wrapper');
498    const searchInput = searchContainer.querySelector('input[type="search"], input[type="text"]');
499
500    if (!searchContainer) {
501      return;
502    }
503  
504    // Toggle open/closed
505    if (mobilesearch.classList.contains('open')) {
506        mobilesearch.classList.remove('open');
507        searchContainer.style.zIndex = '';
508        document.body.removeEventListener('mousedown', handleOutsideClick);
509    } else {
510        mobilesearch.classList.add('open');
511        searchContainer.style.zIndex = '2';
512
513        // Focus the search input
514        if (searchInput) {
515            searchInput.focus();
516        }
517  
518        // Give the browser a tick so the opening click doesn’t immediately trigger our outside-click handler
519        setTimeout(() => {
520            document.body.addEventListener('mousedown', handleOutsideClick);
521        }, 0);
522    }
523  
524    /**
525     * 
526     * handleOutsideClick
527     * 
528     * Handles clicks outside the mobile search dialog
529     * 
530     * @param {*} e The click event 
531     */
532    function handleOutsideClick(e) {
533      // If click is _not_ inside the .mobilesearch **and** not inside the AddSearch dropdown
534      const isInMobilesearch = mobilesearch.contains(e.target);
535      const acDropdown = document.querySelector('[id^="addsearch-ac"]');
536      const isInAddsearchAC = acDropdown && acDropdown.contains(e.target);
537  
538      if (!isInMobilesearch && !isInAddsearchAC) {
539        mobilesearch.classList.remove('open');
540        searchContainer.style.zIndex = '';
541        document.body.removeEventListener('mousedown', handleOutsideClick);
542      }
543    }
544}
545
546/**
547 * 
548 * useMobileSearch
549 * 
550 * Uses the mobile search and redirects to the search page with the search input
551 * 
552 * @returns void
553 */
554function useSearch(event, element) {
555    // prevent default action of form submission
556    event.preventDefault();
557
558    // get the search input value from the parent element of the clicked element
559    const searchInputElement = element.parentElement.querySelector('.search-field');
560    const searchInput = searchInputElement ? searchInputElement.value : '';
561
562    // If the search input is empty, do not redirect
563    if (searchInput === '') {
564        return false;
565    }
566
567    // Get the current URL origin
568    const url = window.location.origin;
569
570    // Redirect to the search page with the search input as a query parameter
571    window.location.href = `${url}?s=${encodeURIComponent(searchInput)}&search=${encodeURIComponent(searchInput)}`;
572}
573
574// Helper function to handle clicks on the logo container
575function handleLogoContainerClick() {
576    const logoContainers = document.querySelectorAll('.logo-container');
577    logoContainers.forEach(container => {
578        container.addEventListener('click', function (e) {
579            if (!e.target.closest('.logo')) {
580                e.preventDefault();
581            }
582        });
583    });
584}
585document.addEventListener('DOMContentLoaded', function () {
586    handleLogoContainerClick();
587});
588
589/**
590 * 
591 * toggleSmallHeader
592 * 
593 * Adds a class to the header to make it display smaller
594 * 
595 * @param {*} distanceScrolled The distance scrolled from the top of the page
596 * @returns void
597 */
598function toggleSmallHeader(distanceScrolled) {
599
600    // Vars
601    let header = document.getElementsByTagName('header')[0];
602    let headerPlaceholder = document.getElementsByClassName('header-placeholder')[0];
603
604    // Cancel if not all conditions for a scrolling header are met
605    if (!isHeaderScrollable(header, headerPlaceholder)) {
606        return false;
607    }
608
609    // If the scroll distance is higher than the header placeholder, add the class "scrolled", otherwise leave it as unscrolled
610    if (distanceScrolled > header.offsetHeight) {
611        header.classList.add('scrolled');
612        header.classList.remove('unscrolled');
613    } else {
614        header.classList.remove('scrolled');
615        header.classList.add('unscrolled');
616    }
617}
618window.onscroll = function(e) {
619
620    // Vars
621    let distanceScrolled = document.documentElement.scrollTop;
622
623    // Adds a class to the header to make it display smaller
624    toggleSmallHeader(distanceScrolled);
625
626}
627
628/**
629 * 
630 * resizeHeaderPlaceholder
631 * 
632 * Adjusts the size of the header placeholder to match the header
633 * 
634 * @returns void
635 */
636function resizeHeaderPlaceholder() {
637    // Vars
638    let header = document.getElementsByTagName('header')[0];
639    let headerPlaceholder = document.getElementsByClassName('header-placeholder')[0];
640
641    // Cancel if not all conditions for a scrolling header are met
642    if (!isHeaderScrollable(header, headerPlaceholder)) {
643        return false;
644    }
645
646    let headerHeight = header.offsetHeight;
647
648    // On mobile, ensure a minimum height for the placeholder
649    if (window.innerWidth <= 1200 && headerHeight < 90) {
650        headerHeight = 90;
651    }
652
653    // Set the size of the placeholder
654    headerPlaceholder.style.height = headerHeight + "px";
655
656}
657document.addEventListener('DOMContentLoaded', function () {
658
659    // Vars
660    let header = document.getElementsByTagName('header')[0];
661    let logo = document.querySelector('.logo-column img');
662
663    // Add unscrolled class initially if header exists
664    if (header) {
665        header.classList.add('unscrolled');
666    }
667
668    // Adjusts the size of the header placeholder to match the header
669    resizeHeaderPlaceholder();
670
671    // Adjusts the size of the header placeholder to match the header once the logo has loaded
672    if(logo !== null) {
673        logo.onload = function(e) {
674            resizeHeaderPlaceholder();
675        }
676    }
677
678});
679window.onresize = function(e) {
680    // Adjusts the size of the header placeholder to match the header
681    resizeHeaderPlaceholder();
682}
683
684/**
685 * 
686 * isHeaderScrollable
687 * 
688 * Checks if the header is scrollable
689 * 
690 * @param {*} header The header element
691 * @param {*} headerPlaceholder The header placeholder element
692 * @returns boolean True if the header is scrollable, false if not
693 */
694function isHeaderScrollable(header, headerPlaceholder) {
695
696    // Cancel if there is no header
697    if (!header) {
698        return false;
699    }
700
701    // Cancel if the header should not scroll along
702    if (!header.classList.contains('scrollable')) {
703        return false;
704    }
705
706    // Cancel if there is no placeholder
707    if (!headerPlaceholder) {
708        return false;
709    }
710
711    return true;
712}
713
714/**
715* 
716* menuMaxHeight
717* 
718* Sets the maximum height of the mobile menu to the window height minus the menu's top offset
719* 
720* @returns void
721*/
722function menuMaxHeight() {
723    // Vars
724    let header = document.getElementsByTagName('header')[0];
725    let headerPlaceholder = document.getElementsByClassName('header-placeholder')[0];
726    let menu = document.querySelector('.menu-wrapper.mobile .menu');
727    let menuYOffset = menu.getBoundingClientRect().y;
728    let windowHeight = window.innerHeight;
729    let maxMenuHeight = 0;
730
731    // Cancel if there is no header or menu
732    if (!header || !menu) {
733        return false;
734    }
735
736    // For scrollable headers, use the original logic
737    if (isHeaderScrollable(header, headerPlaceholder)) {
738        // Subtract the top distance of the menu from the browser height
739        if (windowHeight && windowHeight > 0 && menuYOffset && menuYOffset > 0) {
740            maxMenuHeight = windowHeight - menuYOffset;
741        }
742    } else {
743        // For non-scrollable headers, calculate max height to prevent content overflow
744        if (windowHeight && windowHeight > 0 && menuYOffset && menuYOffset > 0) {
745            // Subtract a small buffer to prevent viewport overflow
746            maxMenuHeight = windowHeight - menuYOffset - 20;
747        }
748    }
749
750    if (maxMenuHeight && maxMenuHeight > 0) {
751        menu.style.maxHeight = maxMenuHeight+"px";
752    }
753}

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.