PageSourceSearch

https://fitseveneleven.de/wp-content/plugins/countdown-bar-pro/public/js/countdown.js?ver=1.0.0

js fitseveneleven.de collected 2026-10-01 16:19:21 UTC 16,229 bytes, 348 lines download raw bytes

1/**
2 * Frontend-Skript für den Countdown-Störer
3 *
4 * Dieses Skript liest die durch das Admin-Interface gespeicherten Optionen
5 * (fit711CountDownOptions) und wendet sie im Frontend an. Neben dem
6 * Countdown werden nun auch Hintergrund (einfarbig oder Gradient), ein
7 * benutzerdefinierter Text, Ausrichtungsoptionen und Einstellungen für den
8 * Schließen-Button berücksichtigt. Nach Ablauf kann der Banner wahlweise
9 * ausgeblendet oder durch einen eigenen Text ersetzt werden.
10 */
11/**
12 * Erweiterte Frontend-Logik für den Countdown-Störer.
13 *
14 * Dieses Skript liest die in den Plugin-Einstellungen gespeicherten Optionen aus
15 * und wendet sie im Frontend an. Unterstützt werden nun Farbigkeits‑Intensitäten,
16 * Gradienten, Einheitenplatzierung, benutzerdefinierte Textpositionen sowie
17 * individuelle Abstände für links/rechts. Alle Farben werden in RGBA umgerechnet
18 * basierend auf der eingestellten Intensität.
19 */
20(function() {
21    // Wenn keine Optionen definiert sind oder der Banner deaktiviert ist, abbrechen
22    if ( typeof fit711CountDownOptions === 'undefined' || ! fit711CountDownOptions.enabled ) {
23        return;
24    }
25    var options = fit711CountDownOptions;
26    if ( ! options.expiry ) {
27        return;
28    }
29    var expiryDate = new Date( options.expiry );
30    var bannerEl   = document.getElementById( 'fit711-countdown-stoerer' );
31    if ( ! bannerEl ) return;
32    var contentEl  = bannerEl.querySelector( '.fit711-countdown-content' );
33    var closeBtn   = bannerEl.querySelector( '.fit711-countdown-close' );
34
35    // Wenn eine Ziel-URL angegeben ist, mache den Banner klickbar. Die URL
36    // wird entweder im selben Fenster oder in einem neuen Tab geöffnet,
37    // abhängig von der Option `open_in_new_tab`. Ein Klick auf den Close-
38    // Button darf den Link nicht auslösen.
39    if ( options.target_url && options.target_url.trim() !== '' ) {
40        bannerEl.style.cursor = 'pointer';
41        bannerEl.addEventListener('click', function(e) {
42            // Nicht ausführen, wenn der Close-Button oder dessen Kind angeklickt wurde
43            if ( e.target && (e.target === closeBtn || (e.target.closest && e.target.closest('.fit711-countdown-close')) ) ) {
44                return;
45            }
46            // Öffne die Ziel-URL im neuen Tab oder im selben Fenster
47            var url = options.target_url;
48            if ( options.open_in_new_tab ) {
49                window.open(url, '_blank');
50            } else {
51                window.location.href = url;
52            }
53        });
54    }
55
56    // Überprüfen, ob der Banner auf der aktuellen Seite angezeigt werden soll
57    // 1. URL-Filter: falls target_urls angegeben, muss die aktuelle URL mindestens eine dieser Zeichenfolgen enthalten
58    var shouldShow = true;
59    if ( options.target_urls && options.target_urls.trim() !== '' ) {
60        var patterns = options.target_urls.split(/\n|,/).map(function(p) { return p.trim(); }).filter(Boolean);
61        var currentUrl = window.location.href;
62        shouldShow = patterns.some(function(p) {
63            return currentUrl.indexOf(p) !== -1;
64        });
65    }
66    // 1b. Ausschluss-Filter: wenn die aktuelle URL eine der exclude_urls enthaelt, NICHT anzeigen (hat Vorrang)
67    if ( shouldShow && options.exclude_urls && options.exclude_urls.trim() !== '' ) {
68        var excludePatterns = options.exclude_urls.split(/\n|,/).map(function(p) { return p.trim(); }).filter(Boolean);
69        var curUrl = window.location.href;
70        if ( excludePatterns.some(function(p) { return curUrl.indexOf(p) !== -1; }) ) {
71            shouldShow = false;
72        }
73    }
74    // 2. Post-Type-Filter: falls ausgewählte Post Types definiert sind
75    if ( shouldShow && options.selected_post_types && options.selected_post_types.length ) {
76        var bodyClasses = document.body.className;
77        shouldShow = options.selected_post_types.some(function(slug) {
78            return bodyClasses.indexOf('post-type-' + slug) !== -1 ||
79                   bodyClasses.indexOf('single-' + slug) !== -1 ||
80                   bodyClasses.indexOf('page-' + slug) !== -1;
81        });
82    }
83    if ( ! shouldShow ) {
84        if ( bannerEl ) {
85            bannerEl.style.display = 'none';
86        }
87        return;
88    }
89
90    /**
91     * Ermittelt das aktuelle Gerät basierend auf der Fensterbreite und gibt den
92     * entsprechenden CSS‑Code aus den gerätespezifischen Einstellungen zurück.
93     * Anschließend wird das CSS in ein <style>-Element eingefügt. Dabei werden
94     * typografische Anführungszeichen in reguläre Anführungszeichen umgewandelt
95     * und durch JSON‑Encoding entstandene Escape-Zeichen (\:) entfernt, sodass
96     * gültiges CSS entsteht. Falls kein gerätespezifisches CSS definiert ist,
97     * wird nichts eingefügt.
98     */
99    function applyDeviceCss() {
100        var deviceStyles = options.device_styles || {};
101        // Bestimme das Gerät anhand der Fensterbreite. Desktop >= 1025px,
102        // Tablet 601–1024px, Mobil <= 600px. Diese Werte können bei Bedarf
103        // angepasst werden.
104        var width = window.innerWidth;
105        var device;
106        if (width <= 600) {
107            device = 'mobile';
108        } else if (width <= 1024) {
109            device = 'tablet';
110        } else {
111            device = 'desktop';
112        }
113        var css = '';
114        if (deviceStyles[device] && deviceStyles[device].customCss) {
115            css = deviceStyles[device].customCss;
116            // Ersetze Escape-Sequenzen für Doppelpunkte, die beim Einfügen über
117            // wp_localize_script entstehen können (\: -> :).
118            css = css.replace(/\\:/g, ':');
119            // Konvertiere typografische Anführungszeichen in gerade Anführungszeichen
120            // damit JavaScript den String korrekt interpretieren kann.
121            css = css.replace(/[\u201C\u201D\u201E\u201F\u2039\u203A\u00AB\u00BB]/g, '"');
122        }
123        if (css) {
124            // Style-Element nur einmal einfügen. Wenn es bereits existiert, wird der
125            // Inhalt aktualisiert. Dadurch verhindern wir, dass sich mehrere
126            // <style>-Tags anhäufen, wenn applyDeviceCss mehrfach aufgerufen wird.
127            var existing = document.getElementById('fit711-countdown-device-css');
128            if (!existing) {
129                existing = document.createElement('style');
130                existing.type = 'text/css';
131                existing.id = 'fit711-countdown-device-css';
132                document.head.appendChild(existing);
133            }
134            existing.innerHTML = css;
135        }
136    }
137
138    // Füge gerätespezifisches CSS hinzu, falls definiert
139    applyDeviceCss();
140
141    // Prüfen, ob der Banner aktuell ausgeblendet werden soll (z. B. nach Schließen)
142    var hideUntilTs = localStorage.getItem( 'fit711_countdown_hide_until' );
143    if ( hideUntilTs && parseInt( hideUntilTs, 10 ) > Date.now() ) {
144        bannerEl.style.display = 'none';
145        return;
146    }
147
148    // Hilfsfunktion: Hex nach RGBA unter Berücksichtigung der Intensität (0–100)
149    function hexToRgba(hex, intensity) {
150        if (!hex) return hex;
151        // Wenn bereits ein rgb/rgba-Wert übergeben wurde, diesen direkt zurückgeben
152        if (typeof hex === 'string' && hex.trim().match(/^rgba?\(/)) {
153            return hex;
154        }
155        // Entferne #:e
156        var h = hex.replace('#', '');
157        if (h.length === 3) {
158            h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2];
159        }
160        var r = parseInt(h.substring(0, 2), 16);
161        var g = parseInt(h.substring(2, 4), 16);
162        var b = parseInt(h.substring(4, 6), 16);
163        var alpha;
164        if ( typeof intensity === 'number' && ! isNaN(intensity) ) {
165            alpha = Math.max(0, Math.min(1, intensity / 100));
166        } else {
167            alpha = 1;
168        }
169        return 'rgba(' + r + ',' + g + ',' + b + ',' + alpha + ')';
170    }
171
172    // Wende Hintergrund an
173    var styles = options.global_styles || {};
174    if ( styles.backgroundType === 'gradient' ) {
175        var c1 = hexToRgba(styles.gradientStart || '#333333', parseInt(styles.gradientStartIntensity, 10));
176        var c2 = hexToRgba(styles.gradientMiddle || '#666666', parseInt(styles.gradientMiddleIntensity, 10));
177        var c3 = hexToRgba(styles.gradientEnd || '#999999', parseInt(styles.gradientEndIntensity, 10));
178        bannerEl.style.background = 'linear-gradient(to right, ' + c1 + ', ' + c2 + ', ' + c3 + ')';
179    } else {
180        var bg = hexToRgba(styles.backgroundColor || '#333333', parseInt(styles.backgroundColorIntensity, 10));
181        bannerEl.style.background = bg;
182    }
183    // Einheitenfarbe (Units) inkl. Intensität
184    var unitColor = hexToRgba(styles.textColor || '#ffffff', parseInt(styles.textColorIntensity, 10));
185    contentEl.style.color = unitColor;
186    // Schriftgröße der Ziffern wird am numbersEl separat gesetzt
187    // Richte den Inhaltscontainer ein
188    contentEl.style.display = 'flex';
189    contentEl.style.alignItems = 'center';
190    contentEl.style.justifyContent = 'center';
191
192    // Lege separate Container für Zahlen und benutzerdefinierten Text an
193    var numbersEl = document.createElement('div');
194    numbersEl.className = 'fit711-countdown-numbers';
195    // Schriftgröße für Ziffern
196    if ( styles.fontSize ) {
197        numbersEl.style.fontSize = styles.fontSize + 'px';
198    }
199    // Der messageEl wird nur erstellt, wenn ein benutzerdefinierter Text gesetzt ist
200    var messageEl = null;
201    if ( styles.customText && styles.customText.trim() !== '' ) {
202        messageEl = document.createElement('div');
203        messageEl.className = 'fit711-countdown-message';
204        // HTML erlauben: setze innerHTML statt textContent
205        messageEl.innerHTML = styles.customText;
206        // Farbe und Größe des Texts
207        var msgColor = hexToRgba(styles.customTextColor || '#ffffff', parseInt(styles.customTextColorIntensity, 10));
208        messageEl.style.color = msgColor;
209        if ( styles.customTextSize ) {
210            messageEl.style.fontSize = styles.customTextSize + 'px';
211        }
212    }
213    // Bereite Inhaltscontainer basierend auf Textposition vor
214    contentEl.innerHTML = '';
215    // Setze Flex-Richtung abhängig von Position
216    var pos = styles.customTextPosition || 'below';
217    var margin = parseInt(styles.customTextMargin || 0, 10);
218    if ( pos === 'left' ) {
219        contentEl.style.flexDirection = 'row';
220        contentEl.appendChild(messageEl ? messageEl : document.createDocumentFragment());
221        contentEl.appendChild(numbersEl);
222        if ( messageEl ) {
223            messageEl.style.marginRight = margin + 'px';
224        }
225    } else if ( pos === 'right' ) {
226        contentEl.style.flexDirection = 'row';
227        contentEl.appendChild(numbersEl);
228        contentEl.appendChild(messageEl ? messageEl : document.createDocumentFragment());
229        if ( messageEl ) {
230            messageEl.style.marginLeft = margin + 'px';
231        }
232    } else if ( pos === 'above' ) {
233        contentEl.style.flexDirection = 'column';
234        if ( messageEl ) {
235            contentEl.appendChild(messageEl);
236            messageEl.style.marginBottom = margin + 'px';
237        }
238        contentEl.appendChild(numbersEl);
239    } else { // below
240        contentEl.style.flexDirection = 'column';
241        contentEl.appendChild(numbersEl);
242        if ( messageEl ) {
243            messageEl.style.marginTop = margin + 'px';
244            contentEl.appendChild(messageEl);
245        }
246    }
247
248    // Stil des Schließen-Buttons
249    if ( closeBtn ) {
250        // Farbe inkl. Intensität
251        if ( styles.closeButtonColor ) {
252            var xColor = hexToRgba(styles.closeButtonColor, parseInt(styles.closeButtonColorIntensity, 10));
253            closeBtn.style.color = xColor;
254        }
255        if ( styles.closeButtonSize ) {
256            closeBtn.style.fontSize = styles.closeButtonSize + 'px';
257        }
258        if ( styles.closeButtonWeight ) {
259            closeBtn.style.fontWeight = styles.closeButtonWeight;
260        }
261        // Position: Reset Standard und dann setzen
262        closeBtn.style.position = 'absolute';
263        // horizontale Position
264        if ( styles.closeButtonPositionHorizontal === 'left' ) {
265            closeBtn.style.left = '0.5rem';
266            closeBtn.style.right = '';
267        } else {
268            closeBtn.style.right = '0.5rem';
269            closeBtn.style.left = '';
270        }
271        // vertikale Position
272        if ( styles.closeButtonPositionVertical === 'middle' ) {
273            closeBtn.style.top = '50%';
274            closeBtn.style.bottom = '';
275            closeBtn.style.transform = 'translateY(-50%)';
276        } else if ( styles.closeButtonPositionVertical === 'bottom' ) {
277            closeBtn.style.bottom = '0.5rem';
278            closeBtn.style.top = '';
279            closeBtn.style.transform = '';
280        } else {
281            closeBtn.style.top = '0.5rem';
282            closeBtn.style.bottom = '';
283            closeBtn.style.transform = '';
284        }
285        // Close-Button Event
286        closeBtn.addEventListener('click', function() {
287            bannerEl.style.display = 'none';
288            var days = parseInt(options.hide_for_days || 0, 10);
289            var hideUntil = new Date();
290            hideUntil.setDate(hideUntil.getDate() + days);
291            localStorage.setItem('fit711_countdown_hide_until', hideUntil.getTime());
292        });
293    }
294
295    // Funktion zur Aktualisierung des Countdowns und Darstellung der Einheiten
296    function updateCountdown() {
297        var now  = new Date();
298        var diff = expiryDate.getTime() - now.getTime();
299        if ( diff <= 0 ) {
300            clearInterval(interval);
301            if ( options.expire_behavior === 'custom_text' && options.expire_text ) {
302                numbersEl.innerHTML = options.expire_text;
303                // benutzerdefinierte Nachricht ausblenden, falls vorhanden
304                if ( messageEl ) {
305                    messageEl.style.display = 'none';
306                }
307            } else {
308                bannerEl.style.display = 'none';
309            }
310            return;
311        }
312        var days  = Math.floor(diff / (1000 * 60 * 60 * 24));
313        var hours = Math.floor((diff / (1000 * 60 * 60)) % 24);
314        var mins  = Math.floor((diff / (1000 * 60)) % 60);
315        var secs  = Math.floor((diff / 1000) % 60);
316
317        // Berechne RGBA für Ziffern und Einheiten
318        var numColor = hexToRgba(styles.numberColor || '#ff0000', parseInt(styles.numberColorIntensity, 10));
319        var unitColorNow = unitColor; // use previously calculated unit color
320
321        // Erzeuge HTML abhängig von der Einheitenposition
322        if ( styles.unitsPosition === 'below' ) {
323            // Jedes Segment wird vertikal angeordnet (Zahl über Einheit)
324            var seg = function(value, label) {
325                return '<div style="display:inline-flex; flex-direction:column; align-items:center; margin-right:8px;">' +
326                    '<span style="color:' + numColor + ';" class="fit711-countdown-number">' + value + '</span>' +
327                    '<span style="color:' + unitColorNow + '; font-size:0.8em;">' + label + '</span>' +
328                    '</div>';
329            };
330            numbersEl.innerHTML =
331                seg(days, 'Tage') +
332                seg(hours, 'Std') +
333                seg(mins, 'Min') +
334                seg(secs, 'Sek');
335        } else {
336            // Inline-Anordnung: Zahl gefolgt von Einheit
337            numbersEl.innerHTML =
338                '<span style="color:' + numColor + ';" class="fit711-countdown-number">' + days + '</span> <span style="color:' + unitColorNow + ';">Tage</span> ' +
339                '<span style="color:' + numColor + ';" class="fit711-countdown-number">' + hours + '</span> <span style="color:' + unitColorNow + ';">Std</span> ' +
340                '<span style="color:' + numColor + ';" class="fit711-countdown-number">' + mins + '</span> <span style="color:' + unitColorNow + ';">Min</span> ' +
341                '<span style="color:' + numColor + ';" class="fit711-countdown-number">' + secs + '</span> <span style="color:' + unitColorNow + ';">Sek</span>';
342        }
343    }
344
345    // Starte den Countdown
346    updateCountdown();
347    var interval = setInterval(updateCountdown, 1000);
348})();

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.