(function () { if (window.__ptvRoserBedWidgetInit) return; window.__ptvRoserBedWidgetInit = true; var styleEl = document.createElement('style'); styleEl.textContent = "#ptv-roser-bed-widget{--ptv-g:#1c4220;--ptv-gp:#f0f7f0;--ptv-gb:#c8e6ca;--ptv-tx:#1a1a1a;--ptv-gr:#6b7280;width:100%;max-width:100%;box-sizing:border-box;margin:1rem 0;border:1px solid var(--ptv-gb);border-radius:16px;background:#fafaf8;font-family:inherit;color:var(--ptv-tx);overflow:hidden}\n#ptv-roser-bed-widget *{box-sizing:border-box}\n#ptv-roser-bed-widget .ptv-bw-head{background:var(--ptv-g);color:#fff;padding:.9rem 1.2rem;font-weight:600;font-size:1.02rem;display:flex;align-items:center;justify-content:space-between;gap:.6rem;cursor:pointer;user-select:none}\n#ptv-roser-bed-widget .ptv-bw-chevron{transition:transform .25s ease;font-size:.85rem;flex:none}\n#ptv-roser-bed-widget.ptv-collapsed .ptv-bw-chevron{transform:rotate(-90deg)}\n#ptv-roser-bed-widget .ptv-bw-body{transition:max-height .3s ease,padding .3s ease;max-height:6000px;overflow:hidden;padding:.8rem .7rem 1.3rem}\n#ptv-roser-bed-widget.ptv-collapsed .ptv-bw-body{max-height:0;padding-top:0;padding-bottom:0}\n#ptv-roser-bed-widget .ptv-bw-loading{padding:1.4rem;font-size:.9rem;color:var(--ptv-gr)}\n#ptv-roser-bed-widget .ptv-bw-filters{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:.9rem 1.2rem;margin-bottom:1rem}\n#ptv-roser-bed-widget .ptv-bw-filters .ptv-bw-field{min-width:0}\n@media (max-width:680px){#ptv-roser-bed-widget .ptv-bw-filters{grid-template-columns:1fr}}\n#ptv-roser-bed-widget .ptv-bw-field{margin-bottom:0}\n#ptv-roser-bed-widget .ptv-bw-label{display:block;font-size:.8rem;font-weight:600;color:var(--ptv-g);margin-bottom:.4rem}\n#ptv-roser-bed-widget .ptv-bw-pills{display:flex;flex-wrap:wrap;gap:.4rem}\n#ptv-roser-bed-widget .ptv-bw-pill{border:1px solid var(--ptv-gb);background:#fff;border-radius:999px;padding:.35rem .8rem;font-size:.82rem;cursor:pointer;display:inline-flex;align-items:center;gap:.35rem;color:var(--ptv-tx)}\n#ptv-roser-bed-widget .ptv-bw-pill:hover{border-color:var(--ptv-g)}\n#ptv-roser-bed-widget .ptv-bw-pill.ptv-bw-active{background:var(--ptv-g);border-color:var(--ptv-g);color:#fff}\n#ptv-roser-bed-widget .ptv-bw-swatch{width:12px;height:12px;border-radius:50%;border:1px solid var(--ptv-gb);flex:none}\n#ptv-roser-bed-widget .ptv-bw-match-row{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:.5rem;margin:.2rem 0 .6rem}\n#ptv-roser-bed-widget .ptv-bw-match-count{font-size:.8rem;color:var(--ptv-gr)}\n#ptv-roser-bed-widget .ptv-bw-selected-count{font-size:.8rem;color:var(--ptv-g);font-weight:600}\n#ptv-roser-bed-widget .ptv-bw-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(128px,1fr));gap:.6rem;max-height:620px;overflow-y:auto;padding:.6rem;border:1px solid var(--ptv-gb);border-radius:12px;background:#fff;margin-bottom:1rem}\n#ptv-roser-bed-widget .ptv-bw-card{position:relative;border:1px solid var(--ptv-gb);border-radius:10px;padding:.45rem;cursor:pointer;background:#fff;transition:border-color .12s,background .12s}\n#ptv-roser-bed-widget .ptv-bw-card:hover{border-color:var(--ptv-g)}\n#ptv-roser-bed-widget .ptv-bw-card.ptv-bw-checked{border-color:var(--ptv-g);background:var(--ptv-gp)}\n#ptv-roser-bed-widget .ptv-bw-card-img{width:100%;aspect-ratio:1;object-fit:cover;border-radius:7px;background:#eee;display:block}\n#ptv-roser-bed-widget .ptv-bw-card-img.ptv-bw-noimg{display:flex;align-items:center;justify-content:center;font-size:1.6rem}\n#ptv-roser-bed-widget .ptv-bw-card-navn{font-weight:600;font-size:.76rem;margin-top:.35rem;line-height:1.25}\n#ptv-roser-bed-widget .ptv-bw-card-botanisk{font-style:italic;font-size:.66rem;color:var(--ptv-gr);line-height:1.2}\n#ptv-roser-bed-widget .ptv-bw-card-check{position:absolute;top:.35rem;right:.35rem;width:22px;height:22px;border-radius:50%;background:rgba(255,255,255,.92);border:1.5px solid var(--ptv-gb);display:flex;align-items:center;justify-content:center;font-size:.78rem;font-weight:700;color:var(--ptv-g);box-shadow:0 1px 3px rgba(0,0,0,.2)}\n#ptv-roser-bed-widget .ptv-bw-card.ptv-bw-checked .ptv-bw-card-check{background:var(--ptv-g);border-color:var(--ptv-g);color:#fff}\n#ptv-roser-bed-widget .ptv-bw-grid-empty{padding:1.2rem;text-align:center;color:var(--ptv-gr);font-size:.85rem}\n#ptv-roser-bed-widget .ptv-bw-areal-row{display:flex;flex-wrap:wrap;align-items:flex-end;gap:1.2rem;margin-bottom:.9rem}\n#ptv-roser-bed-widget .ptv-bw-stepper{display:flex;align-items:center;gap:.5rem}\n#ptv-roser-bed-widget .ptv-bw-stepper button{width:34px;height:34px;border-radius:8px;border:1px solid var(--ptv-gb);background:#fff;font-size:1.1rem;cursor:pointer;color:var(--ptv-g)}\n#ptv-roser-bed-widget .ptv-bw-stepper button:hover{background:var(--ptv-gp)}\n#ptv-roser-bed-widget .ptv-bw-stepper input{width:80px;text-align:center;padding:.4rem;border:1px solid var(--ptv-gb);border-radius:8px;font-size:.95rem}\n#ptv-roser-bed-widget .ptv-bw-unit{font-size:.82rem;color:var(--ptv-gr)}\n#ptv-roser-bed-widget .ptv-bw-actions{display:flex;flex-wrap:wrap;gap:.6rem;margin-bottom:1rem}\n#ptv-roser-bed-widget .ptv-bw-btn-secondary{flex:1;min-width:170px;padding:.7rem 1rem;border-radius:10px;border:1.5px solid var(--ptv-g);background:#fff;color:var(--ptv-g);font-weight:600;font-size:.9rem;cursor:pointer}\n#ptv-roser-bed-widget .ptv-bw-btn-secondary:hover{background:var(--ptv-gp)}\n#ptv-roser-bed-widget .ptv-bw-btn-primary{flex:1;min-width:170px;padding:.7rem 1rem;border-radius:10px;border:none;background:var(--ptv-g);color:#fff;font-weight:600;font-size:.9rem;cursor:pointer}\n#ptv-roser-bed-widget .ptv-bw-btn-primary:hover{background:#153318}\n#ptv-roser-bed-widget .ptv-bw-btn-mini{padding:.65rem 1.1rem;border-radius:8px;border:none;background:var(--ptv-g);color:#fff;font-weight:600;font-size:.85rem;cursor:pointer;white-space:nowrap}\n#ptv-roser-bed-widget .ptv-bw-btn-mini:hover{background:#153318}\n#ptv-roser-bed-widget .ptv-bw-hint{font-size:.85rem;color:var(--ptv-gr);background:var(--ptv-gp);border-radius:10px;padding:.9rem 1rem;margin-bottom:1rem;text-align:center;line-height:1.4}\n#ptv-roser-bed-widget .ptv-bw-empty{font-size:.85rem;color:#991b1b;background:#fef2f2;border-radius:10px;padding:.9rem 1rem;margin-bottom:1rem;text-align:center;line-height:1.4}\n#ptv-roser-bed-widget .ptv-bw-tilvalg{margin-bottom:1rem;border:1px solid var(--ptv-gb);border-radius:12px;padding:.8rem 1rem;background:#fff}\n#ptv-roser-bed-widget .ptv-bw-tilvalg-titel{font-size:.8rem;font-weight:600;color:var(--ptv-g);margin-bottom:.6rem}\n#ptv-roser-bed-widget .ptv-bw-tilvalg-item{display:flex;align-items:center;gap:.6rem;padding:.4rem 0;border-bottom:1px solid var(--ptv-gb)}\n#ptv-roser-bed-widget .ptv-bw-tilvalg-item:last-child{border-bottom:none}\n#ptv-roser-bed-widget .ptv-bw-tilvalg-item input[type=checkbox]{width:18px;height:18px;flex:none;accent-color:var(--ptv-g)}\n#ptv-roser-bed-widget .ptv-bw-tilvalg-img{width:40px;height:40px;border-radius:7px;object-fit:cover;flex:none;background:#eee}\n#ptv-roser-bed-widget .ptv-bw-tilvalg-img.ptv-bw-noimg{display:flex;align-items:center;justify-content:center;font-size:1.1rem}\n#ptv-roser-bed-widget .ptv-bw-tilvalg-tekst{min-width:0;flex:1}\n#ptv-roser-bed-widget .ptv-bw-tilvalg-navn{font-weight:600;font-size:.82rem}\n#ptv-roser-bed-widget .ptv-bw-tilvalg-pris{font-size:.75rem;color:var(--ptv-gr)}\n#ptv-roser-bed-widget .ptv-bw-tilvalg-qty{width:56px;text-align:center;padding:.3rem;border:1px solid var(--ptv-gb);border-radius:7px;font-size:.85rem}\n#ptv-roser-bed-widget .ptv-bw-resultat{margin-bottom:1rem}\n#ptv-roser-bed-widget .ptv-bw-resultat-titel{font-size:.85rem;font-weight:600;color:var(--ptv-g);margin-bottom:.6rem}\n#ptv-roser-bed-widget .ptv-bw-plantekort{display:flex;gap:.7rem;align-items:center;padding:.5rem 0;border-bottom:1px solid var(--ptv-gb)}\n#ptv-roser-bed-widget .ptv-bw-plantekort:last-child{border-bottom:none}\n#ptv-roser-bed-widget .ptv-bw-plantekort-img{width:52px;height:52px;border-radius:8px;object-fit:cover;flex:none;background:#eee}\n#ptv-roser-bed-widget .ptv-bw-plantekort-img.ptv-bw-noimg{display:flex;align-items:center;justify-content:center;font-size:1.3rem}\n#ptv-roser-bed-widget .ptv-bw-plantekort-tekst{min-width:0;flex:1}\n#ptv-roser-bed-widget .ptv-bw-plantekort-navn{font-weight:600;font-size:.88rem}\n#ptv-roser-bed-widget .ptv-bw-plantekort-botanisk{font-style:italic;font-size:.75rem;color:var(--ptv-gr)}\n#ptv-roser-bed-widget .ptv-bw-plantekort-detaljer{font-size:.78rem;color:var(--ptv-gr);margin-top:.15rem}\n#ptv-roser-bed-widget .ptv-bw-plantekort-pris{font-size:.85rem;font-weight:600;flex:none;text-align:right}\n#ptv-roser-bed-widget .ptv-bw-pricebar{background:var(--ptv-g);color:#fff;border-radius:10px;padding:.8rem 1rem;margin-bottom:1rem;text-align:center}\n#ptv-roser-bed-widget .ptv-bw-pricebar .ptv-bw-amount{font-size:1.4rem;font-weight:700}\n#ptv-roser-bed-widget .ptv-bw-pricebar small{display:block;opacity:.85;font-size:.72rem;margin-top:2px}\n#ptv-roser-bed-widget .ptv-bw-cta{width:100%;padding:.85rem;border:none;border-radius:10px;background:#2d5a27;color:#fff;font-size:1rem;font-weight:600;cursor:pointer}\n#ptv-roser-bed-widget .ptv-bw-cta:hover{background:#234a1e}\n#ptv-roser-bed-widget .ptv-bw-cta:disabled{opacity:.6;cursor:default}\n#ptv-roser-bed-widget .ptv-bw-status{margin-top:.6rem;font-size:.82rem}\n#ptv-roser-bed-widget .ptv-bw-status.ptv-error{color:#991b1b}\n#ptv-roser-bed-widget .ptv-bw-status.ptv-ok{color:var(--ptv-g)}\n#ptv-roser-bed-widget .ptv-bw-status a{color:var(--ptv-g);font-weight:600}\n#ptv-roser-bed-widget .ptv-bw-disclaimer{font-size:.68rem;color:var(--ptv-gr);margin-top:.7rem;line-height:1.4}\n#ptv-roser-bed-widget .ptv-bw-vaelg-alle{border:1px solid var(--ptv-gb);background:#fff;border-radius:999px;padding:.3rem .8rem;font-size:.78rem;cursor:pointer;color:var(--ptv-g);font-weight:600}\n#ptv-roser-bed-widget .ptv-bw-vaelg-alle:hover{border-color:var(--ptv-g);background:var(--ptv-gp)}\n#ptv-roser-bed-widget .ptv-bw-tv-total{margin-left:auto;font-weight:600;font-size:.85rem;color:var(--ptv-tx);flex:none}\n#ptv-roser-bed-widget .ptv-bw-jordvalg-prompt{font-size:.85rem;background:#eff6ff;border:1px solid #bfdbfe;border-radius:10px;padding:.7rem .9rem;margin-bottom:.5rem}\n#ptv-roser-bed-widget .ptv-bw-jordvalg-tekst{color:#1e40af;margin-bottom:.5rem;line-height:1.4}\n#ptv-roser-bed-widget .ptv-bw-jordvalg-btns{display:flex;flex-wrap:wrap;gap:.5rem}\n#ptv-roser-bed-widget .ptv-bw-tag{font-size:.68rem;background:var(--ptv-gb);color:var(--ptv-g);border-radius:10px;padding:1px 7px;margin-left:.4rem;font-weight:700}\n#ptv-roser-bed-widget .ptv-bw-v-titel{font-size:1.15rem;font-weight:700;color:var(--ptv-g);margin:0 0 .9rem}\n#ptv-roser-bed-widget .ptv-bw-vgrid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1rem;margin-bottom:1rem}\n@media (max-width:900px){#ptv-roser-bed-widget .ptv-bw-vgrid{grid-template-columns:repeat(2,minmax(0,1fr))}}\n@media (max-width:560px){#ptv-roser-bed-widget .ptv-bw-vgrid{grid-template-columns:1fr}}\n#ptv-roser-bed-widget .ptv-bw-vcard{border:1px solid var(--ptv-gb);border-radius:12px;padding:.9rem;background:#fff;display:flex;flex-direction:column;gap:.3rem}\n#ptv-roser-bed-widget .ptv-bw-vcard-img{width:100%;aspect-ratio:1;object-fit:cover;border-radius:9px;background:#eee;display:block}\n#ptv-roser-bed-widget .ptv-bw-vcard-img.ptv-bw-noimg{display:flex;align-items:center;justify-content:center;font-size:2rem}\n#ptv-roser-bed-widget .ptv-bw-vcard-navn{font-weight:700;font-size:1rem;margin-top:.3rem}\n#ptv-roser-bed-widget .ptv-bw-vcard-botanisk{font-style:italic;font-size:.78rem;color:var(--ptv-gr)}\n#ptv-roser-bed-widget .ptv-bw-vcard-pris{font-weight:600;font-size:1rem;color:var(--ptv-tx);margin-top:.1rem}\n#ptv-roser-bed-widget .ptv-bw-vcard-row{display:flex;align-items:center;gap:.6rem;margin-top:.4rem}\n#ptv-roser-bed-widget .ptv-bw-vcard-stepper{display:flex;align-items:center;gap:.35rem;flex:none}\n#ptv-roser-bed-widget .ptv-bw-vcard-stepper button{width:28px;height:28px;border-radius:7px;border:1px solid var(--ptv-gb);background:#fff;font-size:.95rem;cursor:pointer;color:var(--ptv-g)}\n#ptv-roser-bed-widget .ptv-bw-vcard-stepper button:hover{background:var(--ptv-gp)}\n#ptv-roser-bed-widget .ptv-bw-vcard-qty{width:42px;text-align:center;padding:.25rem;border:1px solid var(--ptv-gb);border-radius:7px;font-size:.82rem}\n#ptv-roser-bed-widget .ptv-bw-vcard-buy{flex:1;min-width:0;padding:.55rem .7rem;font-size:.82rem}\n#ptv-roser-bed-widget .ptv-bw-filters-full{margin-bottom:.9rem}\n#ptv-roser-bed-widget .ptv-bw-filters-row2{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:.9rem 1.2rem;margin-bottom:.9rem}\n#ptv-roser-bed-widget .ptv-bw-filters-row3{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:.9rem 1.2rem;margin-bottom:1rem}\n@media (max-width:680px){#ptv-roser-bed-widget .ptv-bw-filters-row2{grid-template-columns:1fr}#ptv-roser-bed-widget .ptv-bw-filters-row3{grid-template-columns:1fr}}\n#ptv-roser-bed-widget .ptv-bw-field-full{grid-column:1/-1}\n#ptv-roser-bed-widget .ptv-bw-subpills{margin-top:.5rem;padding-top:.5rem;border-top:1px dashed var(--ptv-gb)}"; document.head.appendChild(styleEl); var MARKUP_VARIANT_HTML = "
🌹 Vælg dine favoritter – filtrér og læg direkte i kurven.▾
\n
Henter roser…
\n"; var FARVE_PILLS = [ { vaerdi: 41, label: 'Hvid', hex: '#ffffff' }, { vaerdi: 42, label: 'Rosa', hex: '#f472b6' }, { vaerdi: 43, label: 'Rød', hex: '#dc2626' }, { vaerdi: 44, label: 'Gul', hex: '#facc15' }, { vaerdi: 47, label: 'Orange', hex: '#fb923c' }, { vaerdi: 14954, label: 'Abrikos', hex: '#f5a262' }, { vaerdi: 45, label: 'Lilla', hex: '#a855f7' }, { vaerdi: 52, label: 'Fersken', hex: '#ffcba4' }, { vaerdi: 48, label: 'Violet', hex: '#7c3aed' }, { vaerdi: 50, label: 'Creme', hex: '#f5f0dc' } ]; var LYS_PILLS = [ { key: 'fuld_sol', label: 'Fuld sol' }, { key: 'halvskygge', label: 'Halvskygge' }, { key: 'skygge', label: 'Skygge' } ]; var LYS_MATCH = { fuld_sol: [2, 4, 3], halvskygge: [5, 4, 7], skygge: [6, 3, 7] }; var JORD_PILLS = [ { key: 'toer', label: 'Tør' }, { key: 'fugtig', label: 'Fugtig' }, { key: 'almindelig', label: 'Almindelig' } ]; var JORD_BUCKET = { 1: 'almindelig', 2: 'fugtig', 3: 'toer', 4: 'toer', 5: 'toer', 6: 'fugtig', 7: 'almindelig', 8: 'almindelig', 9: 'almindelig', 10: 'almindelig', 11: 'almindelig', 12: 'almindelig', 13: 'fugtig', 14: 'almindelig', 15: 'almindelig', 16: 'fugtig', 17: 'almindelig', 18: 'almindelig', 19: 'toer', 20: 'almindelig' }; var JORD_TIL_TYPE = { toer: 'let_jord', almindelig: 'alm_havemuld', fugtig: 'fed_jord' }; var HOEJDE_PILLS = [ { vaerdi: 52003, label: '25-50 cm' }, { vaerdi: 52004, label: '50-100 cm' }, { vaerdi: 52005, label: '1-2 m' }, { vaerdi: 52006, label: '2-5 m' }, { vaerdi: 52007, label: '5-10 m' } ]; var SAESON_PILLS = [ { key: 'foraar', label: 'Forår' }, { key: 'sommer', label: 'Sommer' }, { key: 'efteraar', label: 'Efterår' }, { key: 'vinter', label: 'Vinter' } ]; var SAESON_MATCH = { foraar: [2, 3, 9], sommer: [3, 4, 5], efteraar: [5, 6, 7], vinter: [7, 8, 9] }; var ANVENDELSE_PILLS = [ { vaerdi: 349, label: 'Krukker' }, { vaerdi: 348, label: 'Hække' }, { vaerdi: 51782, label: 'Rosenbed' }, { vaerdi: 362, label: 'Espalier' }, { vaerdi: 351, label: 'Mure' }, { vaerdi: 51764, label: 'Staudebed' }, { vaerdi: 350, label: 'Pergolaer' }, { vaerdi: 51781, label: 'Gruppeplantning' }, { vaerdi: 335, label: 'Terasse' }, { vaerdi: 51770, label: 'Snitblomst' }, { vaerdi: 361, label: 'Læhegn' }, { vaerdi: 334, label: 'Parker' } ]; var OVRIGE_PILLS = [ { vaerdi: 51989, label: 'Duftende' }, { vaerdi: 51988, label: 'Bivenlig' } ]; var TILVALG_LABELS = { jordforbedring: '🌱', godning: '🌾', felco: '✂️', handske: '🧤' }; function initVariantWidget(ROOT, UNDERKAT_ID, DATA_URL, KURV_URL) { ROOT.innerHTML = MARKUP_VARIANT_HTML; var el = { head: ROOT.querySelector('#ptv-bw-head'), loading: ROOT.querySelector('#ptv-bw-loading'), body: ROOT.querySelector('#ptv-bw-body'), titel: ROOT.querySelector('#ptv-bw-v-titel'), farveField: ROOT.querySelector('#ptv-bw-v-farve-field'), farvePills: ROOT.querySelector('#ptv-bw-v-farve-pills'), hoejdeField: ROOT.querySelector('#ptv-bw-v-hoejde-field'), hoejdePills: ROOT.querySelector('#ptv-bw-v-hoejde-pills'), saesonField: ROOT.querySelector('#ptv-bw-v-saeson-field'), saesonPills: ROOT.querySelector('#ptv-bw-v-saeson-pills'), anvendelseField: ROOT.querySelector('#ptv-bw-v-anvendelse-field'), anvendelsePills: ROOT.querySelector('#ptv-bw-v-anvendelse-pills'), ovrigeField: ROOT.querySelector('#ptv-bw-v-ovrige-field'), ovrigePills: ROOT.querySelector('#ptv-bw-v-ovrige-pills'), opstammetField: ROOT.querySelector('#ptv-bw-v-opstammet-field'), opstammetPills: ROOT.querySelector('#ptv-bw-v-opstammet-pills'), stammehoejdePills: ROOT.querySelector('#ptv-bw-v-stammehoejde-pills'), matchCount: ROOT.querySelector('#ptv-bw-v-match-count'), grid: ROOT.querySelector('#ptv-bw-v-grid'), empty: ROOT.querySelector('#ptv-bw-v-empty'), status: ROOT.querySelector('#ptv-bw-v-status') }; var DATA = null; var valgtFarver = []; var valgtHoejde = []; var valgtSaeson = []; var valgtAnvendelse = []; var valgtOvrige = []; var valgtOpstammet = false; var valgtStammehoejde = []; var qtyState = {}; var FARVE_VIS = [], HOEJDE_VIS = [], SAESON_VIS = [], ANVENDELSE_VIS = [], OVRIGE_VIS = [], OPSTAMMET_VIS = false, STAMMEHOEJDE_VIS = []; function fmtKr(n) { var v = Math.round((n + 1e-9) * 100) / 100; var parts = v.toFixed(2).split('.'); var intPart = parts[0]; var decPart = parts[1]; var out = ''; for (var i = 0; i < intPart.length; i++) { if (i > 0 && (intPart.length - i) % 3 === 0) out += '.'; out += intPart[i]; } return out + ',' + decPart; } function findPris(trin, qty) { if (!trin || trin.length === 0) return null; var vaerdi = trin[0][1]; for (var i = 0; i < trin.length; i++) { if (trin[i][0] <= qty) vaerdi = trin[i][1]; } return vaerdi; } function effectiveVarenrTrin(p) { if (!valgtOpstammet || !p.har_opstammet || !p.opstammet_varianter || !p.opstammet_varianter.length) { return { varenr: p.varenr, trin: p.trin }; } var kandidatVarianter = valgtStammehoejde.length ? p.opstammet_varianter.filter(function (v) { return valgtStammehoejde.indexOf(v.hoejde_cm) !== -1; }) : p.opstammet_varianter; if (!kandidatVarianter.length) kandidatVarianter = p.opstammet_varianter; var bedst = kandidatVarianter[0]; kandidatVarianter.forEach(function (v) { if ((findPris(v.trin, 1) || 0) < (findPris(bedst.trin, 1) || 0)) bedst = v; }); return { varenr: bedst.varenr, trin: bedst.trin }; } function unionMatchSet(map, keys) { var out = []; keys.forEach(function (k) { var set = map[k] || []; set.forEach(function (id) { if (out.indexOf(id) === -1) out.push(id); }); }); return out; } function matchFilter(p) { if (valgtFarver.length) { if (!p.farve_ids.some(function (id) { return valgtFarver.indexOf(id) !== -1; })) return false; } if (valgtHoejde.length) { if (!p.hoejde_ids.some(function (id) { return valgtHoejde.indexOf(id) !== -1; })) return false; } if (valgtSaeson.length) { var saesonSet = unionMatchSet(SAESON_MATCH, valgtSaeson); if (saesonSet.indexOf(p.blomstring_id) === -1) return false; } if (valgtAnvendelse.length) { if (!p.anvendelse_ids.some(function (id) { return valgtAnvendelse.indexOf(id) !== -1; })) return false; } if (valgtOvrige.length) { if (!p.ovrige_ids.some(function (id) { return valgtOvrige.indexOf(id) !== -1; })) return false; } if (valgtOpstammet) { if (!p.har_opstammet) return false; if (valgtStammehoejde.length) { if (!p.opstammet_varianter.some(function (v) { return valgtStammehoejde.indexOf(v.hoejde_cm) !== -1; })) return false; } } return true; } function computeUsedFilterSets(kandidater) { var farve = [], hoejde = [], saeson = [], anvendelse = [], ovrige = [], opstammet = false, stammehoejde = []; kandidater.forEach(function (p) { p.farve_ids.forEach(function (id) { if (farve.indexOf(id) === -1) farve.push(id); }); p.hoejde_ids.forEach(function (id) { if (hoejde.indexOf(id) === -1) hoejde.push(id); }); p.anvendelse_ids.forEach(function (id) { if (anvendelse.indexOf(id) === -1) anvendelse.push(id); }); p.ovrige_ids.forEach(function (id) { if (ovrige.indexOf(id) === -1) ovrige.push(id); }); if (p.har_opstammet) { opstammet = true; (p.opstammet_varianter || []).forEach(function (v) { if (stammehoejde.indexOf(v.hoejde_cm) === -1) stammehoejde.push(v.hoejde_cm); }); } SAESON_PILLS.forEach(function (pill) { if (saeson.indexOf(pill.key) !== -1) return; var set = SAESON_MATCH[pill.key] || []; if (set.indexOf(p.blomstring_id) !== -1) saeson.push(pill.key); }); }); stammehoejde.sort(function (a, b) { return a - b; }); return { farve: FARVE_PILLS.filter(function (p) { return farve.indexOf(p.vaerdi) !== -1; }), hoejde: HOEJDE_PILLS.filter(function (p) { return hoejde.indexOf(p.vaerdi) !== -1; }), saeson: SAESON_PILLS.filter(function (p) { return saeson.indexOf(p.key) !== -1; }), anvendelse: ANVENDELSE_PILLS.filter(function (p) { return anvendelse.indexOf(p.vaerdi) !== -1; }), ovrige: OVRIGE_PILLS.filter(function (p) { return ovrige.indexOf(p.vaerdi) !== -1; }), opstammet: opstammet, stammehoejde: stammehoejde }; } function renderFlervalgPills(container, pills, valgteListe, getKey, onToggle) { container.innerHTML = pills.map(function (p) { var vaerdi = getKey(p); var aktiv = valgteListe.indexOf(vaerdi) !== -1; var swatch = p.hex ? '' : ''; return ''; }).join(''); Array.prototype.forEach.call(container.querySelectorAll('.ptv-bw-pill'), function (btn) { btn.addEventListener('click', function () { var raw = btn.getAttribute('data-v'); var v = isNaN(Number(raw)) ? raw : Number(raw); onToggle(v); }); }); } function toggleFarve(v) { var idx = valgtFarver.indexOf(v); if (idx === -1) valgtFarver.push(v); else valgtFarver.splice(idx, 1); renderFarvePills(); render(); } function renderFarvePills() { renderFlervalgPills(el.farvePills, FARVE_VIS, valgtFarver, function (p) { return p.vaerdi; }, toggleFarve); } function toggleHoejde(v) { var idx = valgtHoejde.indexOf(v); if (idx === -1) valgtHoejde.push(v); else valgtHoejde.splice(idx, 1); renderHoejdePills(); render(); } function renderHoejdePills() { renderFlervalgPills(el.hoejdePills, HOEJDE_VIS, valgtHoejde, function (p) { return p.vaerdi; }, toggleHoejde); } function toggleAnvendelse(v) { var idx = valgtAnvendelse.indexOf(v); if (idx === -1) valgtAnvendelse.push(v); else valgtAnvendelse.splice(idx, 1); renderAnvendelsePills(); render(); } function renderAnvendelsePills() { renderFlervalgPills(el.anvendelsePills, ANVENDELSE_VIS, valgtAnvendelse, function (p) { return p.vaerdi; }, toggleAnvendelse); } function toggleOvrige(v) { var idx = valgtOvrige.indexOf(v); if (idx === -1) valgtOvrige.push(v); else valgtOvrige.splice(idx, 1); renderOvrigePills(); render(); } function renderOvrigePills() { renderFlervalgPills(el.ovrigePills, OVRIGE_VIS, valgtOvrige, function (p) { return p.vaerdi; }, toggleOvrige); } function toggleOpstammet() { valgtOpstammet = !valgtOpstammet; if (!valgtOpstammet) valgtStammehoejde = []; renderOpstammetPills(); renderStammehoejdePills(); render(); } function renderOpstammetPills() { el.opstammetPills.innerHTML = ''; var btn = el.opstammetPills.querySelector('.ptv-bw-pill'); if (btn) btn.addEventListener('click', toggleOpstammet); } function toggleStammehoejde(v) { var idx = valgtStammehoejde.indexOf(v); if (idx === -1) valgtStammehoejde.push(v); else valgtStammehoejde.splice(idx, 1); renderStammehoejdePills(); render(); } function renderStammehoejdePills() { if (!valgtOpstammet || STAMMEHOEJDE_VIS.length === 0) { el.stammehoejdePills.hidden = true; el.stammehoejdePills.innerHTML = ''; return; } el.stammehoejdePills.hidden = false; el.stammehoejdePills.innerHTML = STAMMEHOEJDE_VIS.map(function (cm) { var aktiv = valgtStammehoejde.indexOf(cm) !== -1; return ''; }).join(''); Array.prototype.forEach.call(el.stammehoejdePills.querySelectorAll('.ptv-bw-pill'), function (btn) { btn.addEventListener('click', function () { toggleStammehoejde(Number(btn.getAttribute('data-v'))); }); }); } function toggleSaeson(v) { var idx = valgtSaeson.indexOf(v); if (idx === -1) valgtSaeson.push(v); else valgtSaeson.splice(idx, 1); renderSaesonPills(); render(); } function renderSaesonPills() { renderFlervalgPills(el.saesonPills, SAESON_VIS, valgtSaeson, function (p) { return p.key; }, toggleSaeson); } function renderFilterFields() { el.farveField.hidden = FARVE_VIS.length === 0; el.hoejdeField.hidden = HOEJDE_VIS.length === 0; el.saesonField.hidden = SAESON_VIS.length === 0; el.anvendelseField.hidden = ANVENDELSE_VIS.length === 0; el.ovrigeField.hidden = OVRIGE_VIS.length === 0; el.opstammetField.hidden = !OPSTAMMET_VIS; renderFarvePills(); renderHoejdePills(); renderSaesonPills(); renderAnvendelsePills(); renderOvrigePills(); renderOpstammetPills(); renderStammehoejdePills(); } function getQty(id) { return qtyState[id] || 1; } function cardPrisHtml(p) { var qty = getQty(p.plante_id); var eff = effectiveVarenrTrin(p); var enhedsPris = findPris(eff.trin, qty) || 0; return fmtKr(enhedsPris * DATA.moms_faktor) + ' kr/stk'; } function laegIKurv(btn, p) { var qty = getQty(p.plante_id); var eff = effectiveVarenrTrin(p); btn.disabled = true; el.status.className = 'ptv-bw-status'; el.status.textContent = 'Opretter kurv…'; fetch(KURV_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ items: [{ vareNr: eff.varenr, quantity: qty }] }) }) .then(function (r) { return r.json(); }) .then(function (res) { btn.disabled = false; if (res && res.success && res.url) { el.status.className = 'ptv-bw-status ptv-ok'; el.status.innerHTML = 'Kurv oprettet — sender dig til kurven…'; try { var topWin = window.top || window.parent || window; topWin.location.href = res.url; } catch (e) { el.status.innerHTML = 'Kurv oprettet — gå til kurv →'; } } else { el.status.className = 'ptv-bw-status ptv-error'; el.status.textContent = 'Kunne ikke oprette kurven automatisk. Prøv igen om lidt.'; } }) .catch(function () { btn.disabled = false; el.status.className = 'ptv-bw-status ptv-error'; el.status.textContent = 'Kunne ikke oprette kurven automatisk. Prøv igen om lidt.'; }); } function opdaterKortPris(id) { var kort = el.grid.querySelector('[data-id="' + id + '"]'); if (!kort) return; var prisEl = kort.querySelector('.ptv-bw-vcard-pris'); var qtyInput = kort.querySelector('.ptv-bw-vcard-qty'); var p = DATA.kandidater.filter(function (x) { return x.plante_id === id; })[0]; if (!p) return; if (prisEl) prisEl.textContent = cardPrisHtml(p); if (qtyInput) qtyInput.value = getQty(id); } function renderGrid(pool) { if (pool.length === 0) { el.grid.innerHTML = ''; el.empty.hidden = false; return; } el.empty.hidden = true; el.grid.innerHTML = pool.map(function (p) { var imgHtml = p.billede ? '' : '
🌱
'; return '
' + imgHtml + '
' + p.navn + '
' + '
' + p.navn_botanisk + '
' + '
' + cardPrisHtml(p) + '
' + '
' + '
' + '' + '' + '' + '
' + '' + '
' + '
'; }).join(''); Array.prototype.forEach.call(el.grid.querySelectorAll('.ptv-bw-vcard'), function (kort) { var id = parseInt(kort.getAttribute('data-id'), 10); var p = pool.filter(function (x) { return x.plante_id === id; })[0]; var qtyInput = kort.querySelector('.ptv-bw-vcard-qty'); kort.querySelector('.ptv-bw-vcard-minus').addEventListener('click', function () { qtyState[id] = Math.max(1, getQty(id) - 1); opdaterKortPris(id); }); kort.querySelector('.ptv-bw-vcard-plus').addEventListener('click', function () { qtyState[id] = getQty(id) + 1; opdaterKortPris(id); }); qtyInput.addEventListener('input', function () { qtyState[id] = Math.max(1, parseInt(qtyInput.value, 10) || 1); opdaterKortPris(id); }); kort.querySelector('.ptv-bw-vcard-buy').addEventListener('click', function (ev) { laegIKurv(ev.currentTarget, p); }); }); } function render() { if (!DATA) return; var pool = DATA.kandidater.filter(matchFilter); el.matchCount.textContent = pool.length + ' roser matcher dine filtre'; renderGrid(pool); } function fetchData() { fetch(DATA_URL).then(function (r) { return r.json(); }).then(function (json) { if (!json || !json.ok) { el.loading.textContent = 'Kunne ikke hente roser lige nu. Prøv at genindlÌse siden.'; return; } DATA = json; el.loading.hidden = true; el.body.hidden = false; el.titel.textContent = 'VÌlg dine favorit ' + (DATA.underkategori_navn || 'roser'); var vis = computeUsedFilterSets(DATA.kandidater); FARVE_VIS = vis.farve; HOEJDE_VIS = vis.hoejde; SAESON_VIS = vis.saeson; ANVENDELSE_VIS = vis.anvendelse; OVRIGE_VIS = vis.ovrige; OPSTAMMET_VIS = vis.opstammet; STAMMEHOEJDE_VIS = vis.stammehoejde; renderFilterFields(); render(); }).catch(function () { el.loading.textContent = 'Kunne ikke hente roser lige nu. Prøv at genindlÌse siden.'; }); } el.head.addEventListener('click', function () { ROOT.classList.toggle('ptv-collapsed'); }); fetchData(); } var ROOTS = document.querySelectorAll('#ptv-roser-bed-widget'); Array.prototype.forEach.call(ROOTS, function (ROOT) { if (ROOT.__ptvInit) return; ROOT.__ptvInit = true; var UNDERKAT_ID = ROOT.getAttribute('data-underkategori-id') || ''; var DATA_URL = 'https://n8n.plantetorvet.dk/webhook/roser-bed-widget-data' + (UNDERKAT_ID ? '?underkategori_id=' + encodeURIComponent(UNDERKAT_ID) : ''); var KURV_URL = 'https://n8n.plantetorvet.dk/webhook/roser-bed-widget-kurv'; if (UNDERKAT_ID) { initVariantWidget(ROOT, UNDERKAT_ID, DATA_URL, KURV_URL); return; } ROOT.innerHTML = "
🌹 Byg dit bed – filtrér, marker de roser du vil have, og beregn mængde og pris.▾
\n
Henter roser…
\n"; var el = { head: ROOT.querySelector('#ptv-bw-head'), loading: ROOT.querySelector('#ptv-bw-loading'), body: ROOT.querySelector('#ptv-bw-body'), farveField: ROOT.querySelector('#ptv-bw-farve-field'), farvePills: ROOT.querySelector('#ptv-bw-farve-pills'), lysField: ROOT.querySelector('#ptv-bw-lys-field'), lysPills: ROOT.querySelector('#ptv-bw-lys-pills'), jordField: ROOT.querySelector('#ptv-bw-jord-field'), jordPills: ROOT.querySelector('#ptv-bw-jord-pills'), hoejdeField: ROOT.querySelector('#ptv-bw-hoejde-field'), hoejdePills: ROOT.querySelector('#ptv-bw-hoejde-pills'), saesonField: ROOT.querySelector('#ptv-bw-saeson-field'), saesonPills: ROOT.querySelector('#ptv-bw-saeson-pills'), anvendelseField: ROOT.querySelector('#ptv-bw-anvendelse-field'), anvendelsePills: ROOT.querySelector('#ptv-bw-anvendelse-pills'), ovrigeField: ROOT.querySelector('#ptv-bw-ovrige-field'), ovrigePills: ROOT.querySelector('#ptv-bw-ovrige-pills'), opstammetField: ROOT.querySelector('#ptv-bw-opstammet-field'), opstammetPills: ROOT.querySelector('#ptv-bw-opstammet-pills'), stammehoejdePills: ROOT.querySelector('#ptv-bw-stammehoejde-pills'), matchCount: ROOT.querySelector('#ptv-bw-match-count'), vaelgAlleBtn: ROOT.querySelector('#ptv-bw-vaelg-alle'), selectedCount: ROOT.querySelector('#ptv-bw-selected-count'), grid: ROOT.querySelector('#ptv-bw-grid'), areal: ROOT.querySelector('#ptv-bw-areal'), arealMinus: ROOT.querySelector('#ptv-bw-areal-minus'), arealPlus: ROOT.querySelector('#ptv-bw-areal-plus'), beregnBtn: ROOT.querySelector('#ptv-bw-beregn'), beregnBtnTop: ROOT.querySelector('#ptv-bw-beregn-top'), hint: ROOT.querySelector('#ptv-bw-hint'), empty: ROOT.querySelector('#ptv-bw-empty'), tilvalgSection: ROOT.querySelector('#ptv-bw-tilvalg-section'), tilvalgListe: ROOT.querySelector('#ptv-bw-tilvalg-liste'), resultat: ROOT.querySelector('#ptv-bw-resultat'), resultatTitel: ROOT.querySelector('#ptv-bw-resultat-titel'), resultatListe: ROOT.querySelector('#ptv-bw-resultat-liste'), pricebar: ROOT.querySelector('#ptv-bw-pricebar'), cta: ROOT.querySelector('#ptv-bw-cta'), status: ROOT.querySelector('#ptv-bw-status'), disclaimer: ROOT.querySelector('#ptv-bw-disclaimer') }; var DATA = null; var valgtFarver = []; var valgtLys = []; var valgtJord = null; var jordvalgFed = null; var valgtHoejde = []; var valgtSaeson = []; var valgtAnvendelse = []; var valgtOvrige = []; var valgtOpstammet = false; var valgtStammehoejde = []; var valgteProdukter = {}; var valgteTilvalg = {}; var sidsteValgt = []; var FARVE_VIS = [], LYS_VIS = [], JORD_VIS = [], HOEJDE_VIS = [], SAESON_VIS = [], ANVENDELSE_VIS = [], OVRIGE_VIS = [], OPSTAMMET_VIS = false, STAMMEHOEJDE_VIS = []; function fmtKr(n) { var v = Math.round((n + 1e-9) * 100) / 100; var parts = v.toFixed(2).split('.'); var intPart = parts[0]; var decPart = parts[1]; var out = ''; for (var i = 0; i < intPart.length; i++) { if (i > 0 && (intPart.length - i) % 3 === 0) out += '.'; out += intPart[i]; } return out + ',' + decPart; } function findPris(trin, qty) { if (!trin || trin.length === 0) return null; var vaerdi = trin[0][1]; for (var i = 0; i < trin.length; i++) { if (trin[i][0] <= qty) vaerdi = trin[i][1]; } return vaerdi; } function getAreal() { return Math.max(0, parseFloat(el.areal.value) || 0); } function renderFlervalgPills(container, pills, valgteListe, getKey, onToggle) { container.innerHTML = pills.map(function (p) { var vaerdi = getKey(p); var aktiv = valgteListe.indexOf(vaerdi) !== -1; var swatch = p.hex ? '' : ''; return ''; }).join(''); Array.prototype.forEach.call(container.querySelectorAll('.ptv-bw-pill'), function (btn) { btn.addEventListener('click', function () { var raw = btn.getAttribute('data-v'); var v = isNaN(Number(raw)) ? raw : Number(raw); onToggle(v); }); }); } function toggleFarve(v) { var idx = valgtFarver.indexOf(v); if (idx === -1) valgtFarver.push(v); else valgtFarver.splice(idx, 1); renderFarvePills(); render(); } function renderFarvePills() { renderFlervalgPills(el.farvePills, FARVE_VIS, valgtFarver, function (p) { return p.vaerdi; }, toggleFarve); } function toggleHoejde(v) { var idx = valgtHoejde.indexOf(v); if (idx === -1) valgtHoejde.push(v); else valgtHoejde.splice(idx, 1); renderHoejdePills(); render(); } function renderHoejdePills() { renderFlervalgPills(el.hoejdePills, HOEJDE_VIS, valgtHoejde, function (p) { return p.vaerdi; }, toggleHoejde); } function toggleAnvendelse(v) { var idx = valgtAnvendelse.indexOf(v); if (idx === -1) valgtAnvendelse.push(v); else valgtAnvendelse.splice(idx, 1); renderAnvendelsePills(); render(); } function renderAnvendelsePills() { renderFlervalgPills(el.anvendelsePills, ANVENDELSE_VIS, valgtAnvendelse, function (p) { return p.vaerdi; }, toggleAnvendelse); } function toggleOvrige(v) { var idx = valgtOvrige.indexOf(v); if (idx === -1) valgtOvrige.push(v); else valgtOvrige.splice(idx, 1); renderOvrigePills(); render(); } function renderOvrigePills() { renderFlervalgPills(el.ovrigePills, OVRIGE_VIS, valgtOvrige, function (p) { return p.vaerdi; }, toggleOvrige); } function toggleOpstammet() { valgtOpstammet = !valgtOpstammet; if (!valgtOpstammet) valgtStammehoejde = []; renderOpstammetPills(); renderStammehoejdePills(); render(); } function renderOpstammetPills() { el.opstammetPills.innerHTML = ''; var btn = el.opstammetPills.querySelector('.ptv-bw-pill'); if (btn) btn.addEventListener('click', toggleOpstammet); } function toggleStammehoejde(v) { var idx = valgtStammehoejde.indexOf(v); if (idx === -1) valgtStammehoejde.push(v); else valgtStammehoejde.splice(idx, 1); renderStammehoejdePills(); render(); } function renderStammehoejdePills() { if (!valgtOpstammet || STAMMEHOEJDE_VIS.length === 0) { el.stammehoejdePills.hidden = true; el.stammehoejdePills.innerHTML = ''; return; } el.stammehoejdePills.hidden = false; el.stammehoejdePills.innerHTML = STAMMEHOEJDE_VIS.map(function (cm) { var aktiv = valgtStammehoejde.indexOf(cm) !== -1; return ''; }).join(''); Array.prototype.forEach.call(el.stammehoejdePills.querySelectorAll('.ptv-bw-pill'), function (btn) { btn.addEventListener('click', function () { toggleStammehoejde(Number(btn.getAttribute('data-v'))); }); }); } function toggleLys(v) { var idx = valgtLys.indexOf(v); if (idx === -1) valgtLys.push(v); else valgtLys.splice(idx, 1); renderLysPills(); render(); } function renderLysPills() { renderFlervalgPills(el.lysPills, LYS_VIS, valgtLys, function (p) { return p.key; }, toggleLys); } function toggleJord(v) { valgtJord = (valgtJord === v) ? null : v; jordvalgFed = null; renderJordPills(); render(); if (sidsteValgt.length) beregn(); } function renderJordPills() { el.jordPills.innerHTML = JORD_VIS.map(function (p) { var aktiv = valgtJord === p.key; return ''; }).join(''); Array.prototype.forEach.call(el.jordPills.querySelectorAll('.ptv-bw-pill'), function (btn) { btn.addEventListener('click', function () { toggleJord(btn.getAttribute('data-v')); }); }); } function toggleSaeson(v) { var idx = valgtSaeson.indexOf(v); if (idx === -1) valgtSaeson.push(v); else valgtSaeson.splice(idx, 1); renderSaesonPills(); render(); } function renderSaesonPills() { renderFlervalgPills(el.saesonPills, SAESON_VIS, valgtSaeson, function (p) { return p.key; }, toggleSaeson); } function applyFieldWidth(fieldEl, vis) { if (!fieldEl) return; fieldEl.classList.toggle('ptv-bw-field-full', vis.length > 6); } function renderFilterFields() { el.farveField.hidden = FARVE_VIS.length === 0; el.lysField.hidden = LYS_VIS.length === 0; el.jordField.hidden = JORD_VIS.length === 0; el.hoejdeField.hidden = HOEJDE_VIS.length === 0; el.saesonField.hidden = SAESON_VIS.length === 0; el.anvendelseField.hidden = ANVENDELSE_VIS.length === 0; el.ovrigeField.hidden = OVRIGE_VIS.length === 0; el.opstammetField.hidden = !OPSTAMMET_VIS; applyFieldWidth(el.lysField, LYS_VIS); applyFieldWidth(el.jordField, JORD_VIS); applyFieldWidth(el.hoejdeField, HOEJDE_VIS); applyFieldWidth(el.saesonField, SAESON_VIS); applyFieldWidth(el.anvendelseField, ANVENDELSE_VIS); applyFieldWidth(el.ovrigeField, OVRIGE_VIS); renderFarvePills(); renderLysPills(); renderJordPills(); renderHoejdePills(); renderSaesonPills(); renderAnvendelsePills(); renderOvrigePills(); renderOpstammetPills(); renderStammehoejdePills(); } function computeUsedFilterSets(kandidater) { var farve = [], hoejde = [], saeson = [], anvendelse = [], ovrige = [], lys = [], jord = [], opstammet = false, stammehoejde = []; kandidater.forEach(function (p) { p.farve_ids.forEach(function (id) { if (farve.indexOf(id) === -1) farve.push(id); }); p.hoejde_ids.forEach(function (id) { if (hoejde.indexOf(id) === -1) hoejde.push(id); }); p.anvendelse_ids.forEach(function (id) { if (anvendelse.indexOf(id) === -1) anvendelse.push(id); }); p.ovrige_ids.forEach(function (id) { if (ovrige.indexOf(id) === -1) ovrige.push(id); }); if (p.har_opstammet) { opstammet = true; (p.opstammet_varianter || []).forEach(function (v) { if (stammehoejde.indexOf(v.hoejde_cm) === -1) stammehoejde.push(v.hoejde_cm); }); } var jordBucket = JORD_BUCKET[p.jord_id]; if (jordBucket && jord.indexOf(jordBucket) === -1) jord.push(jordBucket); SAESON_PILLS.forEach(function (pill) { if (saeson.indexOf(pill.key) !== -1) return; var set = SAESON_MATCH[pill.key] || []; if (set.indexOf(p.blomstring_id) !== -1) saeson.push(pill.key); }); LYS_PILLS.forEach(function (pill) { if (lys.indexOf(pill.key) !== -1) return; var set = LYS_MATCH[pill.key] || []; if (set.indexOf(p.lys_id) !== -1) lys.push(pill.key); }); }); stammehoejde.sort(function (a, b) { return a - b; }); return { farve: FARVE_PILLS.filter(function (p) { return farve.indexOf(p.vaerdi) !== -1; }), hoejde: HOEJDE_PILLS.filter(function (p) { return hoejde.indexOf(p.vaerdi) !== -1; }), saeson: SAESON_PILLS.filter(function (p) { return saeson.indexOf(p.key) !== -1; }), anvendelse: ANVENDELSE_PILLS.filter(function (p) { return anvendelse.indexOf(p.vaerdi) !== -1; }), ovrige: OVRIGE_PILLS.filter(function (p) { return ovrige.indexOf(p.vaerdi) !== -1; }), lys: LYS_PILLS.filter(function (p) { return lys.indexOf(p.key) !== -1; }), jord: JORD_PILLS.filter(function (p) { return jord.indexOf(p.key) !== -1; }), opstammet: opstammet, stammehoejde: stammehoejde }; } function unionMatchSet(map, keys) { var out = []; keys.forEach(function (k) { var set = map[k] || []; set.forEach(function (id) { if (out.indexOf(id) === -1) out.push(id); }); }); return out; } function matchFilter(p) { if (valgtLys.length) { var lysSet = unionMatchSet(LYS_MATCH, valgtLys); if (lysSet.indexOf(p.lys_id) === -1) return false; } if (valgtJord) { var bucket = JORD_BUCKET[p.jord_id]; if (bucket !== valgtJord) return false; } if (valgtFarver.length) { if (!p.farve_ids.some(function (id) { return valgtFarver.indexOf(id) !== -1; })) return false; } if (valgtHoejde.length) { if (!p.hoejde_ids.some(function (id) { return valgtHoejde.indexOf(id) !== -1; })) return false; } if (valgtSaeson.length) { var saesonSet = unionMatchSet(SAESON_MATCH, valgtSaeson); if (saesonSet.indexOf(p.blomstring_id) === -1) return false; } if (valgtAnvendelse.length) { if (!p.anvendelse_ids.some(function (id) { return valgtAnvendelse.indexOf(id) !== -1; })) return false; } if (valgtOvrige.length) { if (!p.ovrige_ids.some(function (id) { return valgtOvrige.indexOf(id) !== -1; })) return false; } if (valgtOpstammet) { if (!p.har_opstammet) return false; if (valgtStammehoejde.length) { if (!p.opstammet_varianter.some(function (v) { return valgtStammehoejde.indexOf(v.hoejde_cm) !== -1; })) return false; } } return true; } function effectiveVarenrTrin(p) { if (!valgtOpstammet || !p.har_opstammet || !p.opstammet_varianter || !p.opstammet_varianter.length) { return { varenr: p.varenr, trin: p.trin }; } var kandidatVarianter = valgtStammehoejde.length ? p.opstammet_varianter.filter(function (v) { return valgtStammehoejde.indexOf(v.hoejde_cm) !== -1; }) : p.opstammet_varianter; if (!kandidatVarianter.length) kandidatVarianter = p.opstammet_varianter; var bedst = kandidatVarianter[0]; kandidatVarianter.forEach(function (v) { if ((findPris(v.trin, 1) || 0) < (findPris(bedst.trin, 1) || 0)) bedst = v; }); return { varenr: bedst.varenr, trin: bedst.trin }; } function beregnMaengder(valgt, arealTotal) { var antalArter = valgt.length; var arealPrArt = antalArter > 0 ? arealTotal / antalArter : 0; return valgt.map(function (p) { var antalPlanter = Math.max(1, Math.round(arealPrArt * p.taethed_pr_m2)); var eff = effectiveVarenrTrin(p); var enhedsPris = findPris(eff.trin, antalPlanter) || 0; return { plante: p, varenr: eff.varenr, antalPlanter: antalPlanter, enhedsPris: enhedsPris, prisTotal: antalPlanter * enhedsPris }; }); } function renderResultat(sammensaetning) { el.resultatTitel.textContent = sammensaetning.length + ' roser i dit bed:'; el.resultatListe.innerHTML = sammensaetning.map(function (item) { var p = item.plante; var imgHtml = p.billede ? '' : '
🌱
'; var pris = fmtKr(item.prisTotal * DATA.moms_faktor) + ' kr'; return '
' + imgHtml + '
' + '
' + p.navn + '
' + '
' + p.navn_botanisk + '
' + '
' + item.antalPlanter + ' stk' + (p.taethed_estimeret ? ' · estimeret tĂŚthed' : '') + '
' + '
' + '
' + pris + '
' + '
'; }).join(''); } function findTilvalgByKey(key) { var liste = (DATA.tilvalg || []).filter(function (t) { return t.key === key; }); return liste.length ? liste[0] : null; } function beregnFedJordPoser(areal, plantejordData) { var bagLiter = plantejordData.bagLiter; var poserHele = Math.ceil((areal * 0.15 * 1000) / bagLiter); var antalHullerEstimat = Math.ceil(areal * plantejordData.hulleDensitet); var poserHuller = Math.ceil((antalHullerEstimat * 0.15 * 0.15 * 0.15 * 1000) / bagLiter); return { poserHele: poserHele, poserHuller: poserHuller }; } function jordforbedringLinje() { var areal = getAreal(); if (areal <= 0 || !sidsteValgt.length) return null; var type = valgtJord ? JORD_TIL_TYPE[valgtJord] : 'alm_havemuld'; if (type === 'let_jord' || type === 'alm_havemuld') { var rosenjord = findTilvalgByKey('jordforbedring'); if (!rosenjord) return null; var literPrRose = type === 'let_jord' ? 40 : 25; var totalRoser = sidsteValgt.reduce(function (sum, item) { return sum + item.antalPlanter; }, 0); var literBehov = totalRoser * literPrRose; var poser = Math.max(1, Math.ceil(literBehov / 50)); var tekst = type === 'let_jord' ? 'Tør jord: vi anbefaler 40 liter Rosenjord fra Champost pr. rose (50-liters sÌkke).' : 'Almindelig jord: vi anbefaler 25 liter Rosenjord fra Champost pr. rose (50-liters sÌkke).'; return { navn: rosenjord.navn, billede: rosenjord.billede, varenr: rosenjord.varenr, trin: rosenjord.trin, antal: poser, tekst: tekst }; } if (type === 'fed_jord') { if (!jordvalgFed) return null; var plantejord = findTilvalgByKey('plantejord'); if (!plantejord) return null; var poserFed = beregnFedJordPoser(areal, plantejord); if (jordvalgFed === 'huller') { return { navn: plantejord.navn + ' (kun plantehuller)', billede: plantejord.billede, varenr: plantejord.varenr, trin: plantejord.trin, antal: poserFed.poserHuller, tekst: 'Fugtig jord: vi anbefaler at forbedre kun plantehullerne (billigst) med Plantetorvets Plantejord.' }; } return { navn: plantejord.navn + ' (hele arealet)', billede: plantejord.billede, varenr: plantejord.varenr, trin: plantejord.trin, antal: poserFed.poserHele, tekst: 'Fugtig jord: vi anbefaler at forbedre hele arealet (sikrest) med Plantetorvets Plantejord.' }; } return null; } function godningLinje() { var areal = getAreal(); if (areal <= 0 || !sidsteValgt.length) return null; var storBag = areal > 15; var godning = findTilvalgByKey(storBag ? 'godning10' : 'godning2'); if (!godning) return null; var bagKg = storBag ? 10 : 2; var kgBehov = areal * 0.3; var antal = Math.max(1, Math.ceil(kgBehov / bagKg)); var tekst = 'Vi anbefaler Bio Rosengødning NPK 6-2-8 (+2): ca. 0,3 kg pr. m² ürligt (10 kg pr. 100 m², fordelt pü 2-3 gødninger).'; return { navn: godning.navn, billede: godning.billede, varenr: godning.varenr, trin: godning.trin, antal: antal, tekst: tekst }; } function tilvalgTotal() { var sum = 0; var jl = jordforbedringLinje(); if (jl && valgteTilvalg.jordforbedring && valgteTilvalg.jordforbedring.checked) { sum += jl.antal * (findPris(jl.trin, jl.antal) || 0); } var gl = godningLinje(); if (gl && valgteTilvalg.godning && valgteTilvalg.godning.checked) { sum += gl.antal * (findPris(gl.trin, gl.antal) || 0); } ['felco', 'handske'].forEach(function (key) { var produkt = findTilvalgByKey(key); var state = valgteTilvalg[key]; if (produkt && state && state.checked) { var qty = Math.max(1, state.qty || 1); sum += qty * (findPris(produkt.trin, qty) || 0); } }); return sum; } function updatePricebar() { var bedTotal = sidsteValgt.reduce(function (sum, item) { return sum + item.prisTotal; }, 0); var tvTotal = tilvalgTotal(); var total = (bedTotal + tvTotal) * DATA.moms_faktor; el.pricebar.innerHTML = '
' + fmtKr(total) + ' kr
' + 'i alt inkl. moms' + (tvTotal > 0 ? ' (inkl. tilvalg)' : '') + ''; } function simpleTilvalgRowHtml(key, emoji) { var produkt = findTilvalgByKey(key); if (!produkt) return ''; var state = valgteTilvalg[key] || { checked: false, qty: 1 }; var qty = Math.max(1, state.qty || 1); var enhedsPris = findPris(produkt.trin, qty) || 0; var imgHtml = produkt.billede ? '' : '
' + emoji + '
'; return ''; } function renderTilvalg() { if (!DATA || !DATA.tilvalg || DATA.tilvalg.length === 0) { el.tilvalgSection.hidden = true; return; } el.tilvalgSection.hidden = false; var rows = ''; { var type = valgtJord ? JORD_TIL_TYPE[valgtJord] : 'alm_havemuld'; if (type === 'fed_jord') { rows += '
' + '
Fugtig jord: vĂŚlg hvordan Jordforbedring skal beregnes.
' + '
' + '' + '' + '
'; } var jl = jordforbedringLinje(); if (jl) { var jChecked = valgteTilvalg.jordforbedring === undefined ? true : !!valgteTilvalg.jordforbedring.checked; valgteTilvalg.jordforbedring = { checked: jChecked }; var jTotal = jl.antal * (findPris(jl.trin, jl.antal) || 0) * DATA.moms_faktor; var jImgHtml = jl.billede ? '' : '
' + TILVALG_LABELS.jordforbedring + '
'; rows += ''; } } var gl = godningLinje(); if (gl) { var gChecked = valgteTilvalg.godning === undefined ? true : !!valgteTilvalg.godning.checked; valgteTilvalg.godning = { checked: gChecked }; var gTotal = gl.antal * (findPris(gl.trin, gl.antal) || 0) * DATA.moms_faktor; var gImgHtml = gl.billede ? '' : '
' + TILVALG_LABELS.godning + '
'; rows += ''; } rows += simpleTilvalgRowHtml('felco', TILVALG_LABELS.felco); rows += simpleTilvalgRowHtml('handske', TILVALG_LABELS.handske); el.tilvalgListe.innerHTML = rows; Array.prototype.forEach.call(el.tilvalgListe.querySelectorAll('[data-jordvalg]'), function (btn) { btn.addEventListener('click', function () { jordvalgFed = btn.getAttribute('data-jordvalg'); renderTilvalg(); updatePricebar(); }); }); Array.prototype.forEach.call(el.tilvalgListe.querySelectorAll('input[type=checkbox]'), function (cb) { cb.addEventListener('change', function () { var key = cb.getAttribute('data-tv'); valgteTilvalg[key] = valgteTilvalg[key] || { qty: 1 }; valgteTilvalg[key].checked = cb.checked; updatePricebar(); }); }); Array.prototype.forEach.call(el.tilvalgListe.querySelectorAll('.ptv-bw-tilvalg-qty'), function (inp) { inp.addEventListener('input', function () { var key = inp.getAttribute('data-tvqty'); valgteTilvalg[key] = valgteTilvalg[key] || { checked: false }; valgteTilvalg[key].qty = Math.max(1, parseInt(inp.value, 10) || 1); renderTilvalg(); updatePricebar(); }); }); } function updateSelectedCount() { var n = Object.keys(valgteProdukter).length; el.selectedCount.textContent = n > 0 ? n + ' produkt' + (n === 1 ? '' : 'er') + ' valgt' : ''; } function renderGrid(pool) { if (pool.length === 0) { el.grid.innerHTML = '
Ingen roser matcher dine filtre.
'; return; } el.grid.innerHTML = pool.map(function (p) { var checked = !!valgteProdukter[p.plante_id]; var imgHtml = p.billede ? '' : '
🌱
'; return '
' + '
' + (checked ? '✓' : '') + '
' + imgHtml + '
' + p.navn + '
' + '
' + p.navn_botanisk + '
' + '
'; }).join(''); Array.prototype.forEach.call(el.grid.querySelectorAll('.ptv-bw-card'), function (card) { card.addEventListener('click', function () { var id = parseInt(card.getAttribute('data-id'), 10); if (valgteProdukter[id]) delete valgteProdukter[id]; else valgteProdukter[id] = true; card.classList.toggle('ptv-bw-checked'); card.querySelector('.ptv-bw-card-check').textContent = valgteProdukter[id] ? '✓' : ''; updateSelectedCount(); opdaterVaelgAlleBtn(pool); }); }); } function vaelgAlleAktiv(pool) { return pool.length > 0 && pool.every(function (p) { return !!valgteProdukter[p.plante_id]; }); } function opdaterVaelgAlleBtn(pool) { if (!el.vaelgAlleBtn) return; if (pool.length === 0) { el.vaelgAlleBtn.hidden = true; return; } el.vaelgAlleBtn.hidden = false; el.vaelgAlleBtn.textContent = vaelgAlleAktiv(pool) ? 'Fravælg alle' : 'Vælg alle'; } function toggleVaelgAlle() { var pool = DATA.kandidater.filter(matchFilter); if (vaelgAlleAktiv(pool)) { pool.forEach(function (p) { delete valgteProdukter[p.plante_id]; }); } else { pool.forEach(function (p) { valgteProdukter[p.plante_id] = true; }); } renderGrid(pool); updateSelectedCount(); opdaterVaelgAlleBtn(pool); } function render() { if (!DATA) return; var pool = DATA.kandidater.filter(matchFilter); el.matchCount.textContent = pool.length + ' roser matcher dine filtre'; el.empty.hidden = pool.length !== 0; renderGrid(pool); updateSelectedCount(); opdaterVaelgAlleBtn(pool); } function visResultat(sammensaetning) { sidsteValgt = sammensaetning; renderResultat(sammensaetning); el.resultat.hidden = false; renderTilvalg(); updatePricebar(); el.pricebar.hidden = false; el.cta.hidden = false; el.disclaimer.hidden = false; el.hint.hidden = true; } function skjulResultat(besked) { sidsteValgt = []; el.resultat.hidden = true; el.tilvalgSection.hidden = true; el.pricebar.hidden = true; el.cta.hidden = true; el.disclaimer.hidden = true; if (besked) { el.hint.hidden = false; el.hint.textContent = besked; } } function beregn() { var areal = getAreal(); var valgtePlanter = DATA.kandidater.filter(function (p) { return valgteProdukter[p.plante_id]; }); if (valgtePlanter.length === 0) { skjulResultat('Marker mindst én rose i listen ovenfor for at beregne.'); return; } if (areal <= 0) { skjulResultat('Angiv arealet i m² for at beregne mængde og pris.'); return; } visResultat(beregnMaengder(valgtePlanter, areal)); } function fetchData() { fetch(DATA_URL).then(function (r) { return r.json(); }).then(function (json) { if (!json || !json.ok) { el.loading.textContent = 'Kunne ikke hente roser lige nu. Prøv at genindlæse siden.'; return; } DATA = json; el.loading.hidden = true; el.body.hidden = false; var vis = computeUsedFilterSets(DATA.kandidater); FARVE_VIS = vis.farve; LYS_VIS = vis.lys; JORD_VIS = vis.jord; HOEJDE_VIS = vis.hoejde; SAESON_VIS = vis.saeson; ANVENDELSE_VIS = vis.anvendelse; OVRIGE_VIS = vis.ovrige; OPSTAMMET_VIS = vis.opstammet; STAMMEHOEJDE_VIS = vis.stammehoejde; renderFilterFields(); render(); }).catch(function () { el.loading.textContent = 'Kunne ikke hente roser lige nu. Prøv at genindlæse siden.'; }); } el.head.addEventListener('click', function () { ROOT.classList.toggle('ptv-collapsed'); }); el.areal.addEventListener('input', function () { if (sidsteValgt.length) beregn(); }); el.arealMinus.addEventListener('click', function () { el.areal.value = Math.max(0.5, (parseFloat(el.areal.value) || 1) - 0.5); if (sidsteValgt.length) beregn(); }); el.arealPlus.addEventListener('click', function () { el.areal.value = (parseFloat(el.areal.value) || 0) + 0.5; if (sidsteValgt.length) beregn(); }); el.beregnBtn.addEventListener('click', beregn); el.beregnBtnTop.addEventListener('click', beregn); el.vaelgAlleBtn.addEventListener('click', toggleVaelgAlle); el.cta.addEventListener('click', function () { var items = sidsteValgt.map(function (item) { return { vareNr: item.varenr, quantity: item.antalPlanter }; }); var jl = jordforbedringLinje(); if (jl && valgteTilvalg.jordforbedring && valgteTilvalg.jordforbedring.checked) { items.push({ vareNr: jl.varenr, quantity: jl.antal }); } var gl = godningLinje(); if (gl && valgteTilvalg.godning && valgteTilvalg.godning.checked) { items.push({ vareNr: gl.varenr, quantity: gl.antal }); } ['felco', 'handske'].forEach(function (key) { var produkt = findTilvalgByKey(key); var state = valgteTilvalg[key]; if (produkt && state && state.checked) { items.push({ vareNr: produkt.varenr, quantity: Math.max(1, state.qty || 1) }); } }); if (!items.length) return; el.cta.disabled = true; el.status.className = 'ptv-bw-status'; el.status.textContent = 'Opretter kurv…'; fetch(KURV_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ items: items }) }) .then(function (r) { return r.json(); }) .then(function (res) { el.cta.disabled = false; if (res && res.success && res.url) { el.status.className = 'ptv-bw-status ptv-ok'; el.status.innerHTML = 'Kurv oprettet — sender dig til kurven…'; try { var topWin = window.top || window.parent || window; topWin.location.href = res.url; } catch (e) { el.status.innerHTML = 'Kurv oprettet — gå til kurv →'; } } else { el.status.className = 'ptv-bw-status ptv-error'; el.status.textContent = 'Kunne ikke oprette kurven automatisk. Prøv igen om lidt.'; } }) .catch(function () { el.cta.disabled = false; el.status.className = 'ptv-bw-status ptv-error'; el.status.textContent = 'Kunne ikke oprette kurven automatisk. Prøv igen om lidt.'; }); }); fetchData(); }); })();