1/** 2 * Category / content tabs â click tab to show matching panel (editor + live pages). 3 */ 4(function (global) { 5 'use strict'; 6 7 if (global.__bwTabsBooted) { 8 return; 9 } 10 global.__bwTabsBooted = true; 11 12 var delegatedDocs = typeof WeakSet !== 'undefined' ? new WeakSet() : null; 13 var delegatedBoundLegacy = false; 14 15 function isEditorMode() { 16 if (global.BW_IS_CONTENTBOX_EDITOR || global.BW_IS_AIBOX_EDITOR) { 17 return true; 18 } 19 if (global.BwIsContentboxEditor && global.BwIsContentboxEditor()) { 20 return true; 21 } 22 if (global.BwContentboxClickfix && typeof global.BwContentboxClickfix.isEditorMode === 'function') { 23 return global.BwContentboxClickfix.isEditorMode(); 24 } 25 if (document.body && document.body.classList.contains('bw-page-editor')) { 26 return true; 27 } 28 return false; 29 } 30 31 function tabButtons(tabs) { 32 return tabs.querySelectorAll('.bw-tab-nav .bw-tab-btn, .bw-tab-nav button[data-bw-tab], .bw-tab-nav button'); 33 } 34 35 function tabPanels(tabs) { 36 return tabs.querySelectorAll('.bw-tab-panels > .bw-tab-panel, .bw-tab-panels > [data-bw-tab-panel]'); 37 } 38 39 function readBtnSlug(btn) { 40 return btn.getAttribute('data-bw-tab') || ''; 41 } 42 43 function panelSlug(panel) { 44 return panel.getAttribute('data-bw-tab-panel') || ''; 45 } 46 47 function styleTabButton(btn, active) { 48 btn.classList.toggle('is-active', active); 49 btn.setAttribute('aria-selected', active ? 'true' : 'false'); 50 } 51 52 function showPanel(panel, show) { 53 if (show) { 54 panel.removeAttribute('hidden'); 55 panel.classList.add('is-active'); 56 } else { 57 panel.setAttribute('hidden', 'hidden'); 58 panel.classList.remove('is-active'); 59 } 60 } 61 62 function activateTabInSection(sec, slug) { 63 if (!sec || !slug) { 64 return false; 65 } 66 var panels = sec.querySelectorAll('.bw-tab-panels > .bw-tab-panel, .bw-tab-panels > [data-bw-tab-panel], .bw-tab-panel[data-bw-tab-panel], [data-bw-tab-panel]'); 67 if (!panels.length) { 68 return false; 69 } 70 var matched = false; 71 panels.forEach(function (panel) { 72 var on = panelSlug(panel) === slug; 73 showPanel(panel, on); 74 if (on) { 75 matched = true; 76 } 77 }); 78 if (!matched) { 79 return false; 80 } 81 sec.querySelectorAll('.bw-tab-nav .bw-tab-btn, .bw-tab-nav button[data-bw-tab], .bw-tab-nav button').forEach(function (btn) { 82 styleTabButton(btn, readBtnSlug(btn) === slug); 83 }); 84 return true; 85 } 86 87 function activateTab(tabs, slug) { 88 if (!tabs || !slug) { 89 return; 90 } 91 var sec = tabs.closest('.is-section'); 92 if (sec && activateTabInSection(sec, slug)) { 93 return; 94 } 95 var matched = false; 96 tabPanels(tabs).forEach(function (panel) { 97 var on = panelSlug(panel) === slug; 98 showPanel(panel, on); 99 if (on) { 100 matched = true; 101 } 102 }); 103 if (!matched) { 104 return; 105 } 106 tabButtons(tabs).forEach(function (btn) { 107 styleTabButton(btn, readBtnSlug(btn) === slug); 108 }); 109 } 110 111 function mergeOrphanTabPanels(tabs) { 112 if (!tabs) { 113 return; 114 } 115 var sec = tabs.closest('.is-section'); 116 if (!sec) { 117 return; 118 } 119 var wraps = sec.querySelectorAll('.bw-tab-panels'); 120 if (wraps.length < 2) { 121 return; 122 } 123 var best = null; 124 var bestScore = -1; 125 wraps.forEach(function (wrap) { 126 var score = wrap.querySelectorAll('.gallery-item, .bw-tab-panel .column, .bw-tab-panel img').length; 127 score += wrap.querySelectorAll('.bw-tab-panel').length * 3; 128 var btnOnly = wrap.querySelectorAll('a.is-btn, button.is-btn').length; 129 if (btnOnly > 0 && score < 8) { 130 score -= 20; 131 } 132 if (score > bestScore) { 133 bestScore = score; 134 best = wrap; 135 } 136 }); 137 if (!best || best.parentElement === tabs) { 138 return; 139 } 140 wraps.forEach(function (wrap) { 141 if (wrap !== best && wrap.parentElement) { 142 wrap.parentElement.removeChild(wrap); 143 } 144 }); 145 if (best.parentElement !== tabs) { 146 tabs.appendChild(best); 147 } 148 } 149 150 function prepareTabs(tabs) { 151 if (!tabs) { 152 return; 153 } 154 mergeOrphanTabPanels(tabs); 155 156 var btns = tabButtons(tabs); 157 var panels = tabPanels(tabs); 158 if (!btns.length || !panels.length) { 159 return; 160 } 161 if (tabs.getAttribute('data-bw-tabs-prepared') === '1') { 162 return; 163 } 164 tabs.setAttribute('data-bw-tabs-prepared', '1'); 165 166 btns.forEach(function (btn, i) { 167 if (!btn.getAttribute('type')) { 168 btn.setAttribute('type', 'button'); 169 } 170 if (!btn.classList.contains('bw-tab-btn')) { 171 btn.classList.add('bw-tab-btn'); 172 } 173 btn.setAttribute('role', 'tab'); 174 if (!btn.getAttribute('data-bw-tab')) { 175 var label = (btn.textContent || '').trim().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, ''); 176 btn.setAttribute('data-bw-tab', label || ('tab-' + i)); 177 } 178 }); 179
180 panels.forEach(function (panel, i) { 181 panel.setAttribute('role', 'tabpanel'); 182 if (!panel.getAttribute('data-bw-tab-panel')) { 183 var btn = btns[i]; 184 if (btn) { 185 panel.setAttribute('data-bw-tab-panel', readBtnSlug(btn)); 186 } 187 } 188 }); 189 190 var activeSlug = ''; 191 btns.forEach(function (btn) { 192 if (btn.classList.contains('is-active')) { 193 activeSlug = readBtnSlug(btn); 194 } 195 }); 196 if (!activeSlug) { 197 activeSlug = readBtnSlug(btns[0]); 198 } 199 activateTab(tabs, activeSlug); 200 } 201 202 function bindDelegation(doc) { 203 doc = doc || document; 204 if (delegatedDocs) { 205 if (delegatedDocs.has(doc)) { 206 return; 207 } 208 delegatedDocs.add(doc); 209 } else if (doc === document) { 210 if (delegatedBoundLegacy) { 211 return; 212 } 213 delegatedBoundLegacy = true; 214 } 215 216 doc.addEventListener('click', function (e) { 217 var btn = e.target.closest('.bw-tab-nav .bw-tab-btn, .bw-tab-nav button'); 218 if (!btn) { 219 return; 220 } 221 var slug = readBtnSlug(btn); 222 if (!slug) { 223 return; 224 } 225 var sec = btn.closest('.is-section'); 226 e.preventDefault(); 227 e.stopPropagation(); 228 if (sec && activateTabInSection(sec, slug)) { 229 return; 230 } 231 var tabs = btn.closest('[data-bw-tabs], .bw-tabs'); 232 if (!tabs) { 233 return; 234 } 235 activateTab(tabs, slug); 236 }, true); 237 238 doc.addEventListener('keydown', function (e) { 239 if (e.key !== 'Enter' && e.key !== ' ') { 240 return; 241 } 242 var btn = e.target.closest('.bw-tab-nav .bw-tab-btn, .bw-tab-nav button'); 243 if (!btn) { 244 return; 245 } 246 var tabs = btn.closest('[data-bw-tabs], .bw-tabs'); 247 if (!tabs) { 248 return; 249 } 250 e.preventDefault(); 251 activateTab(tabs, readBtnSlug(btn)); 252 }, true); 253 } 254 255 function init(root) { 256 root = root || document; 257 var doc = (root.nodeType === 9) ? root : (root.ownerDocument || document); 258 var scope = (root.nodeType === 9) ? (root.body || root) : root; 259 bindDelegation(doc); 260 scope.querySelectorAll('[data-bw-tabs], .bw-tabs').forEach(prepareTabs); 261 } 262 263 function watch() { 264 init(document); 265 if (typeof MutationObserver === 'undefined') { 266 return; 267 } 268 var obs = new MutationObserver(function () { 269 init(document); 270 }); 271 var target = document.querySelector('.is-wrapper') || document.body; 272 if (target) { 273 obs.observe(target, { childList: true, subtree: true }); 274 } 275 } 276 277 global.BwTabs = { init: init, watch: watch, activateTab: activateTab }; 278 279 function boot() { 280 watch(); 281 window.addEventListener('load', function () { 282 init(document); 283 }); 284 } 285 286 if (document.readyState === 'loading') { 287 document.addEventListener('DOMContentLoaded', boot); 288 } else { 289 boot(); 290 } 291})(typeof window !== 'undefined' ? window : this);
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.