1/** 2 * Program â filtrace pÅednášek. 3 * 4 * Obsluha popupu ÅeÄnÃka se pÅesunula do src/js/speaker-popup.js (spoleÄná 5 * s blokem ÅeÄnÃci). Tady zůstávajà jen filtry. 6 */ 7(function () { 8 const qs = (sel, root = document) => root.querySelector(sel); 9 const qsa = (sel, root = document) => Array.from(root.querySelectorAll(sel)); 10 11 const TEXTS = (typeof window !== 'undefined' && window.abfProgramTexts) || {}; 12 13 function text(key, fallback) { 14 const value = TEXTS[key]; 15 return typeof value === 'string' && value !== '' ? value : fallback; 16 } 17 18 // SkloÅovánà držà stejné pravidlo jako abf_program_count_text() v PHP, 19 // aby text po prvnÃm filtrovánà neposkoÄil do jiného tvaru. 20 function form(n) { 21 if (n === 1) return 'One'; 22 if (n >= 2 && n <= 4) return 'Few'; 23 return 'Many'; 24 } 25 26 function countText(found, total) { 27 if (found === total) { 28 const fallback = { One: 'Celkem %d pÅednáška', Few: 'Celkem %d pÅednášky', Many: 'Celkem %d pÅednášek' }; 29 return text('countTotal' + form(total), fallback[form(total)]).replace('%d', String(total)); 30 } 31 32 const fallback = { 33 One: 'Nalezena %d pÅednáška z %t', 34 Few: 'Nalezeny %d pÅednášky z %t', 35 Many: 'Nalezeno %d pÅednášek z %t', 36 }; 37 return text('countFound' + form(found), fallback[form(found)]) 38 .replace('%d', String(found)) 39 .replace('%t', String(total)); 40 } 41 42 function applyFilters(tabPane) { 43 const filtersRoot = qs('[data-program-filters]', tabPane); 44 if (!filtersRoot) return; 45 46 const placeVal = qs('select[data-filter="place"]', filtersRoot)?.value || ''; 47 const timewindowVal = qs('select[data-filter="timewindow"]', filtersRoot)?.value || ''; 48 const speakerVal = qs('select[data-filter="speaker"]', filtersRoot)?.value || ''; 49 const filtering = !!(placeVal || timewindowVal || speakerVal); 50 51 // 1) pÅednášky 52 const events = qsa('.event-list-item-wrapper', tabPane); 53 let found = 0; 54 55 events.forEach((el) => { 56 const elPlace = el.getAttribute('data-place') || ''; 57 const elTimewindow = el.getAttribute('data-timewindow') || ''; 58 59 // PÅednáška může mÃt vÃc ÅeÄnÃků â atribut je seznam ID oddÄlený Äárkou, 60 // takže se musà hledat v seznamu, ne porovnávat celý ÅetÄzec. 61 const elSpeakerIds = (el.getAttribute('data-speaker-id') || '') 62 .split(',') 63 .map((id) => id.trim()) 64 .filter(Boolean); 65 66 const okPlace = !placeVal || elPlace === placeVal; 67 const okTime = !timewindowVal || elTimewindow === timewindowVal; 68 const okSpeaker = !speakerVal || elSpeakerIds.includes(speakerVal); 69 70 const show = okPlace && okTime && okSpeaker; 71 el.style.display = show ? '' : 'none'; 72 if (show) found++; 73 }); 74 75 // 2) sekce (hala / blok programu) â bez filtru se nikdy neskrývá nic, 76 // aby se nezmÄnil výchozà vzhled stránky. Viditelnost poÄÃtáme z výsledku 77 // filtru, ne z vykreslené viditelnosti: neaktivnà záložka dne je display:none. 78 qsa('.program-section-wrapper', tabPane).forEach((section) => { 79 const inside = qsa('.event-list-item-wrapper', section); 80 const hasVisible = inside.some((el) => el.style.display !== 'none'); 81 section.style.display = filtering && !hasVisible ? 'none' : ''; 82 }); 83 84 // 3) poÄet výsledků, tlaÄÃtko pro zruÅ¡enà filtrů a prázdný stav 85 const countEl = qs('[data-program-count]', tabPane); 86 const total = countEl ? parseInt(countEl.getAttribute('data-total') || '', 10) : NaN; 87 const totalCount = Number.isFinite(total) ? total : events.length; 88 89 if (countEl) countEl.textContent = countText(found, totalCount); 90 91 qsa('[data-program-reset]', tabPane).forEach((btn) => { 92 const inEmptyState = !!btn.closest('[data-program-empty]'); 93 if (!inEmptyState) btn.hidden = !filtering; 94 }); 95 96 const emptyEl = qs('[data-program-empty]', tabPane); 97 if (emptyEl) emptyEl.hidden = !(filtering && found === 0); 98 } 99 100 function resetFilters(tabPane) { 101 const filtersRoot = qs('[data-program-filters]', tabPane); 102 if (!filtersRoot) return; 103 104 qsa('select', filtersRoot).forEach((sel) => { 105 sel.value = ''; 106 }); 107 108 applyFilters(tabPane); 109 110 const firstSelect = qs('select', filtersRoot); 111 if (firstSelect) firstSelect.focus(); 112 } 113 114 function bindProgramFilters(scope) { 115 const panes = qsa('.w-tab-pane', scope); 116
117 panes.forEach((pane) => { 118 const filtersRoot = qs('[data-program-filters]', pane); 119 if (!filtersRoot) return; 120 121 // KoÅeny `.wp-block-custom-block` se můžou pÅekrývat (blok v bloku) a stejný 122 // panel by se pak proÅ¡el dvakrát â bez pojistky by se posluchaÄe navázaly opakovanÄ. 123 if (pane.dataset.abfFiltersBound === '1') { 124 applyFilters(pane); 125 return; 126 } 127 pane.dataset.abfFiltersBound = '1'; 128 129 qsa('select', filtersRoot).forEach((sel) => { 130 sel.addEventListener('change', () => applyFilters(pane)); 131 }); 132 133 qsa('[data-program-reset]', pane).forEach((btn) => { 134 btn.addEventListener('click', (e) => { 135 e.preventDefault(); 136 resetFilters(pane); 137 }); 138 }); 139 140 // init 141 applyFilters(pane); 142 }); 143 144 // když pÅepneÅ¡ tab, Webflow jen pÅepÃná classes 145 // takže je dobré pÅi kliknutà na tab link znovu aplikovat filtry na aktivnà pane 146 qsa('.w-tab-link', scope).forEach((link) => { 147 link.addEventListener('click', () => { 148 // micro delay â po pÅepnutà tabů 149 setTimeout(() => { 150 const activePane = qs('.w-tab-pane.w--tab-active', scope); 151 if (activePane) applyFilters(activePane); 152 }, 0); 153 }); 154 }); 155 } 156 157 // pokud může být program blok na stránce vÃckrát, radÅ¡i scope: 158 const boot = () => qsa('.wp-block-custom-block').forEach((block) => bindProgramFilters(block)); 159 160 // OptimalizaÄnà pluginy obÄas vložà skript až po DOMContentLoaded â pak by se 161 // posluchaÄ nikdy nespustil a filtry by zůstaly mrtvé. StejnÄ jako archiv-akci.js. 162 if (document.readyState === 'loading') { 163 document.addEventListener('DOMContentLoaded', boot); 164 } else { 165 boot(); 166 } 167})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.