PageSourceSearch

https://t3bootstrap.de/_assets/b15aa46bd0e2bbd3ef8f7195b7ef9867/JavaScript/main.js?1781740154

js t3bootstrap.de collected 2026-09-30 09:41:05 UTC 15,937 bytes, 547 lines download raw bytes

1let App = function () {
2
3
4  function initBootstrap() {
5
6    $('[data-bs-toggle="tooltip"]').tooltip();
7    $('[data-bs-toggle="popover"]').popover();
8
9
10    if ($('.navbar-onepage').length > 0) {
11      $('body').scrollspy({target: $('.navbar-onepage'), offset: ($('#nav-main').height() + 21)});
12    }
13
14  }
15
16  function initLightbox() {
17
18    if (typeof GLightbox === 'undefined') return;
19    /* Config is now embedded as a non-executable <script type="application/json">
20       block (see EXT:template/Configuration/TypoScript/HTML/Components/glightbox.typoscript)
21       so it doesn't need a CSP nonce. Fall back to {} if the block is missing
22       (page that doesn't include the lightbox lib for whatever reason). */
23    let lightboxParams = {};
24    const configEl = document.getElementById('t3b-lightbox-config');
25    if (configEl) {
26      try { lightboxParams = JSON.parse(configEl.textContent || '{}'); } catch (e) {
27        console.warn('t3bootstrap: failed to parse GLightbox config', e);
28      }
29    }
30    /* fix for missing title attribute in lightbox a tags */
31    $('.lightbox').each(function () {
32      if (this.title === '') {
33        $(this).attr('title', $("img", $(this)).attr('title'));
34      }
35      const parents = $(this).parents('figure');
36      if (parents.length > 0) {
37        if ($('.image-caption span.description', parents.get(0)).length > 0) {
38          $(this).attr('data-description', $('.image-caption span.description', parents.get(0)).html());
39        }
40      }
41
42    });
43
44    const lightbox = GLightbox(lightboxParams);
45    lightbox.on('open', () => {
46
47    });
48    lightbox.on('close', () => {
49
50    });
51
52  }
53
54  function initCountdown() {
55    if (typeof FlipDown === 'undefined') return;
56
57    $('.countdown').each(function () {
58      $(this).addClass('flipdown');
59      let date = $(this).attr('data-endtime');
60      let theme = $(this).attr('data-theme');
61      if (theme === undefined || theme == '') {
62        theme = 'dark';
63      }
64      new FlipDown(parseInt(date), $(this).attr('id'), {theme:theme}).start();
65    });
66  }
67
68  function initHeader() {
69
70    if ($('.navbar-meta').length > 0 && $('.page-header--layout-4').length == 0 && $('.page-header--layout-2').length == 0 && $('.navbar-brand').position().top != $('.navbar-meta').position().top && $('.page-header.sticky-top').length > 0) {
71
72      let userNavbarHeight = $('.navbar-meta').height();
73      $(window).scroll(function () {
74        if (document.documentElement.scrollTop > 100) {
75          $('.page-header').addClass('page-header--shrinked');
76        } else if (document.documentElement.scrollTop < 100 - userNavbarHeight - 5) {
77          $('.page-header').removeClass('page-header--shrinked');
78        }
79      });
80    }
81
82  }
83
84
85  function initEqualHeight() {
86
87    if (typeof $('body').matchHeight() === 'undefined') return;
88    $('.equal-height').matchHeight({
89      byRow: true,
90      property: 'min-height'
91    });
92    $('.ce-header').matchHeight({
93      byRow: true,
94      property: 'min-height'
95    });
96
97    $('.frame-type-card .card').matchHeight({
98      byRow: true,
99      property: 'min-height'
100    });
101
102  }
103
104  function initSmoothScroll() {
105
106    /* from here on only for one pager */
107    if ($('.navbar-onepage').length === 0) return;
108
109    /* one page: link on logo */
110    $('.navbar-onepage .navbar-brand a').on('click', function (event) {
111      event.preventDefault();
112      $('html, body').animate({
113        scrollTop: 0
114      }, 800, function () {
115
116      });
117    });
118
119    /* close nav */
120    $('.nav-onepage a').on('click', function (event) {
121      $(this).closest('.navbar-collapse.show').collapse('hide');
122    });
123
124  }
125
126  function initAjaxModals() {
127
128    var modalTemplate = jQuery('<div class="modal fade" id="ajax-modal" tabindex="-1" role="dialog" aria-labelledby="ajaxModalLabel" aria-hidden="true">\n' +
129      ' <div class="modal-dialog" role="document">\n' +
130      ' <div class="modal-content">\n' +
131      ' <div class="modal-header">\n' +
132      ' <p class="fs-h5 modal-title" id="ajaxModalLabel"></p>\n' +
133      ' <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>\n' +
134      ' </div>\n' +
135      ' <div class="modal-text"></div>\n' +
136      ' <div class="modal-body">\n' +
137      ' </div>\n' +
138      ' </div>\n' +
139      ' </div>\n' +
140      '</div>').attr('id', 'modalContact');
141
142
143    jQuery('body').append(modalTemplate);
144    let modalBody = modalTemplate.find('.modal-body');
145
146    let showContent = function (content) {
147
148      modalBody.html(content);
149      modalTemplate.find('.modal-title').html(modalBody.find('h2').html());
150      modalBody.find('h2').remove();
151      let form = modalTemplate.find('form');
152
153      form.find('[type=submit]').on('click', function (e) {
154        e.preventDefault();
155
156        /* show spinner */
157
158
159        let values = form.serialize();
160        values = values += '&' + jQuery(e.target).attr('name') + '=' + jQuery(e.target).attr('value');
161
162        jQuery.ajax({
163          type: "POST",
164          url: form.attr('action'),
165          data: values,
166          headers: {
167            'Cache-Control': 'no-cache, no-store, must-revalidate',
168            'Pragma': 'no-cache',
169            'Expires': '0'
170          },
171          dataType: 'html',
172          success: showContent
173        });
174
175      });
176
177    };
178
179    jQuery('.modal-ajax').on('click', function (e) {
180      e.preventDefault();
181      let url = jQuery(this).data('url');
182
183      /* show spinner */
184
185      jQuery.ajax({
186        type: "POST",
187        url: url,
188        headers: {
189          'Cache-Control': 'no-cache, no-store, must-revalidate',
190          'Pragma': 'no-cache',
191          'Expires': '0'
192        },
193        dataType: 'html',
194        success: function (content) {
195          showContent(content);
196          modalTemplate.modal('show');
197
198          /* hide spinner */
199
200        }
201      });
202    });
203
204  }
205
206  function initAriaBar() {
207
208    if (jQuery('.nav-aria').length === 0) return;
209
210    jQuery('body').addClass('with-aria-bar');
211
212    if ($.cookie('aria-high-contrast') == '1') {
213      jQuery('body').addClass('high-ct-enabled');
214      jQuery(this).addClass('active');
215      jQuery('.btn-contrast').addClass('active');
216    }
217
218    jQuery('.btn-contrast').on('click', function (event) {
219      event.preventDefault();
220      if (jQuery(this).hasClass('active')) {
221        jQuery('body').removeClass('high-ct-enabled');
222        jQuery(this).removeClass('active');
223        $.removeCookie('aria-high-contrast', {path: '/'});
224      } else {
225        jQuery('body').addClass('high-ct-enabled');
226        jQuery(this).addClass('active');
227        $.cookie('aria-high-contrast', '1', {path: '/'});
228      }
229    });
230
231  }
232
233  function initCompareSlider() {
234    if ($(".beforeafterdefault").length > 0) {
235      $(".beforeafterdefault").cndkbeforeafter({autoSliding: true, mode: 'drag'});
236    }
237  }
238
239  function initScrollbarWidth(App) {
240    // thx d.walsh
241    var scrollDiv = document.createElement('div');
242    scrollDiv.className = 'scrollbar-measure';
243    document.body.appendChild(scrollDiv);
244    var scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth;
245    document.body.removeChild(scrollDiv);
246    App.scrollbarWidth = scrollbarWidth;
247    document.documentElement.style.setProperty('--scrollbar-width', scrollbarWidth + 'px');
248  }
249
250  function initAos() {
251    if ($('[data-aos]').length > 0 && typeof aosIsInitialized !== 'undefined') {
252      AOS.init();
253    }
254  }
255
256  function initSearchbox() {
257    $('#t3b__search__collapse__button--desktop').on('click', function (event) {
258      $(this).css('opacity', '0');
259      $('#tx_indexedsearch_word-default').focus();
260    });
261    $('#t3b__search__collapse--desktop').on('focusout', function (event) {
262      $('.searchbar-toggler').css('opacity', '1');
263      setTimeout(function () {
264        $('#t3b__search__collapse--desktop').collapse('hide');
265      }, 500);
266    });
267
268    $('#t3b__search__collapse__button--mobile').on('click', function (event) {
269      $('#tx_indexedsearch_word-mobile').focus();
270    });
271  }
272
273  function initResponsiveTable() {
274    $('table.table-responsive-init').wrap('<div class="table-responsive"></div>');
275  }
276
277  function initScrollToTabs() {
278
279    $('.nav-tabs.sticky').each(function () {
280      $(this).attr('data-offset-y', $(this).offset().top);
281    });
282
283    $('.nav-tabs.sticky button').on('click', function (e) {
284      e.preventDefault();
285      $('html, body').animate({
286        scrollTop: $(this).parent().parent().attr('data-offset-y') - 20
287      }, 500);
288    });
289  }
290
291  function initScrollToAccordionButton() {
292
293    document.querySelectorAll(".accordion-button").forEach(function (btn) {
294      btn.addEventListener("click", function (e) {
295        setTimeout(function () {
296          const rect = btn.getBoundingClientRect();
297
298          if (rect.top < 0 || rect.bottom > window.innerHeight) {
299            btn.scrollIntoView({
300              behavior: "smooth",
301              block: "start"
302            });
303          }
304        }, 300); /* Delay sollte zur Bootstrap Collapse Transition passen */
305      });
306    });
307
308  }
309
310  return {
311
312    scrollbarWidth: 0,
313
314    init: function () {
315
316      initBootstrap();
317      initScrollbarWidth(this);
318      initLightbox();
319      initHeader();
320      initEqualHeight();
321      initSmoothScroll();
322      initAjaxModals();
323      initAriaBar();
324      initCompareSlider();
325      initAos();
326      initSearchbox();
327      initResponsiveTable();
328      initCountdown();
329      initScrollToTabs();
330      initScrollToAccordionButton();
331
332    },
333    compensateScrollbar: function (compensate) {
334      if (compensate) {
335        $('body, .fixed-top, .fixed-bottom, .is-fixed').css('padding-right', this.scrollbarWidth);
336      } else {
337        $('body, .fixed-top, .fixed-bottom, .is-fixed').css('padding-right', 0);
338      }
339    }
340  }
341}();
342
343jQuery(document).ready(function () {
344  App.init();
345});
346
347
348let mmenu;
349
350
351let MmenuWrapper = function () {
352
353  function start() {
354    let navTitle = document.head.querySelector("[name=sitename]") ? document.head.querySelector("[name=sitename]").content : '';
355
356    mmenu = new Mmenu("#mobile-menu", {
357      navbar: {
358        title: navTitle
359      },
360      navbars: [{
361        position: 'bottom',
362        height: 2,
363        content: ['<div id="mobile-footer"></div>']
364      }]
365    }, {
366      offCanvas: {
367        page: {
368          selector: "#page"
369        }
370      },
371      classNames: {
372        selected: 'current'
373      }
374    });
375    const api = mmenu.API;
376    api.bind("openPanel:before",
377      (panel) => {
378        var scrollTopPosition = $(window).scrollTop();
379        $('.fixed-top').css('position', 'absolute').css('top', scrollTopPosition + 'px');
380      }
381    );
382    api.bind("closePanel:after",
383      (panel) => {
384        $('.fixed-top').css('position', 'fixed').css('top', '0px');
385      }
386    );
387    api.bind("openPanel:after",
388      (panel) => {
389        if (document.getElementById('mobile-menu').getAttribute('data-ajax-menu-url') === '') return;
390        populateNextAndPreviousPanels(panel);
391      }
392    );
393
394    let openers = document.querySelectorAll('[data-mm-target="#mobile-menu"]');
395    [].forEach.call(openers, function (opener) {
396      opener.addEventListener('click', (evnt) => {
397        evnt.preventDefault();
398        api.open();
399        if (document.getElementById('mobile-menu').getAttribute('data-ajax-menu-url') !== '') {
400        populateNextAndPreviousPanels(getOpenPanel());
401        }
402      });
403    });
404
405    $('#mobile-footer').html($('#nav-mobile-footer').html());
406
407
408    getOpenPanel().find('ul').attr('data-loaded', 'true');
409    //populateNextAndPreviousPanels(getOpenPanel());
410  }
411
412  function loadMmenuData(pageIds) {
413    //console.debug('loadMmenuData');
414    //console.debug(pageIds);
415    $.ajax({
416      url: $('#mobile-menu').attr('data-ajax-menu-url'),
417      data: {
418        pageIds: pageIds.join(',')
419      },
420      context: document.body
421    }).done(function (data) {
422      let uls = $('<div />').html(data).find('ul');
423      uls.each(function (index) {
424        let id = $(this).attr('data-id');
425        if ($('ul[data-id=' + id + ']').length > 0) {
426          $('ul[data-id=' + id + ']').attr('data-loaded', 'true');
427          let lastElement;
428          $(this).children('li').each(function (index) {
429            let pid = $(this).attr('data-id');
430            if ($('ul[data-id=' + id + '] > li[data-id=' + pid + ']').length > 0) {
431              // skip element
432              lastElement = $('li[data-id=' + pid + ']');
433            } else {
434              if (index === 0) {
435                lastElement = $(this).prependTo($('ul[data-id=' + id + ']'));
436              } else {
437                lastElement = $(this).insertAfter(lastElement);
438              }
439            }
440          });
441        } else if ($('.mm-listitem[data-id=' + id + ']').length > 0) {
442          $('.mm-listitem[data-id=' + id + ']').append($(this));
443        }
444      });
445
446    });
447
448  }
449
450  function populateNextAndPreviousPanels(panel) {
451
452    //if ($('.navbar-toggler').get(0).offsetParent === null) return;
453
454    //console.debug('populateNextAndPreviousPanels');
455    let pageIds = [];
456    //console.debug(panel)
457    $('li.sub', panel).each(function () {
458      if ($('ul[data-id=' + $(this).attr('data-id') + '][data-loaded=true]').length === 0) {
459        if ($(this).attr('data-mm-child') !== undefined && $(this).attr('data-mm-child') !== '') {
460          $('#' + $(this).attr('data-mm-child') + ' > ul > li.sub').each(function () {
461            pageIds.push($(this).attr('data-id'));
462          });
463        } else {
464          pageIds.push($(this).attr('data-id'));
465        }
466      }
467    });
468    // parent
469    let parentId = $(panel).attr('data-mm-parent');
470    if ($('#' + parentId).length > 0 && $('ul[data-id=' + $('#' + parentId).parent().attr('data-id') + '][data-loaded=true]').length === 0) {
471      pageIds.push($('#' + parentId).parent().attr('data-id'));
472    }
473    if (pageIds.length > 0) {
474      loadMmenuData(pageIds);
475    }
476  }
477
478  function getOpenPanel() {
479    return $('.mm-panel--opened');
480  }
481
482  return {
483    init: function () {
484      start();
485    }
486  }
487}();
488
489
490document.addEventListener(
491  "DOMContentLoaded", () => {
492    if (typeof Mmenu === 'undefined' || document.getElementById('mobile-menu') 
492=== null) return;
493    MmenuWrapper.init();
494  }
495);
496
497
498function loadJS(url) {
499  // adding the script tag to the head
500  var head = document.getElementsByTagName('head')[0];
501  var script = document.createElement('script');
502  script.type = 'text/javascript';
503  script.src = url;
504
505  // fire the loading
506  head.appendChild(script);
507}
508
509
510
511/* fix for shmooth scroll bug and invalid message in chrome */
512var invalidTimeout;
513var scrollTimeout;
514document.querySelectorAll('form').forEach(function(form) {
515
516  form.querySelectorAll('input, textarea, select').forEach(function(element) {
517    element.addEventListener('invalid', function(event) {
518      // Multiple elements in the form will likely report being invalid at the same time, so we wait 50ms
519      // until they've stopped triggering
520      clearTimeout(invalidTimeout);
521      invalidTimeout = setTimeout(function () {
522        // Once the invalid events have stopped, we expect the browser to scroll an element into view
523        // Wait until that scrolling has stopped before attempting to trigger the validation again
524        var hasScrolled = false;
525        function onScroll() {
526          hasScrolled = true;
527          clearTimeout(scrollTimeout);
528          scrollTimeout = setTimeout(function () {
529            // We've finished scrolling after an invalid event, so re-trigger the form validation
530            form.reportValidity();
531            $(window).off("scroll", onScroll);
532          }, 50);
533        }
534
535        $(window).on("scroll", onScroll);
536
537        // No scrolling was necessary
538        setTimeout(function () {
539          if (!hasScrolled) {
540            clearTimeout(scrollTimeout);
541            $(window).off("scroll", onScroll);
542          }
543        }, 20);
544      }, 50);
545    });
546  });
547});

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.