PageSourceSearch

https://www.michaelsrealschule.de/wp-content/themes/flib/templates…?ver=51a6dd162072a3ba59dd7d30fba9add9

js michaelsrealschule.de collected 2026-10-06 19:03:58 UTC 20,158 bytes, 600 lines download raw bytes

1$ = jQuery;
2
3/**
4 * callback function for url generator button
5 */
6function callback__urlGeneratorButton_eventscalendar_2(button){
7    eventscalendar.proccessFilter(button, 'generateURL');
8}
9
10/**
11 * 
12 * callback function for search component
13 * 
14 * @param {*} searchForm The search form
15 */
16function callback__searchComponent_eventscalendar_2(searchForm){
17    // get the search input in the search form
18    let inputElm = searchForm.querySelector('input');
19
20    eventscalendar.proccessFilter(inputElm, inputElm.value);
21}
22
23/**
24 * 
25 * callback function for datepicker component
26 * 
27 * @param {*} elm The element
28 * @param {*} selected
29 * 
30 * @returns void
31 */
32function callback__datepickerComponent_eventscalendar_2(elm, selected){
33    eventscalendar.proccessFilter(elm, selected);
34}
35
36/**
37 * 
38 * callback function for select component
39 * 
40 * @param {*} elm The element
41 * @param {*} selected
42 * 
43 * @returns void
44 */
45function callback__selectComponent_eventscalendar_2(elm, selected){
46    eventscalendar.proccessFilter(elm, selected); 
47}
48
49/**
50 * Reset the filter
51 * 
52 * @returns void
53 */
54function EventsResetFilter(){
55    eventscalendar.resetFilter();
56}
57
58/**
59 * Download ICS file with current filter settings
60 * 
61 * @param {HTMLElement} button The button element
62 * @returns void
63 */
64function downloadEventsIcs(button) {
65    // Check if eventscalendar object is available
66    if (typeof eventscalendar === 'undefined' || !eventscalendar.state) {
67        console.error('Fehler: Kalender nicht initialisiert');
68        return;
69    }
70
71    // Get the REST API url
72    var baseUrl = window.location.protocol + '//' + window.location.host;
73    var apiUrl = baseUrl + '/wp-json/flib/v1/events';
74
75    // Show loading state
76    button.disabled = true;
77    // Store original content before changing it
78    if (!button.getAttribute('data-original-content')) {
79        button.setAttribute('data-original-content', button.innerHTML);
80    }
81    button.innerHTML = '<span>Wird erstellt...</span>';
82
83    try {
84        // Build POST data for REST API with proper date format conversion
85        var postData = {
86            format: 'ics',
87            from: convertDateToRestFormat(eventscalendar.state.filter.startdate),
88            to: convertDateToRestFormat(eventscalendar.state.filter.enddate),
89            category: eventscalendar.state.combinedCategories ? eventscalendar.state.combinedCategories.join(',') : '',
90            place: Array.isArray(eventscalendar.state.filter.place) ? eventscalendar.state.filter.place.join(',') : (eventscalendar.state.filter.place || ''),
91            source: eventscalendar.state.filter.source || 'events-system'
92        };
93
94        // Create a temporary form for file download
95        var tempForm = document.createElement('form');
96        tempForm.method = 'POST';
97        tempForm.action = apiUrl;
98        tempForm.style.display = 'none';
99
100        // Convert POST data to form fields
101        for (var key in postData) {
102            if (postData[key] !== null && postData[key] !== '') {
103                var input = document.createElement('input');
104                input.type = 'hidden';
105                input.name = key;
106                input.value = postData[key];
107                tempForm.appendChild(input);
108            }
109        }
110
111        // Add form to DOM, submit, and remove
112        document.body.appendChild(tempForm);
113        tempForm.submit();
114        document.body.removeChild(tempForm);
115    } catch (error) {
116        console.error('Fehler beim Erstellen der ICS-Datei:', error);
117    }
118
119    // Reset button state
120    setTimeout(function() {
121        button.disabled = false;
122        // Restore original button content
123        var originalContent = button.getAttribute('data-original-content');
124        if (originalContent) {
125            button.innerHTML = originalContent;
126        } else {
127            button.innerHTML = '<span>Kalender abonnieren</span>';
128        }
129    }, 2000);
130}
131
132/**
133 * Convert date from DD.MM.YYYY format to YYYY-MM-DD HH:MM format for REST API
134 * 
135 * @param {string} dateStr - Date string in DD.MM.YYYY format or null
136 * @returns {string} - Date string in YYYY-MM-DD HH:MM format or null
137 */
138function convertDateToRestFormat(dateStr) {
139    if (!dateStr || dateStr === 'null' || dateStr === null) {
140        return null;
141    }
142    
143    // Check if date is in DD.MM.YYYY format
144    var datePattern = /^(\d{1,2})\.(\d{1,2})\.(\d{4})$/;
145    var match = dateStr.match(datePattern);
146    
147    if (match) {
148        var day = match[1].padStart(2, '0');
149        var month = match[2].padStart(2, '0');
150        var year = match[3];
151        
152        // Convert to YYYY-MM-DD 00:00 format
153        return year + '-' + month + '-' + day + ' 00:00';
154    }
155    
156    // If not in expected format, return as-is
157    return dateStr;
158}
159
160/**
161 * 
162 * Switch the page
163 * 
164 * @param {*} item The item to switch to
165 * @param {*} page The page number
166 * 
167 * @returns void
168 */
169function switchPage(item, page){
170    eventscalendar.state.currentPage = page;
171    eventscalendar.refresh()
172}
173
174/**
175 * 
176 * Switch the tab
177 * 
178 * @param {*} type The type to switch to
179 * 
180 * @returns void
181 */
182function switchTab(type){
183    document.querySelectorAll('.tab-button').forEach(function(elm){
184        elm.classList.add('disabled')
185        elm.disabled = false
186    })
187    document.querySelector('[data-tab="'+type+'"]').disabled = true
188    document.querySelector('[data-tab="'+type+'"]').classList.remove('disabled')
189    eventscalendar.state.filter.source = type
190
191    eventscalendar.refresh()
192}
193
194/**
195 * 
196 * Resize events
197 * 
198 */
199window.addEventListener('resize', function() {
200    resizeMobileHiddenParts();
201});
202
203/**
204 *
205 * Toggle the info box
206 * 
207 * @param {*} event The event
208 * @param {*} button The button
209 * 
210 * @returns void
211 */
212function toggleInfoBox(event, button) {
213    event.preventDefault();
214    event.stopPropagation();
215
216    if (!button) return;
217
218    let infoBox = button.closest('.infobox');
219    if (!infoBox) return;
220
221    let hiddenMobilePart = infoBox.querySelector('.mobile-hidden');
222    if (!hiddenMobilePart) return;
223
224    infoBox.classList.toggle('mobile-toggled-visible');
225
226    if (infoBox.classList.contains('mobile-toggled-visible')) {
227        // Get the height of the ul inside the hidden part
228        let hiddenMobilePartHeight = hiddenMobilePart.scrollHeight;
229
230        // Set the height of the hidden part to the height of the ul
231        hiddenMobilePart.style.height = hiddenMobilePartHeight + 'px';
232    } else {
233        hiddenMobilePart.style.height = '0px';
234    }
235}
236
237/**
238 * 
239 * Resize mobile hidden parts
240 * 
241 * returns void
242 */
243function resizeMobileHiddenParts() {
244    let hiddenParts = document.querySelectorAll('.infobox.mobile-toggled-visible .mobile-hidden');
245    if (!hiddenParts) return;
246
247    hiddenParts.forEach(function(hiddenPart) {
248        hiddenPart.style.height = 'auto';
249        let hiddenPartHeight = hiddenPart.scrollHeight;
250        hiddenPart.style.height = hiddenPartHeight + 'px';
251    });
252}
253
254/** 
255 * Eventscalendar JS Class
256 */
257class Eventscalendar{
258
259    constructor(){
260        this.state = {
261            "action": "getEvents",
262            "allow_refresh": true,
263            "generateURL": false,
264            "filter": {
265                "search": '',
266                "source": null,
267                "startdate": null,
268                "enddate": null,
269                "category": [],
270                "place": [],
271                "radius": null,
272                "extraCategories": []
273            },
274            'currentPage': 1,
275            'combinedCategories': []
276        }
277    }
278
279    /**
280     * 
281     * Proccess the filter
282     * 
283     * @param {*} elm The element
284     * @param {*} selected The selected value
285     */
286    proccessFilter(elm, selected) {
287        switch (elm.dataset.name) {
288            case 'search':
289                this.state.filter.search = elm.value || '';
290                break;
291            case 'startdate':
292                this.state.filter.startdate = elm.value || null;
293                break;
294            case 'enddate':
295                this.state.filter.enddate = elm.value || null;
296                break;
297            case 'category':
298                this.state.filter.category = selected;
299                break;
300            case 'place':
301                this.state.filter.place = selected;
302                break;
303            case 'radius':
304                this.state.filter.radius = selected || null;
305                break;
306            default:
307                // Check if it's an extra category filter
308                if (elm.dataset.repeaterFilter === "true") {
309                    const name = elm.dataset.name;
310                    // normalize to array and remove placeholders
311                    const values = (Array.isArray(selected) ? selected : [selected]).filter(v =>
311 v && v !== 'keine-auswahl');
312
313                    if (!Array.isArray(this.state.filter.extraCategories)) {
314                        this.state.filter.extraCategories = [];
315                    }
316
317                    // find existing entry by name and update, else push a new one
318                    const idx = this.state.filter.extraCategories.findIndex(ec => ec && ec.name === name);
319                    if (idx >= 0) {
320                        this.state.filter.extraCategories[idx].values = values;
321                    } else {
322                        this.state.filter.extraCategories.push({ name: name, values: values });
323                    }
324                }
325                break;
326        }
327    
328        // Build combined categories (main + extra) for the API call only
329        const extraCats = Array.isArray(this.state.filter.extraCategories)
330            ? this.state.filter.extraCategories.flatMap(ec => Array.isArray(ec.values) ? ec.values : [])
331            : [];
332
333        const combined = [
334            ...(Array.isArray(this.state.filter.category) ? this.state.filter.category : (this.state.filter.category ? [this.state.filter.category] : [])),
335            ...extraCats,
336        ];
337
338        // Save only into separate state; do not overwrite the raw select state
339        this.state.combinedCategories = Array.from(new Set(combined)).filter(v => v && v !== 'keine-auswahl');
340        
341        // Reset the current page to 1
342        this.state.currentPage = 1;
343
344        // If selected is 'generateURL', set the state of generateURL to true
345        if (selected === 'generateURL') {
346            this.state.generateURL = true;
347        } else {
348            this.state.generateURL = false;
349        }
350    
351        // Refresh the UI
352        this.refresh();
353    }
354
355    /**
356     * Reset the filter
357     * 
358     * @returns void
359     */
360    resetFilter(){
361
362        // Get reference to the filter wrapper of the events calendar
363        const filterWrapper = document.querySelector('.eventscalendar-wrapper .filter-wrapper');
364
365        //block refresh
366        this.state.allow_refresh = false;
367
368        // Get the default settings
369        var refreshWrapper = document.getElementById('eventscalendar-refresh-wrapper');
370        var defaults = refreshWrapper.dataset.defaults
371        defaults = JSON.parse(defaults)
372
373        this.state.filter.startdate = null
374        this.state.filter.enddate = null
375        this.state.filter.category = defaults.category
376        this.state.filter.place = []
377        this.state.filter.radius = null
378        this.state.currentPage = 1
379        this.state.filter.search = ''
380
381        // check if extra categories are present, and reset them (now an array)
382        if (this.state.filter.extraCategories) {
383            this.state.filter.extraCategories = [];
384        }
385
386        // recompute combined categories from raw select values
387        const _combinedAfterReset = [
388            ...(Array.isArray(this.state.filter.category) ? this.state.filter.category : (this.state.filter.category ? [this.state.filter.category] : []))
389        ];
390        this.state.combinedCategories = Array.from(new Set(_combinedAfterReset)).filter(v => v && v !== 'keine-auswahl');
391
392        const startDateElement = filterWrapper.querySelector('[data-name="startdate"]');
393        if (startDateElement) {
394            startDateElement.value = this.formatDate(Date());
395        }
396
397        const endDateElement = filterWrapper.querySelector('[data-name="enddate"]');
398        if (endDateElement) {
399            endDateElement.value = '';
400        }
401
402        const placeElement = filterWrapper.querySelector('[data-name="place"]');
403        if (placeElement && placeElement.slim) {
404            placeElement.slim.setSelected('keine-auswahl');
405            // if the element contains the data-sourceurl attribute setData to 'keine-auswahl' and 'Keine Auswahl'
406            if (placeElement.dataset.sourceurl) {
407                placeElement.slim.setData([
408                    { text: 'Keine Auswahl', value: 'keine-auswahl', placeholder: 'Keine Auswahl'},
409                ]);
410            }
411        }
412
413        const radiusElement = filterWrapper.querySelector('[data-name="radius"]');
414        if (radiusElement && radiusElement.slim) {
415            radiusElement.slim.setSelected('');
416        }
417
418        const categoryElement = filterWrapper.querySelector('[data-name="category"]');
419        if (categoryElement && categoryElement.slim) {
420            categoryElement.slim.setSelected(defaults.category);
421        }
422
423        const categoryRepeaterElements = filterWrapper.querySelectorAll('[data-repeater-filter="true"]');
424        if (categoryRepeaterElements) {
425            categoryRepeaterElements.forEach(function (categoryRepeaterElement) {
426                // set back to empty
427                categoryRepeaterElement.slim.setSelected('keine-auswahl');
428            });
429        }
430
431        const searchElement = filterWrapper.querySelector('[data-name="search"]');
432        if (searchElement) {
433            searchElement.value = '';
434        }
435
436        // Reset the current page to 1
437        this.state.currentPage = 1;
438
439        //unblock refresh
440        this.state.allow_refresh = true;
441
442        // wait a bit before refreshing
443        this.refresh()
444    }
445
446    /**
447     * 
448     * Refresh the events
449     * 
450     * @returns void
451     */
452    refresh(){
453
454        if(!this.state.allow_refresh){
455            history.pushState(this.state, '')
456            return;
457        }
458
459        // Get the ajax url because the script is not localized, see /inc/api/config.php
460        var baseUrl = window.location.protocol + '//' + window.location.host;
461        var ajaxurl = baseUrl + '/wp-admin/admin-ajax.php';
462
463        //get element settings
464        var refreshWrapper = document.getElementById('eventscalendar-refresh-wrapper');
465        var section = refreshWrapper.closest('section');
466
467        var form_data = new FormData();
468        form_data.append('action', this.state.action);
469        form_data.append('startdate', this.state.filter.startdate);
470        form_data.append('enddate', this.state.filter.enddate);
471        form_data.append('category', this.state.combinedCategories);
472        form_data.append('place', this.state.filter.place);
473        form_data.append('radius', this.state.filter.radius);
474        form_data.append('settings', refreshWrapper.dataset.settings);
475        form_data.append('page', this.state.currentPage);
476        form_data.append('source', this.state.filter.source);
477        form_data.append('search', this.state.filter.search);
478        form_data.append('generateURL', this.state.generateURL);
479
480        // Get the ajax url because the script is not localized, see /inc/api/config.php
481        var baseUrl = window.location.protocol + '//' + window.location.host;
482        var ajaxurl = baseUrl + '/wp-admin/admin-ajax.php';
483
484        $.ajax({
485            url: ajaxurl,
486            type: 'POST',
487            contentType: false,
488            processData: false,
489            data: form_data,
490            beforeSend: function(xhr) {
491                document.querySelector('.events-loading').style.display = 'flex';
492                refreshWrapper.style.display = 'none';
493
494                // Jump to section
495                if (section) {
496                    let sectionAnchor = section.querySelector('.section-anchor');
497                    let sectionTop = sectionAnchor.getBoundingClientRect().top + window.scrollY;
498                    window.scrollTo({
499                        top: sectionTop,
500                        behavior: 'smooth'
501                    });
502                }
503            },
504            success: function(response) {
505                console.log(response);
506                refreshWrapper.innerHTML = response.data.html;
507                
508
509                // Get the .calendar-subscription button and change it to the url
510                const icsButton = document.querySelector('.calendar-subscription-button');
511                if (icsButton && response.data.url) {
512                    eventscalendar.copyUrlToClipboard(icsButton, response.data.url);
513                }
514
515                // Reset generateURL back to false after any request
516                eventscalendar.state.generateURL = false;
517
518                history.pushState(eventscalendar.state, '');
519            }
520        })
521        .done(function() {
522            document.querySelector('.events-loading').style.display = 'none';
523            refreshWrapper.style.display = 'block';
524            svgVisible();
525        })
526    }
527
528    formatDate(date) {
529        date = new Date(date)
530        var format = ('0' + date.getDate()).slice(-2)+'.'+('0' + (date.getMonth()+1)).slice(-2) +'.'+date.getFullYear();
531        return format;
532    }
533
534    /**
535     * Copy URL to clipboard and update button text
536     * 
537     * @param {HTMLElement} button - The calendar subscription button
538     * @param {string} url - The URL to copy to clipboard
539     * @returns void
540     */
541    copyUrlToClipboard(button, url) {
542        // Copy URL to clipboard
543        navigator.clipboard.writeText(url).then(function() {
544            const span = button.querySelector('span');
545            const originalText = span.innerText;
546            const originalColor = button.style.backgroundColor;
547            
548            // Show the info text
549            const infoText = document.querySelector('.calendar-subscription-info');
550            if (infoText) {
551                infoText.style.display = 'block';
552            }
553            
554            // Replace icon with check
555            const svg = button.querySelector('svg');
556            if (svg) {
557                const checkPath = 'M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z';
558                svg.innerHTML = '<path fill="currentColor" d="' + checkPath + '"></path>';
559                svg.setAttribute('viewBox', '0 0 512 512');
560            }
561            
562            // Change button appearance
563            button.style.backgroundColor = '#28a745';
564            span.innerText = 'Link in die Zwischenablage kopiert';
565            
566            // Reset after 3 seconds
567            setTimeout(function() {
568                span.innerText = originalText;
569                button.style.backgroundColor = originalColor;
570            }, 3000);
571        });
572    }
573}   
574
575/**
576 * Intit Eventscalendar Object
577 */
578 const eventscalendar = new Eventscalendar();
579
580// add dom content loaded event
581document.addEventListener('DOMContentLoaded', function(){
582    let activeTab = 0
583    document.querySelectorAll('.tab-button').forEach(function(elm, index){
584        if(activeTab != index){
585            elm.classList.add('disabled')
586        }
587        else{
588            elm.disabled = true
589        }
590    });
591    
592    var defaults = document.getElementById('eventscalendar-refresh-wrapper').dataset.defaults;
593    defaults = JSON.parse(defaults);
594
595    eventscalendar.state.filter.category = defaults.category;
596    eventscalendar.state.filter.source = defaults.source;
597
598    const _initCombined = Array.isArray(defaults.category) ? defaults.category : (defaults.category ? [defaults.category] : []);
599    eventscalendar.state.combinedCategories = Array.from(new Set(_initCombined)).filter(v => v && v !== 'keine-auswahl');
600});

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.