PageSourceSearch

https://www.sport-grosse.de/modules/globalsys/empco/out/src/js/empco-modal.js?v=12

js sport-grosse.de collected 2026-10-05 23:02:38 UTC 5,144 bytes, 166 lines download raw bytes

1(function () {
2  'use strict';
3
4  /**
5   * Erzeugt ein zugängliches Modal (Fokus-Management, ESC, Focus-Trap,
6   * Overlay-Klick, Scroll-Sperre).
7   *
8   * options.overlayId  – ID des Overlays
9   * options.dialogId   – ID der Dialog-Box
10   * options.closeIds   – Array mit IDs von Schließen-Buttons
11   * options.onOpen     – optional: function (triggerElement) {}, wird vor dem Anzeigen aufgerufen
12   */
13  function createModal(options) {
14    var overlay = document.getElementById(options.overlayId);
15    var dialog  = document.getElementById(options.dialogId);
16
17    if (!overlay || !dialog) {
18      return null;
19    }
20
21    var lastFocusedElement = null;
22
23    // Alle fokussierbaren Elemente innerhalb des Dialogs ermitteln
24    function getFocusableElements() {
25      var selectors = [
26        'a[href]',
27        'button:not([disabled])',
28        'textarea:not([disabled])',
29        'input:not([disabled])',
30        'select:not([disabled])',
31        '[tabindex]:not([tabindex="-1"])'
32      ];
33      return Array.prototype.slice.call(
34        dialog.querySelectorAll(selectors.join(','))
35      );
36    }
37
38    function onKeydown(event) {
39      // ESC schließt das Popup
40      if (event.key === 'Escape' || event.key === 'Esc') {
41        event.preventDefault();
42        close();
43        return;
44      }
45
46      // Fokus innerhalb des Dialogs halten (Focus-Trap) via Tab
47      if (event.key === 'Tab') {
48        var focusable = getFocusableElements();
49        if (!focusable.length) return;
50
51        var first = focusable[0];
52        var last  = focusable[focusable.length - 1];
53
54        if (event.shiftKey && document.activeElement === first) {
55          event.preventDefault();
56          last.focus();
57        } else if (!event.shiftKey && document.activeElement === last) {
58          event.preventDefault();
59          first.focus();
60        }
61      }
62    }
63
64    function open(triggerElement) {
65      lastFocusedElement = document.activeElement;
66
67      // Inhalt anpassen, bevor das Modal sichtbar wird
68      if (typeof options.onOpen === 'function') {
69        options.onOpen(triggerElement);
70      }
71
72      overlay.hidden = false;
73      document.body.style.overflow = 'hidden'; // Hintergrund-Scroll verhindern
74
75      // Fokus in den Dialog setzen
76      var focusable = getFocusableElements();
77      if (focusable.length) {
78        focusable[0].focus();
79      } else {
80        dialog.setAttribute('tabindex', '-1');
81        dialog.focus();
82      }
83
84      document.addEventListener('keydown', onKeydown, true);
85    }
86
87    function close(e) {
88      if (e && e.preventDefault) {
89        e.preventDefault();
90      }
91
92      overlay.hidden = true;
93      document.body.style.overflow = '';
94
95      document.removeEventListener('keydown', onKeydown, true);
96
97      // Fokus zurück zum auslösenden Element (wichtig für Tastatur-/Screenreader-Nutzer)
98      if (lastFocusedElement) {
99        lastFocusedElement.focus();
100      }
101    }
102
103    // Klick auf Overlay (außerhalb der Dialog-Box) schließt das Popup
104    overlay.addEventListener('click', function (event) {
105      if (event.target === overlay) {
106        close();
107      }
108    });
109
110    // Schließen-Buttons
111    (options.closeIds || []).forEach(function (id) {
112      var btn = document.getElementById(id);
113      if (btn) {
114        btn.addEventListener('click', close);
115      }
116    });
117
118    return { open: open, close: close };
119  }
120
121  /* ------------------------------------------------------------------
122   * Gewährleistungslabel
123   * ------------------------------------------------------------------ */
124  var warrantyModal = createModal({
125    overlayId: 'euWarrantyOverlay',
126    dialogId:  'euWarrantyDialog',
127    closeIds:  ['euWarrantyClose']
128  });
129
130  if (warrantyModal) {
131    var garanTriggers = document.querySelectorAll('[data-warranty-modal]');
132    Array.prototype.forEach.call(garanTriggers, function (btn) {
133      btn.addEventListener('click', function (e) {
134        e.preventDefault();
135        e.stopPropagation();
136        warrantyModal.open(btn);
137      });
138    });
139  }
140
141  /* ------------------------------------------------------------------
142   * GARAN
143   * ------------------------------------------------------------------ */
144  var garanModal = createModal({
145    overlayId: 'garanOverlay',
146    dialogId:  'garanDialog',
147    closeIds:  ['garanClose'],
148    onOpen: function (trigger) {
149      var data = trigger ? trigger.dataset : {};
150      document.getElementById('garanManufacturer').textContent = data.manufacturer;
151      document.getElementById('garanMpn').textContent = data.mpn;
152      document.getElementById('garanYear').textContent = String(data.year).padStart(2, '0');
153    }
154  });
155
156  if (garanModal) {
157    var garanTriggers = document.querySelectorAll('[data-garan-modal]');
158    Array.prototype.forEach.call(garanTriggers, function (btn) {
159      btn.addEventListener('click', function (e) {
160        e.preventDefault();
161        e.stopPropagation();
162        garanModal.open(btn);
163      });
164    });
165  }
166})();

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.