PageSourceSearch

https://buergerportal.steinhagen.de/o/bot-theme/js/classes/headerExtendedMenuClass.js

js steinhagen.de collected 2026-09-25 04:00:24 UTC 9,240 bytes, 287 lines download raw bytes

1class HeaderExtendedMenuClass {
2  mobileNavIsOpen = false;
3  mobileNavFocusedItem = undefined;
4  /**
5   * @param mobileNavMenuId string nav-element
6   * @param mobileNavMenuButtonID string button im nav-element
7   * @param mobileNavMenuListWrapper
8   * @param mobileNavMenuList string liste im nav-element
9   * @param mobileNavMenuListElements string listen-elemente in der liste
10   * @param mobileNavMenuListElementLinks string links in den listen-elementen
11   */
12  constructor(
13    mobileNavMenuId,
14    mobileNavMenuButtonID,
15    mobileNavMenuListWrapper,
16    mobileNavMenuList,
17    mobileNavMenuListElements,
18    mobileNavMenuListElementLinks,
19  ) {
20    this.mobileNavMenuId = mobileNavMenuId;
21    this.mobileNavMenuButtonID = mobileNavMenuButtonID;
22    this.mobileNavMenuListWrapper = mobileNavMenuListWrapper;
23    this.mobileNavMenuList = mobileNavMenuList;
24    this.mobileNavMenuListElements = mobileNavMenuListElements;
25    this.mobileNavMenuListElementLinks = mobileNavMenuListElementLinks;
26    this.firstMenuItemChars = [];
27    this.currentSelectedMenuItemIndex = 0;
28    this.fillFirstMenuItemChars();
29    this.startListener();
30    this.setLastMobileNavFocusedItem(
31      $(this.mobileNavMenuListElements + ":first-child a"),
32    );
33  }
34  /**
35   * @name startListener
36   * @description Startet alle Listener
37   */
38  startListener() {
39    let that = this;
40    $(that.mobileNavMenuButtonID).on("click", function (e) {
41      that.toggleMobileNavMenu();
42    });
43
44    $(that.mobileNavMenuButtonID).on("keydown", function (e) {
45      if (e.keyCode === 13 || e.keyCode === 32) {
46        e.preventDefault();
47        e.stopPropagation();
48        that.toggleMobileNavMenu();
49      }
50    });
51
52    $(document).on("click", function () {
53      if (that.menuIsVisible() && !that.isFocusInMenu()) {
54        that.closeMobileNavMenu();
55      }
56    });
57
58    $(document).on("keydown", function (e) {
59      if (that.menuIsVisible() && that.isFocusInMenu()) {
60        let currentItem = "";
61        let nextItem = "";
62        let prevItem = "";
63        switch (e.keyCode) {
64          case 13: //Enter
65          case 32: //Space
66            // Öffnet den aktuellen Menüpunkt
67            e.preventDefault();
68            $(that.mobileNavMenuListElementLinks + "[tabindex=0]")[0].click();
69            break;
70          case 38: //ArrowUp
71            // Fokussiert den vorherigen Menüpunkt
72            e.preventDefault();
73            currentItem = $(
74              that.mobileNavMenuListElementLinks + "[tabindex=0]",
75            );
76            prevItem = currentItem.parent().prev().find("a");
77            if (prevItem.length === 1) {
78              that.setMenuItemFocus(prevItem);
79            } else {
80              // Fokussiert den letzten Menüpunkt wenn der Anfang der Liste erreicht ist
81              that.setMenuItemFocus(
82                $(that.mobileNavMenuListElements + ":last-child a"),
83              );
84            }
85            break;
86          case 40: //ArrowDown
87            // Fokussiert den nächsten Menüpunkt
88            e.preventDefault();
89            currentItem = $(
90              that.mobileNavMenuListElementLinks + "[tabindex=0]",
91            );
92            nextItem = currentItem.parent().next().find("a");
93            if (nextItem.length === 1) {
94              that.setMenuItemFocus(nextItem);
95            } else {
96              // Fokussiert den letzten Menüpunkt wenn das ende der Liste erreicht ist
97              that.setMenuItemFocus(
98                $(that.mobileNavMenuListElements + ":first-child a"),
99              );
100            }
101            break;
102          case 36: //Home
103            // Fokussiert den ersten Menüpunkt
104            e.preventDefault();
105            that.setMenuItemFocus(
106              $(that.mobileNavMenuListElements + ":first-child a"),
107            );
108            break;
109          case 35: //END
110            // Fokussiert den letzten Menüpunkt
111            e.preventDefault();
112            that.setMenuItemFocus(
113              $(that.mobileNavMenuListElements + ":last-child a"),
114            );
115            break;
116          case 27: //ESC
117            //Schließt das Menü
118            e.preventDefault();
119            that.closeMobileNavMenu();
120            break;
121          default:
122            //Prüft ob die gedrücke Taste mit einem Anfangsbuchstaben der Menüpunkte übereinstimmt
123            that.setFocusByChar(e.key);
124            break;
125        }
126      }
127    });
128  }
129
130  setLastMobileNavFocusedItem(item) {
131    this.mobileNavFocusedItem = item;
132  }
133
134  /**
135   * @name fillFirstMenuItemChars
136   * @description Setzt alle Anfangsbuchstaben der Menüpunkte in ein Array.
137   */
138  fillFirstMenuItemChars() {
139    let that = this;
140    $(this.mobileNavMenuListElementLinks).each(function (index, value) {
141      let char = "";
142      if ($(value).text().trim() !== "") {
143        char = $(value).text().trim().substr(0, 1).toLowerCase();
144      } else {
145        char = $(value).attr("title").trim().substr(0, 1).toLowerCase();
146      }
147      that.firstMenuItemChars.push(char);
148    });
149  }
150
151  /**
152   * @name isFocusInMenu
153   * @description Prüft ob der aktuelle Fokus in Menü liegt.
154   * @returns {boolean}
155   */
156  isFocusInMenu() {
157    return $(this.mobileNavMenuList).find($(":focus")).length === 1;
158  }
159
160  /**
161   * @name menuIsVisible
162   * @description Prüft ob das Menü offen ist.
163   * @returns {boolean}
164   */
165  menuIsVisible() {
166    return (
167      $(this.mobileNavMenuButtonID).attr("aria-expanded") === true ||
168      $(this.mobileNavMenuButtonID).attr("aria-expanded") === "true"
169    );
170  }
171
172  /**
173   * @name toggleMobileNavMenu
174   * @description "Steuert" das öffnen und schließen des Menüs.
175   */
176  toggleMobileNavMenu() {
177    if (this.menuIsVisible()) {
178      this.closeMobileNavMenu();
179    } else if (!this.menuIsVisible()) {
180      this.openMobileNavMenu();
181    }
182  }
183
184  /**
185   * @name setMenuItemFocus
186   * @description Setzt den Fokus und setzt die Attribute an den Menüpunkten.
187   * @param element
188   */
189  setMenuItemFocus(element) {
190    this.currentSelectedMenuItemIndex = $(
191      this.mobileNavMenuListElementLinks,
192    ).index($(element));
193    $(this.mobileNavMenuList + " li a").attr("tabindex", -1);
194    $(element).attr("tabindex", 0);
195    $(element).focus();
196    this.setLastMobileNavFocusedItem($(element));
197  }
198
199  /**
200   * @name openMobileNavMenu
201   * @description Öffnet das Menü und setzt die Attribute am Button.
202   */
203  openMobileNavMenu() {
204    $(this.mobileNavMenuList).removeClass("mobileClosed");
205    this.autoHeightAnimate($(this.mobileNavMenuListWrapper), 500);
206    this.mobileNavIsOpen = true;
207    $(this.mobileNavMenuButtonID).attr("aria-expanded", true);
208    $(this.mobileNavMenuId).data("menu-open", true);
209    $(this.mobileNavFocusedItem).attr("tabindex", 0);
210    $(this.mobileNavMenuButtonID).attr("aria-label", "Menü schließen");
211    this.setMenuItemFocus(
212      $(this.mobileNavMenuListElementLinks + "[tabindex=0]"),
213    );
214  }
215
216  /**
217   * @name closeMobileNavMenu
218   * @description Schließt das Menü und setzt die Attribute am Button.
219   */
220  closeMobileNavMenu() {
221    let that = this;
222    $(that.mobileNavMenuListWrapper)
223      .stop()
224      .animate({ height: "0" }, 500, function () {
225        $(that.mobileNavMenuList).addClass("mobileClosed");
226        $(that.mobileNavMenuButtonID).attr("aria-expanded", false);
227        $(this.mobileNavMenuId).data("menu-open", false);
228        that.mobileNavIsOpen = false;
229        $(that.mobileNavMenuList + " li a").attr("tabindex", -1);
230        $(that.mobileNavMenuButtonID).focus();
231        $(this.mobileNavMenuButtonID).attr("aria-label", "Menü öffnen");
232      });
233  }
234
235  /**
236   * @name setFocusByChar
237   * @description Setzt den Fokus an den nächsten Menüpunkt der mit dem gegebenen Buchstaben beginnt.
238   * @param char
239   */
240  setFocusByChar(char) {
241    if (
242      this.firstMenuItemChars.indexOf(char) !== -1 &&
243      this.firstMenuItemChars !== []
244    ) {
245      let length = $(this.mobileNavMenuListElementLinks).length;
246      let rest = length - this.currentSelectedMenuItemIndex;
247      for (let i = this.currentSelectedMenuItemIndex + 1; i < length; i++) {
248        if (
249          $(this.mobileNavMenuListElementLinks)
250            [i].text.trim()
251            .substr(0, 1)
252            .toLowerCase() === char ||
253          $(this.mobileNavMenuListElementLinks)
254            [i].title.trim()
255            .substr(0, 1)
256            .toLowerCase() === char
257        ) {
258          this.setMenuItemFocus($(this.mobileNavMenuListElementLinks)[i]);
259          return;
260        }
261      }
262      for (let i = 0; i < length - rest + 1; i++) {
263        if (
264          $(this.mobileNavMenuListElementLinks)
265            [i].text.trim()
266            .substr(0, 1)
267            .toLowerCase() === char ||
268          $(this.mobileNavMenuListElementLinks)
269            [i].title.trim()
270            .substr(0, 1)
271            .toLowerCase() === char
272        ) {
273          this.setMenuItemFocus($(this.mobileNavMenuListElementLinks)[i]);
274          return;
275        }
276      }
277    }
278  }
279
280  autoHeightAnimate(element, time) {
281    let currentHeight = element.height();
282    let autoHeight = element.css("height", "auto").height();
283
284    element.height(currentHeight);
285    element.stop().animate({ height: autoHeight }, time);
286  }
287}

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.