1(function () { 2 'use strict'; 3 4 function getVisibleText(el) { 5 const clone = el.cloneNode(true); 6 clone.querySelectorAll('.sr-only, .icon').forEach(function (n) { n.remove(); }); 7 return clone.textContent.trim(); 8 } 9 10 function prefersReducedMotion() { 11 return window.matchMedia('(prefers-reduced-motion: reduce)').matches; 12 } 13 14 function getOrCreateLiveRegion() { 15 let region = document.getElementById('bm-live-region'); 16 if (!region) { 17 region = document.createElement('div'); 18 region.id = 'bm-live-region'; 19 region.setAttribute('aria-live', 'polite'); 20 region.setAttribute('aria-atomic', 'true'); 21 region.className = 'sr-only'; 22 document.body.appendChild(region); 23 } 24 return region; 25 } 26 27 function announce(message) { 28 const region = getOrCreateLiveRegion(); 29 region.textContent = ''; 30 requestAnimationFrame(function () { region.textContent = message; }); 31 } 32 33 // Liest alle .matrix-main Bloecke INNERHALB eines gegebenen Containers 34 function readMatrixData(container) { 35 const columns = []; 36 37 container.querySelectorAll('.matrix-main').forEach(function (mainEl) { 38 const mainToggleBtn = mainEl.querySelector(':scope > .card-collapse-heading button'); 39 if (!mainToggleBtn) return; 40 41 const columnTitle = mainEl.getAttribute('data-title') || getVisibleText(mainToggleBtn); 42 const bereiche = []; 43 44 mainEl.querySelectorAll('h3.bereich').forEach(function (h3) { 45 const bereichTitle = h3.textContent.trim(); 46 const items = []; 47 48 let sibling = h3.nextElementSibling; 49 while (sibling) { 50 if (sibling.matches('h3.bereich')) break; 51 52 if (sibling.matches('.bereich-item, .card-collapse.bereich-item')) { 53 const itemBtn = sibling.querySelector('.card-collapse-heading button'); 54 const collapseId = itemBtn 55 ? (itemBtn.getAttribute('data-target') || itemBtn.getAttribute('aria-controls')) 56 : null; 57 const collapseSelector = collapseId 58 ? (collapseId.charAt(0) === '#' ? collapseId : '#' + collapseId) 59 : null; 60 const collapseEl = collapseSelector 61 ? sibling.querySelector(collapseSelector) || mainEl.querySelector(collapseSelector) 62 : null; 63 64 if (itemBtn) { 65 items.push({ 66 title: getVisibleText(itemBtn), 67 btn: itemBtn, 68 collapseEl: collapseEl, 69 mainEl: mainEl, 70 mainToggleBtn: mainToggleBtn, 71 pill: null 72 }); 73 } 74 } 75 76 sibling = sibling.nextElementSibling; 77 } 78 79 if (items.length > 0) { 80 bereiche.push({ title: bereichTitle, items: items }); 81 } 82 }); 83 84 if (bereiche.length > 0) { 85 columns.push({ title: columnTitle, mainEl: mainEl, mainToggleBtn: mainToggleBtn, bereiche: bereiche }); 86 } 87 }); 88 89 return columns; 90 } 91 92 function collectRowTitles(columns) { 93 const seen = new Set(); 94 const titles = []; 95 columns.forEach(function (col) { 96 col.bereiche.forEach(function (b) { 97 if (!seen.has(b.title)) { seen.add(b.title); titles.push(b.title); } 98 }); 99 }); 100 return titles; 101 } 102 103 function buildTable(columns, container) { 104 const rowTitles = collectRowTitles(columns); 105 106 const wrapper = document.createElement('div'); 107 wrapper.className = 'belastungsmatrix-table-wrapper'; 108 wrapper.setAttribute('tabindex', '0'); 109 wrapper.setAttribute('role', 'region'); 110 const lang = container.closest('[lang]')?.getAttribute('lang'); 111 if(lang == "de"){ 112 wrapper.setAttribute('aria-label', 'Ãbersicht aller Themenfelder'); 113 }else { 114 wrapper.setAttribute('aria-label', 'Overview of all topics'); 115 } 116 117 const table = document.createElement('table'); 118 table.className = 'belastungsmatrix-table'; 119 120 const caption = table.createCaption(); 121 if(lang == "de"){ 122 caption.textContent = 'Ãbersicht aller Themenfelder'; 123 }else { 124 caption.textContent = 'Overview of all topics'; 125 } 126 caption.className = 'bm-caption sr-only'; 127 128 // colgroup: erste col (Zeilen-Header) schmal, restliche cols gleichmäÃig 129 const colgroup = document.createElement('colgroup'); 130 const colHeader = document.createElement('col'); 131 colHeader.style.width = '2.5rem'; 132 colgroup.appendChild(colHeader); 133 columns.forEach(function () { 134 colgroup.appendChild(document.createElement('col')); 135 }); 136 table.appendChild(colgroup); 137 138 const thead = table.createTHead(); 139 const headerRow = thead.insertRow(); 140 141 const thCorner = document.createElement('th'); 142 thCorner.className = 'bm-corner'; 143 thCorner.setAttribute('scope', 'col'); 144 if(lang == "de"){ 145 thCorner.innerHTML = '<span class="sr-only">Arbeitsbereich</span>'; 146 }else { 147 thCorner.innerHTML = '<span class="sr-only">work area</span>'; 148 } 149 150 headerRow.appendChild(thCorner); 151 152 columns.forEach(function (col) { 153 const th = document.createElement('th'); 154 th.className = 'bm-col-header'; 155 th.setAttribute('scope', 'col'); 156 th.textContent = col.title; 157 headerRow.appendChild(th); 158 }); 159 160 const tbody = table.createTBody(); 161
162 rowTitles.forEach(function (rowTitle) { 163 const tr = tbody.insertRow(); 164 165 const thRow = document.createElement('th'); 166 thRow.className = 'bm-row-header'; 167 thRow.setAttribute('scope', 'row'); 168 const thRowSpan = document.createElement('span'); 169 thRowSpan.textContent = rowTitle; 170 thRow.appendChild(thRowSpan); 171 tr.appendChild(thRow); 172 173 columns.forEach(function (col) { 174 const td = document.createElement('td'); 175 td.className = 'bm-cell'; 176 177 const bereich = col.bereiche.find(function (b) { return b.title === rowTitle; }); 178 if (bereich) { 179 const pillWrap = document.createElement('div'); 180 pillWrap.className = 'bm-pills'; 181 182 bereich.items.forEach(function (item) { 183 const pill = document.createElement('button'); 184 pill.className = 'bm-pill'; 185 pill.type = 'button'; 186 pill.innerHTML = item.title; 187 if(lang == "de"){ 188 pill.setAttribute('aria-label', item.title + ' â zum Accordion springen und aufklappen'); 189 }else { 190 pill.setAttribute('aria-label', item.title + ' â Jump to the accordion and open it'); 191 } 192 193 item.pill = pill; 194 195 pill.addEventListener('click', function () { openAccordionItem(item); }); 196 197 pillWrap.appendChild(pill); 198 }); 199 200 td.appendChild(pillWrap); 201 } 202 203 tr.appendChild(td); 204 }); 205 }); 206 207 table.appendChild(tbody); 208 wrapper.appendChild(table); 209 210 // Tabelle VOR den ersten .matrix-main innerhalb des Containers einsetzen 211 const firstMatrix = container.querySelector('.matrix-main'); 212 if (firstMatrix) { 213 container.insertBefore(wrapper, firstMatrix); 214 } else { 215 container.appendChild(wrapper); 216 } 217 } 218 219 function isOpen(collapseEl) { 220 return !!collapseEl && collapseEl.classList.contains('show'); 221 } 222 223 function triggerShow(btn, collapseEl) { 224 if (!collapseEl) return; 225 if (window.jQuery) { 226 jQuery(collapseEl).collapse('show'); 227 return; 228 } 229 if (window.bootstrap && window.bootstrap.Collapse) { 230 window.bootstrap.Collapse.getOrCreateInstance(collapseEl, { toggle: false }).show(); 231 return; 232 } 233 btn.setAttribute('aria-expanded', 'true'); 234 btn.classList.remove('collapsed'); 235 collapseEl.classList.add('show'); 236 collapseEl.removeAttribute('hidden'); 237 } 238 239 function openAccordionItem(item) { 240 const mainCollapseId = item.mainToggleBtn.getAttribute('data-target') 241 || item.mainToggleBtn.getAttribute('aria-controls'); 242 const mainCollapseSelector = mainCollapseId 243 ? (mainCollapseId.charAt(0) === '#' ? mainCollapseId : '#' + mainCollapseId) 244 : null; 245 const mainCollapse = mainCollapseSelector 246 ? item.mainEl.querySelector(mainCollapseSelector) 247 : null; 248 249 const needsMainOpen = mainCollapse && !isOpen(mainCollapse); 250 if (needsMainOpen) triggerShow(item.mainToggleBtn, mainCollapse); 251 252 const delay = needsMainOpen ? 380 : 0; 253 254 setTimeout(function () { 255 if (item.collapseEl && !isOpen(item.collapseEl)) { 256 triggerShow(item.btn, item.collapseEl); 257 } 258 259 setTimeout(function () { 260 const targetEl = item.btn.closest('.card-collapse') || item.btn; 261 262 targetEl.scrollIntoView({ 263 behavior: prefersReducedMotion() ? 'instant' : 'smooth', 264 block: 'start' 265 }); 266 267 item.btn.focus({ preventScroll: true }); 268 announce('Accordion ' + item.title + ' wurde geoeffnet.'); 269 270 if (!prefersReducedMotion()) { 271 targetEl.classList.add('bm-highlight'); 272 setTimeout(function () { targetEl.classList.remove('bm-highlight'); }, 2000); 273 } 274 }, 120); 275 }, delay); 276 } 277 278 function processContainer(container) { 279 const columns = readMatrixData(container); 280 if (columns.length === 0) return; 281 buildTable(columns, container); 282 } 283 284 function init(options) { 285 const opts = Object.assign({ scope: '.belastungsmatrix-container' }, options); 286 const containers = document.querySelectorAll(opts.scope); 287 288 if (containers.length === 0) return; 289 290 getOrCreateLiveRegion(); 291
292 containers.forEach(function (container) { 293 try { 294 processContainer(container); 295 } catch (e) { 296 console.warn('BelastungsmatrixTable: Fehler in Container', container, e); 297 } 298 }); 299 } 300 301 window.BelastungsmatrixTable = { init: init }; 302 303 if (document.readyState === 'loading') { 304 document.addEventListener('DOMContentLoaded', function () { init(); }); 305 } else { 306 init(); 307 } 308}());
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.