PageSourceSearch

https://www.leonhard-frank-schule.de/themes/custom/inklusion/js/navigation.js?tlv9pz

js leonhard-frank-schule.de collected 2026-10-03 18:42:06 UTC 5,484 bytes, 169 lines download raw bytes

1(function (Drupal, once) {
2  Drupal.behaviors.inklusionNavigation = {
3    attach(context) {
4      once('inklusion-navigation', '.nav-toggle', context).forEach((button) => {
5        const navId = button.getAttribute('aria-controls');
6        const nav = navId ? document.getElementById(navId) : null;
7        if (!nav) {
8          return;
9        }
10
11        const originalParent = nav.parentNode;
12        const placeholder = document.createComment('primary-navigation-placeholder');
13        originalParent.insertBefore(placeholder, nav);
14        let restoreTimer = null;
15
16        const isOffCanvasViewport = () => window.matchMedia('(max-width: 991.98px)').matches;
17
18        // Eigene Kopfzeile für den portalierten Off-Canvas-Drawer. Der
19        // ursprüngliche Toggle verbleibt im Header; im geöffneten Drawer
20        // steht zusätzlich ein gut erreichbarer Schließen-Button bereit.
21        let drawerHeader = nav.querySelector('.offcanvas-navigation__header');
22        if (!drawerHeader) {
23          drawerHeader = document.createElement('div');
24          drawerHeader.className = 'offcanvas-navigation__header';
25
26          const drawerClose = document.createElement('button');
27          drawerClose.className = 'offcanvas-navigation__close';
28          drawerClose.type = 'button';
29          drawerClose.setAttribute('aria-label', Drupal.t('Menü schließen'));
30          drawerClose.innerHTML = '<span>Menü</span><span class="offcanvas-navigation__close-icon" aria-hidden="true"></span>';
31
32          drawerHeader.append(drawerClose);
33          nav.prepend(drawerHeader);
34        }
35
36        const moveToBody = () => {
37          if (nav.parentNode !== document.body) {
38            document.body.appendChild(nav);
39          }
40          nav.classList.add('is-offcanvas-navigation');
41        };
42
43        const restoreToHeader = () => {
44          window.clearTimeout(restoreTimer);
45          if (nav.parentNode !== originalParent) {
46            originalParent.insertBefore(nav, placeholder.nextSibling);
47          }
48          nav.classList.remove('is-offcanvas-navigation');
49        };
50
51        const open = () => {
52          if (!isOffCanvasViewport()) {
53            return;
54          }
55          window.clearTimeout(restoreTimer);
56          moveToBody();
57          // Ein Frame Abstand stellt sicher, dass der Browser den geschlossenen
58          // Drawer zuerst layoutet und anschließend sichtbar animiert.
59          window.requestAnimationFrame(() => {
60            window.requestAnimationFrame(() => {
61              nav.classList.add('is-open');
62              document.documentElement.classList.add('nav-is-open');
63              button.setAttribute('aria-expanded', 'true');
64            });
65          });
66        };
67
68        const close = ({ immediate = false } = {}) => {
69          nav.classList.remove('is-open');
70          document.documentElement.classList.remove('nav-is-open');
71          button.setAttribute('aria-expanded', 'false');
72
73          if (immediate) {
74            restoreToHeader();
75            return;
76          }
77
78          restoreTimer = window.setTimeout(restoreToHeader, 500);
79        };
80
81        const toggle = () => {
82          if (nav.classList.contains('is-open')) {
83            close();
84          }
85          else {
86            open();
87          }
88        };
89
90        button.addEventListener('click', (event) => {
91          event.preventDefault();
92          event.stopPropagation();
93          toggle();
94        });
95
96        const drawerClose = drawerHeader.querySelector('.offcanvas-navigation__close');
97        if (drawerClose) {
98          drawerClose.addEventListener('click', (event) => {
99            event.preventDefault();
100            close();
101            button.focus();
102          });
103        }
104
105        nav.addEventListener('click', (event) => {
106          const link = event.target.closest('a');
107          if (link && isOffCanvasViewport()) {
108            close();
109          }
110        });
111
112        document.addEventListener('click', (event) => {
113          if (!nav.classList.contains('is-open')) {
114            return;
115          }
116          if (nav.contains(event.target) || button.contains(event.target)) {
117            return;
118          }
119          close();
120        });
121
122        document.addEventListener('keydown', (event) => {
123          if (event.key === 'Escape' && nav.classList.contains('is-open')) {
124            close();
125            button.focus();
126          }
127        });
128
129        window.addEventListener('resize', () => {
130          if (!isOffCanvasViewport()) {
131            close({ immediate: true });
132          }
133        });
134      });
135
136	once('inklusion-scroll-header', 'body', context).forEach(() => {
137	  const documentElement = document.documentElement;
138
139	  // Hysterese verhindert das Flackern des kompakten Headers.
140	  const compactHeaderStart = 80;
141	  const compactHeaderEnd = 20;
142
143	  let isCompact = documentElement.classList.contains('site-is-scrolled');
144
145	  const updateHeaderState = () => {
146		const scrollPosition =
147		  window.scrollY ||
148		  document.documentElement.scrollTop ||
149		  0;
150
151		if (!isCompact && scrollPosition >= compactHeaderStart) {
152		  isCompact = true;
153		  documentElement.classList.add('site-is-scrolled');
154		}
155		else if (isCompact && scrollPosition <= compactHeaderEnd) {
156		  isCompact = false;
157		  documentElement.classList.remove('site-is-scrolled');
158		}
159	  };
160
161	  updateHeaderState();
162
163	  window.addEventListener('scroll', updateHeaderState, {
164		passive: true,
165	  });
166	});
167    }
168  };
169})(Drupal, once);

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.