(function() {
function init() {
// ---- Konfiguration (URLs ggf. anpassen) ----
// ---- Datei-URLs (Monatsordner pro Datei anpassen, je nachdem wo sie liegt) ----
var DATA_URL = "https://weco-naturstein.de/wp-content/uploads/2026/07/preisliste_export.txt";
var PLZ_URL = "https://weco-naturstein.de/wp-content/uploads/2026/06/plz_geocoord.csv";
var BILD_URL = "https://weco-naturstein.de/wp-content/uploads/2026/06/preisliste_bilder.txt";
var GESTEIN_URL = "https://weco-naturstein.de/wp-content/uploads/2026/07/sortiment_gesteinsart.csv";
// Modus: "preisliste" (Standard) oder "anfrage" (ohne Preise, ohne PLZ-Gate)
var appEl = document.getElementById('preisliste-app');
var IS_ANFRAGE = !!(appEl && (appEl.getAttribute('data-modus') || '').toLowerCase() === 'anfrage');
var LABEL = IS_ANFRAGE ? 'Anfrage' : 'Bestellanfrage';
var ANFRAGE_LISTE = 'N-Z1'; // im Anfrage-Modus verwendete Datenliste (nur fuer Artikelstruktur, Preise werden ausgeblendet)
// Bilddarstellung: "gross" = grosses Bild in der Karte | "klein_link" = kleines verlinktes Bild | "aus" = keine Bilder
var BILD_MODUS = "gross";
var VALID_KEYS = ["N-Z1", "N-Z2", "O-Z1", "O-Z2"];
// Werks-PLZ (Koordinaten werden aus der PLZ-Tabelle gelesen; Fallback unten)
var WERK_LEER = { plz: "26789", lat: 53.2316, lng: 7.4528 };
var WERK_OST = { plz: "39240", lat: 51.9226, lng: 11.8665 };
var ZONE_GRENZE_KM = 150;
// Farbzuordnung der Kategorien
var KATEGORIE_FARBEN = [
{ farbe: '#ABB5D8', kats: ['GARTENMINERALIEN', 'LAVAMULCH', 'BIENENSAND'] },
{ farbe: '#A2C62F', kats: ['ZIERKIES', 'ZIERSPLITT', 'DEKOSTEINE', 'EASIHOLD', 'POLYGONALPLATTEN', 'KERAMISCHE TRITTPLATTEN', 'NATURSTEINPFLASTER', 'GRANIT', 'BETON', 'KR\u00c4UTERSPIRALEN', 'CO2 NEUTRALER BETONSTEIN', 'CO\u2082 NEUTRALER BETONSTEIN', 'BRUCHSTEINE', 'TROCKENMAUERWERK'] },
{ farbe: '#DB4E2A', kats: ['BAUSAND', 'STREU- & PFLASTERSPLITT', 'STREU- UND PFLASTERSPLITT', 'FUGEN-QUARZSAND', 'FUGENSPLITT', 'WASSERGEB. WEGEDECKE', 'WASSERGEBUNDENE WEGEDECKE'] },
{ farbe: '#F08013', kats: ['SPIELEN MIT SAND'] },
{ farbe: '#1EB5D2', kats: ['WASSERAUFBEREITUNG'] }
];
// ---- Elemente ----
var headline = document.getElementById('pl-headline');
var gate = document.getElementById('pl-gate');
var plzInput = document.getElementById('pl-plz');
var plzBtn = document.getElementById('pl-plz-btn');
var gateMsg = document.getElementById('pl-gate-msg');
var mainArea = document.getElementById('pl-main');
var listeInfo = document.getElementById('pl-liste-info');
var searchInput = document.getElementById('pl-search');
var kategorieSelect= document.getElementById('pl-kategorie');
var farbeSelect = document.getElementById('pl-farbe');
var koernungSelect = document.getElementById('pl-koernung');
var clearKategorie = document.getElementById('pl-clear-kategorie');
var clearFarbe = document.getElementById('pl-clear-farbe');
var clearKoernung = document.getElementById('pl-clear-koernung');
var excelBtn = document.getElementById('pl-excel');
var plzChangeBtn = document.getElementById('pl-plz-change');
var resultsDiv = document.getElementById('pl-results');
var loadingDiv = document.getElementById('pl-loading');
var emptyDiv = document.getElementById('pl-empty');
if (!mainArea || !searchInput ||
!kategorieSelect || !farbeSelect || !koernungSelect || !resultsDiv) {
console.warn('Preisliste: ben\u00f6tigte Elemente nicht gefunden, breche ab.');
return;
}
var KAT_DEFAULT = 'Alle Kategorien';
var FARBE_DEFAULT = 'Alle Farben';
var KOERN_DEFAULT = 'Alle K\u00f6rnungen / Ma\u1e9ee / Formate';
var fullData = null; // gesamtes JSON-Objekt mit allen Listen
var allData = []; // aktuell gewaehlte Liste
var plzData = null; // { plz: [lat, lng] }
var bildData = {}; // { "BEZEICHNUNG|FARBE": { bild, link } }
var gesteinData = {}; // { MITTELTEIL: "Gesteinsart" }
var listeKey = null;
// Bilddaten laden (optional; fehlt eine Zuordnung, bleibt der Artikel ohne Bild)
fetch(BILD_URL)
.then(function(r) { return r.text(); })
.then(function(text) {
var start = text.indexOf('{');
bildData = start !== -1 ? JSON.parse(text.slice(start)) : {};
if (mainArea.style.display !== 'none') render();
})
.catch(function() { /* keine Bilddatei vorhanden - ignorieren */ });
// Gesteinsart-Zuordnung laden (optional)
fetch(GESTEIN_URL)
.then(function(r) { return r.text(); })
.then(function(text) {
var start = text.indexOf('{');
gesteinData = start !== -1 ? JSON.parse(text.slice(start)) : {};
if (mainArea.style.display !== 'none') render();
})
.catch(function() { /* keine Gesteinsart-Datei vorhanden - ignorieren */ });
// ---- Daten laden ----
fetch(DATA_URL)
.then(function(r) { return r.json(); })
.then(function(json) {
fullData = json;
if (IS_ANFRAGE) {
// Anfrage-Modus: kein PLZ-Gate, direkt Artikelliste (Preise werden ausgeblendet)
aktiviereListe(ANFRAGE_LISTE, '');
} else {
// Optionaler Direktaufruf fuer interne Zwecke: ?liste=N-Z1
var params = new URLSearchParams(window.location.search);
var direct = (params.get('liste') || '').toUpperCase();
if (VALID_KEYS.indexOf(direct) !== -1) {
aktiviereListe(direct, direct);
}
}
})
.catch(function(err) {
if (gateMsg) gateMsg.textContent = 'Preisliste konnte nicht geladen werden.';
console.error('Preisliste Fehler:', err);
});
// PLZ-Tabelle lazy laden
function ladePlzDaten() {
if (plzData) return Promise.resolve(plzData);
return fetch(PLZ_URL)
.then(function(r) { return r.text(); })
.then(function(text) {
plzData = parsePlzCsv(text);
// Werkskoordinaten aus Tabelle uebernehmen, falls vorhanden
if (plzData[WERK_LEER.plz]) { WERK_LEER.lat = plzData[WERK_LEER.plz][0]; WERK_LEER.lng = plzData[WERK_LEER.plz][1]; }
if (plzData[WERK_OST.plz]) { WERK_OST.lat = plzData[WERK_OST.plz][0]; WERK_OST.lng = plzData[WERK_OST.plz][1]; }
return plzData;
});
}
function parsePlzCsv(text) {
var map = {};
var lines = text.split(/\r?\n/);
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
if (!line) continue;
var parts = line.split(',');
if (parts.length < 3) continue;
var plz = parts[0].trim();
if (!/^\d{5}$/.test(plz)) continue; // Kopfzeile / ungueltige ueberspringen
var lat = parseFloat(parts[1]);
var lng = parseFloat(parts[2]);
if (!isNaN(lat) && !isNaN(lng)) map[plz] = [lat, lng];
}
return map;
}
// ---- Geo ----
function haversine(lat1, lng1, lat2, lng2) {
var R = 6371; // km
var toRad = Math.PI / 180;
var dLat = (lat2 - lat1) * toRad;
var dLng = (lng2 - lng1) * toRad;
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1 * toRad) * Math.cos(lat2 * toRad) *
Math.sin(dLng / 2) * Math.sin(dLng / 2);
return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
}
function ermittleListe(plz) {
var c = plzData[plz];
if (!c) return null;
var dLeer = haversine(c[0], c[1], WERK_LEER.lat, WERK_LEER.lng);
var dOst = haversine(c[0], c[1], WERK_OST.lat, WERK_OST.lng);
var nord = dLeer <= dOst;
var dWerk = nord ? dLeer : dOst;
var zone = dWerk <= ZONE_GRENZE_KM ? 1 : 2;
var key = (nord ? 'N' : 'O') + '-Z' + zone;
var label = (nord ? 'Nord' : 'Ost') + ', Zone ' + zone;
return { key: key, label: label, dist: Math.round(dWerk) };
}
// ---- PLZ-Gate ----
function pruefePlz() {
var raw = (plzInput.value || '').trim();
if (/^\d{1,5}$/.test(raw)) {
while (raw.length < 5) raw = '0' + raw; // fuehrende Nullen
}
if (!/^\d{5}$/.test(raw)) {
gateMsg.textContent = 'Bitte eine g\u00fcltige 5-stellige Postleitzahl eingeben.';
return;
}
gateMsg.textContent = 'Ermittle passende Preisliste\u2026';
ladePlzDaten().then(function() {
var res = ermittleListe(raw);
if (!res) {
gateMsg.textContent = 'Zu dieser Postleitzahl wurde kein Standort gefunden. Bitte pr\u00fcfen Sie die Eingabe oder kontaktieren Sie uns.';
return;
}
if (!fullData || !fullData[res.key]) {
gateMsg.textContent = 'F\u00fcr Ihre Region (' + res.label + ') liegt aktuell keine Preisliste vor. Bitte kontaktieren Sie uns.';
return;
}
gateMsg.textContent = '';
aktiviereListe(res.key, res.label + ' (ca. ' + res.dist + ' km)');
}).catch(function(err) {
gateMsg.textContent = 'Die Standortdaten konnten nicht geladen werden.';
console.error('PLZ-Daten Fehler:', err);
});
}
if (plzBtn) plzBtn.addEventListener('click', pruefePlz);
if (plzInput) plzInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter') { e.preventDefault(); pruefePlz(); }
});
if (plzChangeBtn) {
plzChangeBtn.addEventListener('click', function() {
mainArea.style.display = 'none';
gate.style.display = 'block';
plzInput.value = '';
plzInput.focus();
});
}
// ---- Liste aktivieren ----
// Gebinde-Fortsetzungszeilen zusammenfuehren.
// Fall: In der Excel steht ein Gebinde ueber zwei Zeilen (z. B. "1 Palette" / "ca. 1500 KG").
// Die zweite Zeile hat KEINE Artikelnummer und KEINE Preise -> sie ist keine eigene Variante,
// sondern gehoert zum Gebinde der vorherigen Variante.
// Abgrenzung: Varianten ohne Artnr, aber MIT Preis (z. B. "lose" bei Wegedecken) bleiben eigenstaendig.
function normalisiereVarianten(liste) {
if (!liste || !liste.length) return liste;
function leer(v) { return v === null || v === undefined || String(v).trim() === ''; }
liste.forEach(function(item) {
if (!item.varianten || item.varianten.length < 2) return;
var neu = [];
item.varianten.forEach(function(v) {
var ohneArtnr = leer(v.artikelnummer);
var ohnePreis = leer(v.preis_ab_werk) && leer(v.preis_ab5t) && leer(v.preis_ab12t) && leer(v.preis_ab24t);
if (ohneArtnr && ohnePreis && !leer(v.gebinde) && neu.length > 0) {
var prev = neu[neu.length - 1];
prev.gebinde = (leer(prev.gebinde) ? '' : prev.gebinde + ', ') + String(v.gebinde).trim();
} else {
neu.push(v);
}
});
item.varianten = neu;
});
return liste;
}
function aktiviereListe(key, label) {
listeKey = key;
allData = normalisiereVarianten((fullData && fullData[key]) ? fullData[key] : []);
if (listeInfo && !IS_ANFRAGE) {
listeInfo.textContent = key;
}
if (gate) gate.style.display = 'none';
mainArea.style.display = 'block';
// Filter zuruecksetzen
searchInput.value = '';
kategorieSelect.value = '';
farbeSelect.value = '';
koernungSelect.value = '';
render();
}
// ---- Filter-Logik ----
function passes(item, f) {
if (f.kategorie && item.kategorie !== f.kategorie) return false;
if (f.farbe && item.farbe !== f.farbe) return false;
if (f.koernung) {
var ok = false;
for (var vi = 0; vi < item.varianten.length; vi++) {
if (item.varianten[vi].koernung === f.koernung) { ok = true; break; }
}
if (!ok) return false;
}
if (f.search) {
var parts = [item.bezeichnung, item.farbe, item.kategorie];
for (var vj = 0; vj < item.varianten.length; vj++) {
parts.push(item.varianten[vj].koernung + ' ' + item.varianten[vj].artikelnummer);
}
if (parts.join(' ').toLowerCase().indexOf(f.search) === -1) return false;
}
return true;
}
function aktuelleFilter() {
return {
search: searchInput.value.trim().toLowerCase(),
kategorie: kategorieSelect.value,
farbe: farbeSelect.value,
koernung: koernungSelect.value
};
}
function clone(f, ohne) {
var c = { search: f.search, kategorie: f.kategorie, farbe: f.farbe, koernung: f.koernung };
c[ohne] = '';
return c;
}
function distinct(items, getter) {
var seen = [];
items.forEach(function(item) {
var vals = getter(item);
vals.forEach(function(v) { if (v && seen.indexOf(v) === -1) seen.push(v); });
});
return seen.sort();
}
function rebuildSelect(select, defaultLabel, values, currentVal) {
select.innerHTML = '';
var def = document.createElement('option');
def.value = '';
def.textContent = defaultLabel;
select.appendChild(def);
values.forEach(function(val) {
var opt = document.createElement('option');
opt.value = val;
opt.textContent = val;
select.appendChild(opt);
});
select.value = (values.indexOf(currentVal) !== -1) ? currentVal : '';
}
function updateFacets() {
var f = aktuelleFilter();
var katItems = allData.filter(function(it) { return passes(it, clone(f, 'kategorie')); });
rebuildSelect(kategorieSelect, KAT_DEFAULT, distinct(katItems, function(it) { return [it.kategorie]; }), f.kategorie);
var farbeItems = allData.filter(function(it) { return passes(it, clone(f, 'farbe')); });
rebuildSelect(farbeSelect, FARBE_DEFAULT, distinct(farbeItems, function(it) { return [it.farbe]; }), f.farbe);
var koernItems = allData.filter(function(it) { return passes(it, clone(f, 'koernung')); });
rebuildSelect(koernungSelect, KOERN_DEFAULT, distinct(koernItems, function(it) {
return it.varianten.map(function(v) { return v.koernung; });
}), f.koernung);
}
function updateClearButtons() {
if (clearKategorie) clearKategorie.style.display = kategorieSelect.value !== '' ? 'inline-block' : 'none';
if (clearFarbe) clearFarbe.style.display = farbeSelect.value !== '' ? 'inline-block' : 'none';
if (clearKoernung) clearKoernung.style.display = koernungSelect.value !== '' ? 'inline-block' : 'none';
}
// ---- Darstellung ----
function kategorieFarbe(kat) {
var k = (kat || '').toUpperCase();
for (var gi = 0; gi < KATEGORIE_FARBEN.length; gi++) {
var grp = KATEGORIE_FARBEN[gi];
for (var ki = 0; ki < grp.kats.length; ki++) {
if (k.indexOf(grp.kats[ki]) === 0) return grp.farbe;
}
}
return '#888888';
}
function formatPrice(p) {
if (p === null || p === undefined) return '\u2013';
if (typeof p === 'number') return p.toLocaleString('de-DE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' \u20ac';
return p;
}
function escapeHtml(str) {
var div = document.createElement('div');
div.textContent = str;
return div.innerHTML;
}
function escapeAttr(s) {
return String(s)
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"');
}
function normBild(v) {
if (!v) return null;
if (typeof v === 'string') return { bild: v, link: null };
return v;
}
// WordPress-Vorschaubild aus der Original-URL ableiten (Format siehe THUMB_SUFFIX)
var THUMB_SUFFIX = '-300x400'; // muss einer in WordPress erzeugten Bildgroesse entsprechen
function thumbUrl(bild) {
if (!bild) return bild;
return bild.replace(/\.(jpe?g|png|gif|webp)$/i, THUMB_SUFFIX + '.$1');
}
function mittelteil(an) {
var core = (an || '').toUpperCase().trim().split('-')[0];
return core.length > 2 ? core.substring(2) : '';
}
function normTxt(s) {
return (s || '').toUpperCase().replace(/\s+/g, ' ').trim();
}
function bildInfo(item) {
var i, mt;
// 1. exakte Artikelnummer einer Variante
if (item.varianten) {
for (i = 0; i < item.varianten.length; i++) {
var an = (item.varianten[i].artikelnummer || '').toUpperCase().trim();
if (an && bildData[an]) return normBild(bildData[an]);
}
// 2. Mittelteil (Material+Koernung+Farbe)
for (i = 0; i < item.varianten.length; i++) {
mt = mittelteil(item.varianten[i].artikelnummer);
if (mt && bildData[mt]) return normBild(bildData[mt]);
}
// 3. Material+Farbe (Koernung ignoriert)
for (i = 0; i < item.varianten.length; i++) {
mt = mittelteil(item.varianten[i].artikelnummer);
if (mt && mt.length === 9) {
var mf = mt.substring(0, 2) + mt.substring(6, 9);
if (bildData[mf]) return normBild(bildData[mf]);
}
}
}
var bez = normTxt(item.bezeichnung);
var farbe = normTxt(item.farbe);
var koern = normTxt(item.varianten && item.varianten[0] ? item.varianten[0].koernung : '');
// 4. BEZEICHNUNG|FARBE|KOERNUNG
if (koern && bildData[bez + '|' + farbe + '|' + koern]) return normBild(bildData[bez + '|' + farbe + '|' + koern]);
// 5. BEZEICHNUNG|FARBE
return normBild(bildData[bez + '|' + farbe]);
}
// Gesteinsart eines Artikels ueber den Mittelteil einer Variante
function gesteinVon(item) {
if (!item.varianten) return '';
for (var i = 0; i < item.varianten.length; i++) {
var an = (item.varianten[i].artikelnummer || '').toUpperCase().trim();
if (an && gesteinData[an]) return gesteinData[an]; // exakte Artnr
var mt = mittelteil(item.varianten[i].artikelnummer);
if (mt && gesteinData[mt]) return gesteinData[mt]; // Mittelteil
}
return '';
}
function render() {
updateFacets();
updateClearButtons();
var f = aktuelleFilter();
var filtered = allData.filter(function(it) { return passes(it, f); });
resultsDiv.innerHTML = '';
if (filtered.length === 0) {
if (emptyDiv) emptyDiv.style.display = 'block';
return;
}
if (emptyDiv) emptyDiv.style.display = 'none';
filtered.forEach(function(item) {
var katFarbe = kategorieFarbe(item.kategorie);
var farbeInline = item.farbe ? ' ' + escapeHtml(item.farbe) + ' ' : '';
var gestein = gesteinVon(item);
var gesteinInline = gestein ? ' ' + escapeHtml(gestein) + ' ' : '';
var info = bildInfo(item);
var rows = item.varianten.map(function(v) {
var d = 'data-kat="' + escapeAttr(item.kategorie || '') + '" data-bez="' + escapeAttr(item.bezeichnung || '') + '" data-farbe="' + escapeAttr(item.farbe || '') + '" data-koern="' + escapeAttr(v.koernung || '') + '" data-art="' + escapeAttr(v.artikelnummer || '') + '"';
var preisTds = IS_ANFRAGE ? '' :
'
' + escapeHtml(String(formatPrice(v.preis_ab_werk))) + ' ' +
'' + escapeHtml(String(formatPrice(v.preis_ab5t))) + ' ' +
'' + escapeHtml(String(formatPrice(v.preis_ab12t))) + ' ' +
'' + escapeHtml(String(formatPrice(v.preis_ab24t))) + ' ';
return '' +
'' + escapeHtml(v.koernung || '\u2013') + ' ' +
'' + escapeHtml(v.gebinde || '\u2013') + ' ' +
'' + escapeHtml(v.artikelnummer || '\u2013') + ' ' +
preisTds +
'Hinzuf\u00fcgen Zur ' + LABEL + ' hinzuf\u00fcgen ' +
' ';
}).join('');
var preisThs = IS_ANFRAGE ? '' :
'Ab Werk ' +
'Frei Lager ab 5 t ' +
'Frei Lager ab 12 t ' +
'Frei Lager ab 24 t ';
var tableHtml =
'' +
'K\u00f6rnung / Ma\u1e9ee / Format ' +
'Gebinde ' +
'Artikel-Nr. ' +
preisThs +
'' + LABEL + ' ' +
' ' + rows + '
';
var categoryHtml = '' + escapeHtml(item.kategorie || '') + '
';
var titleHtml = '' + escapeHtml(item.bezeichnung) + farbeInline + gesteinInline + '
';
var bodyHtml;
if (BILD_MODUS === 'gross' && info && info.bild) {
var img = ' ';
if (info.link) img = '' + img + ' ';
bodyHtml =
'' +
'
' + img + '
' +
'
' +
'' +
tableHtml +
'
' +
'
';
} else if (BILD_MODUS === 'klein_link' && info && info.bild) {
var thumb = ' ';
if (info.link) thumb = '' + thumb + ' ';
bodyHtml =
'' +
tableHtml;
} else {
bodyHtml = '' + tableHtml;
}
var card = document.createElement('div');
card.className = 'pl-card';
card.innerHTML = categoryHtml + bodyHtml;
resultsDiv.appendChild(card);
});
}
// ---- CSV / Excel-Export ----
function csvCell(val) {
var s = (val === null || val === undefined) ? '' : String(val);
if (s.indexOf(';') !== -1 || s.indexOf('"') !== -1 || s.indexOf('\n') !== -1) {
s = '"' + s.replace(/"/g, '""') + '"';
}
return s;
}
function preisCsv(p) {
if (p === null || p === undefined) return '';
if (typeof p === 'number') return String(p).replace('.', ',');
return p;
}
function exportExcel() {
var f = aktuelleFilter();
var filtered = allData.filter(function(it) { return passes(it, f); });
var header = IS_ANFRAGE
? ['Kategorie', 'Bezeichnung', 'Farbe', 'Gesteinsart', 'K\u00f6rnung / Ma\u00dfe / Format', 'Gebinde', 'Artikel-Nr.']
: ['Kategorie', 'Bezeichnung', 'Farbe', 'K\u00f6rnung / Ma\u00dfe / Format', 'Gebinde', 'Artikel-Nr.', 'Ab Werk', 'Frei Lager ab 5 t', 'Frei Lager ab 12 t', 'Frei Lager ab 24 t'];
var lines = [header.map(csvCell).join(';')];
filtered.forEach(function(item) {
var gestein = IS_ANFRAGE ? gesteinVon(item) : '';
item.varianten.forEach(function(v) {
var row = IS_ANFRAGE ? [
item.kategorie || '', item.bezeichnung || '', item.farbe || '', gestein,
v.koernung || '', v.gebinde || '', v.artikelnummer || ''
] : [
item.kategorie || '', item.bezeichnung || '', item.farbe || '',
v.koernung || '', v.gebinde || '', v.artikelnummer || '',
preisCsv(v.preis_ab_werk), preisCsv(v.preis_ab5t), preisCsv(v.preis_ab12t), preisCsv(v.preis_ab24t)
];
lines.push(row.map(csvCell).join(';'));
});
});
var csv = '\ufeff' + lines.join('\r\n'); // BOM fuer Excel/Umlaute
var blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
var datum = new Date().toISOString().slice(0, 10);
a.href = url;
a.download = (IS_ANFRAGE ? 'Sortiment_' : 'Preisliste_') + datum + '.csv';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
if (excelBtn) excelBtn.addEventListener('click', exportExcel);
// ---- Filter-Events ----
searchInput.addEventListener('input', render);
kategorieSelect.addEventListener('change', render);
farbeSelect.addEventListener('change', render);
koernungSelect.addEventListener('change', render);
if (clearKategorie) clearKategorie.addEventListener('click', function() { kategorieSelect.value = ''; render(); });
if (clearFarbe) clearFarbe.addEventListener('click', function() { farbeSelect.value = ''; render(); });
if (clearKoernung) clearKoernung.addEventListener('click', function() { koernungSelect.value = ''; render(); });
setupLightbox();
setupBestellung();
}
// ==========================================================================
// BESTELLANFRAGE / WARENKORB
// ==========================================================================
// NACH dem Gravity-Forms-Import hier die Formular-ID eintragen (Zahl):
var BESTELL_FORM_ID = null; // z. B. 9 -> aus der GF-Formularliste (Spalte ID)
var VORLAUF_WERKTAGE = 10; // frühestes Wunschlieferdatum = heute + X Werktage
var CART_KEY = 'weco_pl_cart_v1';
function setupBestellung() {
if (window.__plCart) return;
window.__plCart = true;
var resultsDiv = document.getElementById('pl-results');
var appEl2 = document.getElementById('preisliste-app');
var IS_ANFRAGE = !!(appEl2 && (appEl2.getAttribute('data-modus') || '').toLowerCase() === 'anfrage');
var LABEL = IS_ANFRAGE ? 'Anfrage' : 'Bestellanfrage';
function escapeHtml(s) { var d = document.createElement('div'); d.textContent = (s == null ? '' : String(s)); return d.innerHTML; }
function escapeAttr(s) { return String(s == null ? '' : s).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); }
var KAT_FARBEN = [
{ farbe: '#ABB5D8', kats: ['GARTENMINERALIEN', 'LAVAMULCH', 'BIENENSAND'] },
{ farbe: '#A2C62F', kats: ['ZIERKIES', 'ZIERSPLITT', 'DEKOSTEINE', 'EASIHOLD', 'POLYGONALPLATTEN', 'KERAMISCHE TRITTPLATTEN', 'NATURSTEINPFLASTER', 'GRANIT', 'BETON', 'KR\u00c4UTERSPIRALEN', 'CO2 NEUTRALER BETONSTEIN', 'CO\u2082 NEUTRALER BETONSTEIN', 'BRUCHSTEINE', 'TROCKENMAUERWERK'] },
{ farbe: '#DB4E2A', kats: ['BAUSAND', 'STREU- & PFLASTERSPLITT', 'STREU- UND PFLASTERSPLITT', 'FUGEN-QUARZSAND', 'FUGENSPLITT', 'WASSERGEB. WEGEDECKE', 'WASSERGEBUNDENE WEGEDECKE'] },
{ farbe: '#F08013', kats: ['SPIELEN MIT SAND'] },
{ farbe: '#1EB5D2', kats: ['WASSERAUFBEREITUNG'] }
];
function katFarbeVon(kat) {
var k = (kat || '').toUpperCase();
for (var gi = 0; gi < KAT_FARBEN.length; gi++) {
for (var ki = 0; ki < KAT_FARBEN[gi].kats.length; ki++) {
if (k.indexOf(KAT_FARBEN[gi].kats[ki]) === 0) return KAT_FARBEN[gi].farbe;
}
}
return '#888888';
}
var cart = ladeCart();
// ---------- Styles (injiziert, damit der HTML-Block unberührt bleibt) ----------
var st = document.createElement('style');
st.textContent =
'#preisliste-app .pl-filters { position: static !important; }' +
'.pl-gestein-inline { font-size: 12px; font-weight: 600; color: #3a5a40; background: #eef3ec; padding: 2px 8px; border-radius: 5px; margin-left: 6px; vertical-align: middle; }' +
'.pl-order { text-align: center; vertical-align: middle; }' +
'.pl-order-head { text-align: center; }' +
'.pl-order .pl-add { padding: 7px 14px; border: none; border-radius: 5px; background: #1d6f42; color: #fff; font-size: 13px; font-weight: 600; cursor: pointer; }' +
'.pl-order .pl-add:hover { background: #155232; }' +
'.pl-add-full { display: none; }' +
'.pl-add-short { display: inline; }' +
'.pl-cart-fab { position: fixed; right: 20px; bottom: 20px; z-index: 100001; padding: 10px 16px; border: none; border-radius: 26px; background: #1d6f42; color: #fff; font-size: 14px; font-weight: 600; cursor: pointer; box-shadow: 0 4px 14px rgba(0,0,0,0.25); display: none; }' +
'.pl-cart-fab.show { display: inline-block; }' +
'.pl-cart-panel { position: fixed; right: 16px; bottom: 76px; top: auto; height: min(80vh, 820px); width: 380px; max-width: 90vw; background: #fff; z-index: 100002; border: 1px solid #ddd; border-radius: 10px; box-shadow: 0 8px 30px rgba(0,0,0,0.25); transform: translateX(calc(100% + 24px)); transition: transform 0.25s ease; display: flex; flex-direction: column; overflow: hidden; }' +
'.pl-cart-panel.open { transform: translateX(0); }' +
'.pl-cart-head { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px; border-bottom: 1px solid #e5e5e5; background: #1d6f42; }' +
'.pl-cart-head h3 { margin: 0; font-size: 15px; color: #fff; }' +
'.pl-cart-close { background: none; border: none; font-size: 24px; line-height: 1; cursor: pointer; color: #fff; }' +
'.pl-cart-list { flex: 1 1 auto; overflow-y: auto; padding: 10px 14px; }' +
'.pl-cart-empty { color: #888; text-align: center; padding: 30px 0; font-size: 13px; }' +
'.pl-cart-item { border: 1px solid #e8e8e8; border-radius: 7px; overflow: hidden; margin-bottom: 10px; }' +
'.pl-cart-item .pl-ci-head { padding: 6px 10px; color: #fff; }' +
'.pl-cart-item .pl-ci-name { font-weight: 700; font-size: 13px; }' +
'.pl-cart-item .pl-ci-farbe { font-weight: 400; font-size: 12px; opacity: 0.9; margin-left: 4px; }' +
'.pl-cart-item .pl-ci-body { padding: 8px 10px; }' +
'.pl-cart-item .pl-ci-sub { font-size: 11px; color: #666; margin: 0 0 6px; }' +
'.pl-cart-item .pl-ci-row { display: flex; align-items: center; gap: 6px; }' +
'.pl-cart-item .pl-ci-menge, .pl-cart-item .pl-ci-einheit { flex: 1 1 0 !important; width: auto !important; min-width: 0 !important; height: 32px !important; box-sizing: border-box !important; padding: 4px 8px !important; border: 1px solid #ccc !important; border-radius: 5px !important; font-size: 13px !important; margin: 0 !important; }' +
'.pl-cart-item .pl-ci-del { flex: 0 0 auto; background: none; border: none; color: #c0392b; cursor: pointer; font-size: 12px; text-decoration: underline; padding: 0; }' +
'.pl-cart-foot { border-top: 1px solid #e5e5e5; padding: 10px 14px; }' +
'.pl-cart-hint { font-size: 11px; color: #777; margin: 0 0 8px; }' +
'.pl-cart-checkout { width: 100%; padding: 10px; border: none; border-radius: 6px; background: #A2C62F; color: #fff; font-size: 14px; font-weight: 600; cursor: pointer; }' +
'.pl-cart-checkout:hover { background: #82a024; }' +
'.pl-cart-checkout:disabled { background: #ccc; cursor: not-allowed; }' +
'.pl-cart-clear { width: 100%; margin-top: 6px; padding: 6px; border: 1px solid #ccc; border-radius: 6px; background: #f5f5f5; font-size: 12px; cursor: pointer; }' +
'.pl-cart-data { display: none !important; }' +
// ===================== RESPONSIVE =====================
// Tablets / kleinere Desktops: Karte kompakter, Bild kleiner
'@media (max-width: 1024px) {' +
'#preisliste-app { max-width: 100% !important; }' +
'#preisliste-app .pl-card-img { flex: 0 0 130px !important; }' +
'#preisliste-app table.pl-variants { font-size: 13px; }' +
'#preisliste-app table.pl-variants th, #preisliste-app table.pl-variants td { padding: 6px 8px; }' +
'}' +
// Handys / schmale Tablets: Tabelle -> gestapelte Zeilen-Karten
'@media (max-width: 820px) {' +
'#preisliste-app .pl-card { padding: 12px 14px; }' +
'#preisliste-app .pl-category { margin: -12px -14px 10px -14px; padding: 8px 14px; font-size: 12px; }' +
'#preisliste-app .pl-card-body { flex-direction: column !important; gap: 12px !important; }' +
'#preisliste-app .pl-card-img { flex: 0 0 auto !important; width: 100% !important; max-width: 200px !important; margin: 0 auto !important; }' +
'#preisliste-app .pl-card-img img { aspect-ratio: 4 / 3 !important; }' +
'#preisliste-app .pl-card-content { overflow-x: visible !important; }' +
'#preisliste-app .pl-card-title { font-size: 16px; }' +
// Tabelle aufbrechen
'#preisliste-app table.pl-variants { display: block; width: 100%; border-collapse: collapse; }' +
'#preisliste-app table.pl-variants thead { display: none; }' +
'#preisliste-app table.pl-variants tbody, #preisliste-app table.pl-variants tr, #preisliste-app table.pl-variants td { display: block; width: 100%; }' +
'#preisliste-app table.pl-variants tr { border: 1px solid #e5e5e5; border-radius: 8px; padding: 8px 10px; margin-bottom: 10px; background: #fff; }' +
'#preisliste-app table.pl-variants td { border: none !important; padding: 3px 0 !important; white-space: normal !important; text-align: left !important; display: flex; justify-content: space-between; align-items: baseline; gap: 12px; font-size: 13px; }' +
'#preisliste-app table.pl-variants td[data-label]::before { content: attr(data-label); font-size: 11px; font-weight: 700; color: #777; text-transform: uppercase; flex: 0 0 auto; }' +
'#preisliste-app table.pl-variants td.pl-price { text-align: right !important; }' +
'#preisliste-app table.pl-variants td.pl-order { display: block; margin-top: 8px; padding-top: 8px !important; border-top: 1px solid #eee !important; }' +
'#preisliste-app table.pl-variants td.pl-order .pl-add { width: 100%; padding: 10px; font-size: 14px; }' +
'#preisliste-app table.pl-variants td.pl-order .pl-add-short { display: none; }' +
'#preisliste-app table.pl-variants td.pl-order .pl-add-full { display: inline; }' +
'}' +
// Warenkorb-Panel + Formular auf Handys
'@media (max-width: 600px) {' +
'.pl-cart-panel { right: 8px !important; left: 8px !important; bottom: 70px !important; width: auto !important; max-width: none !important; height: min(70vh, 520px) !important; }' +
'.pl-cart-fab { right: 12px !important; bottom: 12px !important; font-size: 13px !important; padding: 9px 14px !important; }' +
'.gform_wrapper { padding: 14px !important; }' +
'#pl-confirm-popup .pl-cp-box { padding: 22px 18px; }' +
'#preisliste-app .pl-headline { font-size: 28px !important; }' +
'#preisliste-app .pl-filters { gap: 8px !important; padding: 8px 0 !important; }' +
'#preisliste-app .pl-filters input, #preisliste-app .pl-filters select { padding: 9px 10px !important; font-size: 14px !important; }' +
'#preisliste-app .pl-filter-row { flex-direction: column !important; gap: 8px !important; }' +
'#preisliste-app .pl-toolbar { flex-direction: column; align-items: stretch; }' +
'#preisliste-app .pl-toolbar button { width: 100%; }' +
'#preisliste-app #pl-gate { padding: 14px !important; }' +
'#preisliste-app #pl-plz, #preisliste-app #pl-plz-btn { flex: 1 1 100% !important; }' +
'.pl-cart-item .pl-ci-row { flex-wrap: wrap; }' +
'}' +
'.pl-order-summary { border: 1px solid #e0e0e0; border-radius: 8px; padding: 14px 18px; margin: 0 0 20px; background: #fafafa; scroll-margin-top: 150px; }' +
'.pl-order-summary h4 { margin: 0 0 10px; font-size: 16px; }' +
'.pl-order-summary ul { list-style: none; margin: 0; padding: 0; }' +
'.pl-order-summary li { padding: 8px 12px; margin: 0 0 6px; background: #fff; border: 1px solid #e5e5e5; border-radius: 6px; font-size: 14px; line-height: 1.5; }' +
'.pl-order-summary li:last-child { margin-bottom: 0; }' +
'.pl-order-note { margin: 10px 0 0 !important; font-size: 12px; color: #555; line-height: 1.5; }' +
'#pl-confirm-popup { position: fixed; inset: 0; background: rgba(0,0,0,0.55); z-index: 100003; display: flex; align-items: center; justify-content: center; padding: 20px; }' +
'#pl-confirm-popup .pl-cp-box { background: #fff; border-radius: 10px; max-width: 460px; width: 100%; padding: 28px 26px; text-align: center; box-shadow: 0 10px 40px rgba(0,0,0,0.3); }' +
'#pl-confirm-popup .pl-cp-icon { width: 52px; height: 52px; margin: 0 auto 14px; border-radius: 50%; background: #A2C62F; color: #fff; font-size: 30px; line-height: 52px; }' +
'#pl-confirm-popup .pl-cp-msg { font-size: 14px; line-height: 1.6; color: #333; margin-bottom: 18px; }' +
'#pl-confirm-popup .pl-cp-close { padding: 10px 26px; border: none; border-radius: 6px; background: #1d6f42; color: #fff; font-size: 14px; font-weight: 600; cursor: pointer; }' +
'#pl-confirm-popup .pl-cp-close:hover { background: #155232; }' +
'.pl-add-flash { outline: 2px solid #A2C62F; }' +
// Bestellformular bis zum Checkout ausblenden (per CSS, timing-unabhaengig)
'.gform_wrapper:not(.pl-form-visible), .gform-wrapper:not(.pl-form-visible) { display: none !important; }' +
// Gravity-Forms-Formular: kompakt, 2-spaltig, Weco-Look
'.gform_wrapper { max-width: 860px !important; background: #fafafa !important; border: 1px solid #e0e0e0 !important; border-radius: 8px !important; padding: 22px 26px !important; }' +
'.gform_wrapper .gform_fields { display: grid !important; grid-template-columns: repeat(12, 1fr) !important; gap: 12px 22px !important; }' +
'.gform_wrapper .gfield { grid-column: span 6 !important; }' +
'.gform_wrapper .gfield--type-textarea, .gform_wrapper .gfield--type-checkbox, .gform_wrapper .gfield--type-section, .gform_wrapper .pl-cart-data { grid-column: span 12 !important; }' +
'@media (max-width: 700px) { .gform_wrapper .gfield { grid-column: span 12 !important; } }' +
'html body .gform_wrapper .gform_fields .gfield .gfield_label, html body .gform_wrapper label.gfield_label, html body .gform_wrapper legend.gfield_label { font-size: 12px !important; font-weight: 600 !important; margin-bottom: 3px !important; line-height: 1.3 !important; letter-spacing: 0 !important; }' +
'.gform_wrapper .gsection, .gform_wrapper .gfield--type-section { border-bottom: 1px solid #ddd !important; padding-bottom: 4px !important; margin-top: 4px !important; }' +
'.gform_wrapper .gsection_title, .gform_wrapper .gfield--type-section h2, .gform_wrapper .gfield--type-section h3 { font-size: 14px !important; font-weight: 700 !important; margin: 0 !important; }' +
'.gform_wrapper .gfield_required { color: #DB4E2A !important; }' +
'.gform_wrapper .gfield_description { font-size: 11px !important; color: #777 !important; }' +
'.gform_wrapper input[type="text"], .gform_wrapper input[type="email"], .gform_wrapper input[type="tel"], .gform_wrapper input[type="number"], .gform_wrapper select, .gform_wrapper textarea { width: 100% !important; padding: 7px 10px !important; font-size: 13px !important; border: 1px solid #ccc !important; border-radius: 6px !important; background: #fff !important; box-sizing: border-box !important; }' +
'.gform_wrapper textarea { min-height: 70px !important; }' +
'.gform_wrapper .gchoice { display: flex !important; align-items: flex-start !important; gap: 8px !important; }' +
'.gform_wrapper .gchoice input[type="checkbox"] { margin-top: 3px !important; flex: 0 0 auto !important; }' +
'.gform_wrapper .ginput_container_checkbox label, .gform_wrapper .gfield_checkbox label { font-size: 13px !important; font-weight: 400 !important; line-height: 1.5 !important; flex: 1 1 auto !important; }' +
// Absende-Button: sichtbar erzwingen (Divi blendet Formular-Buttons gern aus) + Weco-Look
'.gform_wrapper .gform_footer, .gform_wrapper .gform-footer { display: block !important; margin-top: 18px !important; }' +
'.gform_wrapper input[type="submit"], .gform_wrapper button[type="submit"], .gform_wrapper .gform_button { display: inline-block !important; visibility: visible !important; opacity: 1 !important; padding: 12px 28px !important; border: none !important; border-radius: 6px !important; background: #A2C62F !important; color: #fff !important; font-size: 15px !important; font-weight: 600 !important; cursor: pointer !important; line-height: 1.3 !important; }' +
'.gform_wrapper input[type="submit"]:hover, .gform_wrapper .gform_button:hover { background: #82a024 !important; }';
document.head.appendChild(st);
// ---------- UI-Elemente (Panel + Overlay + FAB) ----------
var fab = document.createElement('button');
fab.type = 'button'; fab.className = 'pl-cart-fab';
document.body.appendChild(fab);
var panel = document.createElement('div');
panel.className = 'pl-cart-panel';
panel.innerHTML =
'
Ihre ' + LABEL + ' \u00d7 ' +
'
' +
'';
document.body.appendChild(panel);
var listEl = panel.querySelector('.pl-cart-list');
var checkoutBtn = panel.querySelector('.pl-cart-checkout');
// ---------- Speicherung ----------
function ladeCart() {
try { var r = window.localStorage.getItem(CART_KEY); return r ? JSON.parse(r) : []; }
catch (e) { return []; }
}
function speichere() {
try { window.localStorage.setItem(CART_KEY, JSON.stringify(cart)); } catch (e) {}
}
// ---------- Warenkorb-Operationen ----------
function keyOf(it) { return (it.art || '') + '|' + it.einheit; }
function addItem(it) {
for (var i = 0; i < cart.length; i++) {
if (keyOf(cart[i]) === keyOf(it)) { cart[i].menge += it.menge; speichere(); renderCart(); return; }
}
cart.push(it); speichere(); renderCart();
}
function leeren() { cart = []; speichere(); renderCart(); }
function renderCart() {
// FAB
var n = cart.length;
fab.textContent = '\uD83D\uDCCB ' + LABEL + ' (' + n + ')';
fab.className = 'pl-cart-fab' + (n > 0 ? ' show' : '');
checkoutBtn.disabled = (n === 0);
// Liste
if (n === 0) {
listEl.innerHTML = 'Noch keine Artikel ausgew\u00e4hlt.
';
closePanel();
return;
}
listEl.innerHTML = cart.map(function(it, idx) {
var sub = [it.koern, it.art].filter(Boolean).join(' \u00b7 ');
var farbe = it.farbe ? '' + escapeHtml(it.farbe) + ' ' : '';
return '' +
'
' +
'' + escapeHtml(it.bez) + ' ' + farbe +
'
' +
'
' +
'
' + escapeHtml(sub) + '
' +
'
' +
' ' +
'' +
['Tonnen','Stück','Paletten'].map(function(u){ return '' + u + ' '; }).join('') +
' ' +
'Entfernen ' +
'
' +
'
' +
'
';
}).join('');
}
function openPanel() { panel.classList.add('open'); }
function closePanel() { panel.classList.remove('open'); }
// ---------- Events ----------
fab.addEventListener('click', openPanel);
panel.querySelector('.pl-cart-close').addEventListener('click', closePanel);
panel.querySelector('.pl-cart-clear').addEventListener('click', function() {
if (cart.length && window.confirm('Auswahl wirklich leeren?')) leeren();
});
// "Hinzufügen" pro Zeile (Delegation auf Ergebnisliste)
if (resultsDiv) {
resultsDiv.addEventListener('click', function(e) {
var btn = e.target.closest ? e.target.closest('.pl-add') : null;
if (!btn) return;
addItem({
kat: btn.getAttribute('data-kat'), bez: btn.getAttribute('data-bez'),
farbe: btn.getAttribute('data-farbe'), koern: btn.getAttribute('data-koern'),
art: btn.getAttribute('data-art'), katfarbe: btn.getAttribute('data-katfarbe'),
menge: 1, einheit: 'Tonnen'
});
openPanel();
btn.classList.add('pl-add-flash');
setTimeout(function(){ btn.classList.remove('pl-add-flash'); }, 400);
});
}
// Menge/Einheit im Panel ändern + entfernen
listEl.addEventListener('input', function(e) {
var wrap = e.target.closest('.pl-cart-item'); if (!wrap) return;
var idx = parseInt(wrap.getAttribute('data-idx'), 10);
if (e.target.classList.contains('pl-ci-menge')) {
var m = parseFloat((e.target.value || '').replace(',', '.'));
if (m > 0) { cart[idx].menge = m; speichere(); }
}
});
listEl.addEventListener('change', function(e) {
var wrap = e.target.closest('.pl-cart-item'); if (!wrap) return;
var idx = parseInt(wrap.getAttribute('data-idx'), 10);
if (e.target.classList.contains('pl-ci-einheit')) { cart[idx].einheit = e.target.value; speichere(); }
});
listEl.addEventListener('click', function(e) {
if (!e.target.classList.contains('pl-ci-del')) return;
var wrap = e.target.closest('.pl-cart-item');
var idx = parseInt(wrap.getAttribute('data-idx'), 10);
cart.splice(idx, 1); speichere(); renderCart();
});
// ---------- Checkout: Warenkorb -> Gravity-Forms-Feld + Formular anzeigen ----------
// Formular ist per CSS ausgeblendet und wird hier per Inline-Style eingeblendet
checkoutBtn.addEventListener('click', function() {
if (!cart.length) return;
var form = findForm();
if (!form) { alert('Das Bestellformular wurde auf dieser Seite nicht gefunden. Bitte stellen Sie sicher, dass das Gravity-Forms-Formular unter der Preisliste eingebunden ist (Shortcode in einem Text-Modul, korrekte Formular-ID).'); return; }
// verstecktes Feld füllen
var dataField = form.querySelector('.pl-cart-data textarea, .pl-cart-data input');
if (dataField) { dataField.value = cartText(); }
// Formular sichtbar machen + Zusammenfassung einfügen
form.classList.add('pl-form-visible');
var summaryBox = zeigeSummary(form);
closePanel();
(summaryBox || form).scrollIntoView({ block: 'start' });
});
function findForm() {
if (BESTELL_FORM_ID) {
var byId = document.querySelector('#gform_wrapper_' + BESTELL_FORM_ID);
if (byId) return byId;
}
return document.querySelector('.gform_wrapper, .gform-wrapper, form[id^="gform_"]');
}
function cartText() {
return cart.map(function(it, i) {
return (i + 1) + ') ' + it.bez + (it.farbe ? ' (' + it.farbe + ')' : '') +
' | Körnung/Maß: ' + (it.koern || '-') +
' | Art.-Nr.: ' + (it.art || '-') +
' | Menge: ' + it.menge + ' ' + it.einheit +
' | Kategorie: ' + (it.kat || '-');
}).join('\n');
}
function zeigeSummary(form) {
var old = document.getElementById('pl-order-summary');
if (old) old.parentNode.removeChild(old);
var box = document.createElement('div');
box.id = 'pl-order-summary'; box.className = 'pl-order-summary';
box.innerHTML = 'Ihre ' + cart.length + ' Position(en) ' +
cart.map(function(it) {
return '' + escapeHtml(it.bez) + (it.farbe ? ' (' + escapeHtml(it.farbe) + ')' : '') +
' \u2013 ' + escapeHtml(it.koern || '') + ' \u2013 ' + escapeHtml(String(it.menge)) + ' ' + escapeHtml(it.einheit) + ' ';
}).join('') + ' ' +
'Wichtiger Hinweis: Wir versenden nur in vollen Verpackungseinheiten. Sollte Ihre angegebene Menge von einer vollen VE abweichen, wird diese von uns erh\u00f6ht. Bei Fragen dazu melden Sie sich gerne!
';
form.parentNode.insertBefore(box, form);
return box;
}
// ---------- Gravity Forms: Datumsgrenze + Warenkorb nach Absenden leeren ----------
var jq = window.jQuery;
if (window.gform && gform.addFilter) {
gform.addFilter('gform_datepicker_options_pre_init', function(optionsObj, formId) {
if (BESTELL_FORM_ID && formId != BESTELL_FORM_ID) return optionsObj;
var earliest = werktagePlus(new Date(), VORLAUF_WERKTAGE);
optionsObj.minDate = earliest;
optionsObj.beforeShowDay = function(d) { return [istWerktag(d), '']; };
return optionsObj;
});
}
if (jq) {
jq(document).on('gform_confirmation_loaded', function(e, formId) {
if (BESTELL_FORM_ID && formId != BESTELL_FORM_ID) return;
leeren();
var s = document.getElementById('pl-order-summary'); if (s) s.parentNode.removeChild(s);
// Bestätigung als Pop-up statt inline
var conf = document.querySelector('#gform_confirmation_wrapper_' + formId + ', .gform_confirmation_message');
var msg = conf ? conf.innerHTML : 'Vielen Dank f\u00fcr Ihre ' + LABEL + '. Wir haben Ihre Anfrage erhalten und melden uns in K\u00fcrze bei Ihnen.
';
if (conf) conf.style.display = 'none';
zeigeConfirmPopup(msg);
});
}
function zeigeConfirmPopup(html) {
var old = document.getElementById('pl-confirm-popup');
if (old) old.parentNode.removeChild(old);
var ov = document.createElement('div');
ov.id = 'pl-confirm-popup';
ov.innerHTML = '\u2713
' + html + '
Schlie\u00dfen ';
document.body.appendChild(ov);
function close() { if (ov.parentNode) ov.parentNode.removeChild(ov); }
ov.addEventListener('click', function(e) { if (e.target === ov) close(); });
ov.querySelector('.pl-cp-close').addEventListener('click', close);
}
// ---------- Werktags-/Feiertagslogik (Niedersachsen) ----------
function ostern(year) {
var a = year % 19, b = Math.floor(year / 100), c = year % 100;
var d = Math.floor(b / 4), e = b % 4, f = Math.floor((b + 8) / 25);
var g = Math.floor((b - f + 1) / 3), h = (19 * a + b - d - g + 15) % 30;
var i = Math.floor(c / 4), k = c % 4, l = (32 + 2 * e + 2 * i - h - k) % 7;
var m = Math.floor((a + 11 * h + 22 * l) / 451);
var month = Math.floor((h + l - 7 * m + 114) / 31);
var day = ((h + l - 7 * m + 114) % 31) + 1;
return new Date(year, month - 1, day);
}
function feiertage(year) {
var o = ostern(year); var set = {};
function add(dt) { set[dt.getFullYear() + '-' + dt.getMonth() + '-' + dt.getDate()] = true; }
add(new Date(year, 0, 1)); // Neujahr
add(new Date(o.getTime() - 2 * 86400000)); // Karfreitag
add(new Date(o.getTime() + 1 * 86400000)); // Ostermontag
add(new Date(year, 4, 1)); // Tag der Arbeit
add(new Date(o.getTime() + 39 * 86400000)); // Christi Himmelfahrt
add(new Date(o.getTime() + 50 * 86400000)); // Pfingstmontag
add(new Date(year, 9, 3)); // Tag der Deutschen Einheit
add(new Date(year, 9, 31)); // Reformationstag (Niedersachsen)
add(new Date(year, 11, 25)); // 1. Weihnachtstag
add(new Date(year, 11, 26)); // 2. Weihnachtstag
return set;
}
var ftCache = {};
function istFeiertag(d) {
var y = d.getFullYear();
if (!ftCache[y]) ftCache[y] = feiertage(y);
return !!ftCache[y][y + '-' + d.getMonth() + '-' + d.getDate()];
}
function istWerktag(d) {
var wd = d.getDay();
return wd !== 0 && wd !== 6 && !istFeiertag(d);
}
function werktagePlus(start, n) {
var d = new Date(start.getFullYear(), start.getMonth(), start.getDate());
var count = 0;
while (count < n) { d.setDate(d.getDate() + 1); if (istWerktag(d)) count++; }
return d;
}
renderCart();
}
function setupLightbox() {
if (window.__plLightbox) return;
window.__plLightbox = true;
var style = document.createElement('style');
style.textContent =
'.pl-card-img img, .pl-thumb { cursor: zoom-in; }' +
'#pl-lightbox { position: fixed; inset: 0; background: rgba(0,0,0,0.85); display: none; align-items: center; justify-content: center; z-index: 99999; padding: 24px; box-sizing: border-box; cursor: zoom-out; }' +
'#pl-lightbox.open { display: flex; }' +
'#pl-lightbox img { max-width: 95%; max-height: 95%; object-fit: contain; border-radius: 4px; box-shadow: 0 4px 30px rgba(0,0,0,0.5); }' +
'#pl-lightbox-close { position: absolute; top: 16px; right: 24px; color: #fff; font-size: 40px; line-height: 1; font-weight: 300; cursor: pointer; background: none; border: none; }';
document.head.appendChild(style);
var box = document.createElement('div');
box.id = 'pl-lightbox';
box.innerHTML = '\u00d7 ';
document.body.appendChild(box);
var boxImg = box.querySelector('img');
function open(src, alt) { boxImg.src = src; boxImg.alt = alt || ''; box.classList.add('open'); }
function close() { box.classList.remove('open'); boxImg.src = ''; }
var results = document.getElementById('pl-results');
if (results) {
results.addEventListener('click', function(e) {
var img = e.target;
if (img && img.tagName === 'IMG' && img.closest('.pl-card-img, .pl-card-header--thumb')) {
e.preventDefault();
open(img.getAttribute('data-full') || img.getAttribute('src'), img.getAttribute('alt'));
}
});
}
box.addEventListener('click', close);
document.addEventListener('keydown', function(e) { if (e.key === 'Escape') close(); });
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();