1function TabsScript() { 2 const app = { 3 init() { 4 // ÐниÑиализиÑÑем вÑе ÑабÑ, и Ñ wrap=true, и Ñ wrap=false 5 this.blocks = document.querySelectorAll('.tabs') 6 7 if (!this.blocks.length) return 8 9 this.resizeTimeout = null 10 11 this.initOverflow() 12 this.initBurgerToggles() 13 this.initTabItemSelection() 14 this.initClickOutside() 15 this.initResize() 16 this.initScrollArrows() 17 }, 18 19 initOverflow() { 20 const { blocks } = this 21 22 blocks.forEach((tabs) => { 23 const list = tabs.querySelector('.tabs__list') 24 const overflowContainer = tabs.querySelector('.tabs-select') 25 const burger = tabs.querySelector('.tabs__burger') 26 27 if (!list || !overflowContainer) return 28 29 const items = Array.from(list.children) 30 31 const selected = overflowContainer.querySelector('.tabs-select__selected') 32 Array.from(overflowContainer.children).forEach((child) => { 33 if (child !== selected) { 34 overflowContainer.removeChild(child) 35 } 36 }) 37 38 const listStyles = window.getComputedStyle(list) 39 const gap = 40 parseFloat( 41 listStyles.gap || listStyles.columnGap || listStyles.rowGap || '0' 42 ) || 0 43 44 const containerWidth = list.clientWidth 45 let usedWidth = 0 46 47 items.forEach((item, index) => { 48 const itemWidth = item.offsetWidth 49 50 if (index > 0) { 51 usedWidth += gap 52 } 53 54 usedWidth += itemWidth 55 56 if (usedWidth > containerWidth) { 57 const text = item.textContent.trim() 58 const overflowItem = document.createElement('div') 59 60 overflowItem.className = 'tabs-select__item js-tab-item' 61 overflowItem.textContent = text 62 63 if (item.dataset && item.dataset.ajaxUrl) { 64 overflowItem.dataset.ajaxUrl = item.dataset.ajaxUrl 65 } 66 67 overflowContainer.appendChild(overflowItem) 68 69 // УбиÑаем Ñаб из оÑновной ÑазмеÑки 70 list.removeChild(item) 71 } 72 }) 73 74 const overflowItemsCount = 75 overflowContainer.children.length - (selected ? 1 : 0) 76 77 if (burger) { 78 burger.style.display = overflowItemsCount > 0 ? '' : 'none' 79 } 80 }) 81 }, 82 83 initBurgerToggles() { 84 const { blocks } = this 85 86 blocks.forEach((tabs) => { 87 const burger = tabs.querySelector('.tabs__burger') 88 if (!burger) return 89 90 const button = burger.querySelector('.btn') 91 if (!button) return 92 93 button.addEventListener('click', (ev) => { 94 ev.preventDefault() 95 96 const isActive = burger.classList.contains('active') 97 98 const allBurgersInBlock = tabs.querySelectorAll('.tabs__burger') 99 allBurgersInBlock.forEach((b) => { 100 b.classList.remove('active') 101 102 const btn = b.querySelector('.btn') 103 if (btn && window.slam && window.slam.app && window.slam.app.setIcon) { 104 window.slam.app.setIcon(btn, 'i-burger') 105 } 106 }) 107 108 if (!isActive) { 109 burger.classList.add('active') 110 111 if (window.slam && window.slam.app && window.slam.app.setIcon) { 112 window.slam.app.setIcon(button, 'i-close') 113 } 114 } else { 115 if (window.slam && window.slam.app && window.slam.app.setIcon) { 116 window.slam.app.setIcon(button, 'i-burger') 117 } 118 } 119 }) 120 }) 121 }, 122 123 initTabItemSelection() { 124 const { blocks } = this 125 126 blocks.forEach((tabs) => { 127 const selectedWrapper = tabs.querySelector('.tabs-select__selected') 128 const selectedSpan = 129 selectedWrapper && selectedWrapper.querySelector('.tabs-select__item span') 130 131 tabs.addEventListener('click', (ev) => { 132 const overflowItem = ev.target.closest('.tabs-select .js-tab-item') 133 const mainItem = ev.target.closest('.tabs__list .js-tab-item') 134 135 if (!overflowItem && !mainItem) return 136 137 const clickedItem = overflowItem || mainItem 138 139 // клик по ÑлеменÑÑ Ð² overflow (ÑолÑко еÑли еÑÑÑ Ð±Ð»Ð¾Ðº вÑбоÑа) 140 if (overflowItem && tabs.contains(overflowItem) && selectedWrapper && selectedSpan) { 141 const text = overflowItem.textContent.trim() 142 selectedSpan.textContent = text 143 selectedWrapper.style.display = '' 144 } 145 146 // клик по оÑÐ½Ð¾Ð²Ð½Ð¾Ð¼Ñ ÑÐ°Ð±Ñ (ÑбÑаÑÑваем вÑбÑаннÑй ÑÐ»ÐµÐ¼ÐµÐ½Ñ Ð² ÑелекÑе, еÑли он еÑÑÑ) 147 if (mainItem && tabs.contains(mainItem) && selectedWrapper && selectedSpan) { 148 selectedSpan.textContent = '' 149 selectedWrapper.style.display = 'none' 150 } 151 152 // менÑем акÑивнÑй Ñаб 153 app.setActiveTab(tabs, clickedItem) 154 155 // загÑÑжаем конÑÐµÐ½Ñ Ð¿Ð¾ AJAX 156 app.loadContent(tabs, clickedItem) 157 }) 158 }) 159 }, 160
161 setActiveTab(tabs, clickedItem) { 162 if (!tabs || !clickedItem) return 163 164 const listItems = tabs.querySelectorAll('.tabs__list .tabs__item') 165 const clickedText = clickedItem.textContent.trim() 166 167 // вÑегда Ñнимаем акÑивноÑÑÑ Ñо вÑÐµÑ Ð¾ÑновнÑÑ Ñабов 168 listItems.forEach((item) => { 169 item.classList.remove('active') 170 }) 171 172 let targetMainItem = clickedItem.closest('.tabs__item') 173 174 if (!targetMainItem) { 175 listItems.forEach((item) => { 176 if (!targetMainItem && item.textContent.trim() === clickedText) { 177 targetMainItem = item 178 } 179 }) 180 } 181 182 if (targetMainItem) { 183 targetMainItem.classList.add('active') 184 } 185 }, 186 187 loadContent(tabs, clickedItem) { 188 if (!tabs || !clickedItem || typeof window === 'undefined') return 189 190 const targetId = tabs.dataset.ajaxTargetId 191 if (!targetId) return 192 193 const targetEl = document.getElementById(targetId) 194 if (!targetEl) return 195 196 const url = 197 (clickedItem.dataset && clickedItem.dataset.ajaxUrl) || 198 (tabs.dataset && tabs.dataset.ajaxUrl) || 199 '/ajax/tabs-news-grid-example.html' 200 201 if (!url) return 202 203 const requestUrl = new URL(url, window.location.origin) 204 205 requestUrl.searchParams.set('IS_AJAX', 'Y') 206 207 fetch(requestUrl.toString(), { 208 headers: { 209 'X-Requested-With': 'XMLHttpRequest', 210 }, 211 }) 212 .then((response) => { 213 if (!response.ok) { 214 throw new Error(`Tabs AJAX request failed with status ${response.status}`) 215 } 216 217 return response.text() 218 }) 219 .then((html) => { 220 targetEl.innerHTML = html 221 }) 222 .catch((error) => { 223 // eslint-disable-next-line no-console 224 console.error('Tabs AJAX load error:', error) 225 }) 226 }, 227 228 initClickOutside() { 229 const { blocks } = this 230 231 if (!window.slam || !window.slam.app || !window.slam.app.clickOutside) return 232 233 blocks.forEach((tabs) => { 234 const burger = tabs.querySelector('.tabs__burger') 235 if (!burger) return 236 237 const button = burger.querySelector('.btn') 238 239 window.slam.app.clickOutside([burger, button], () => { 240 burger.classList.remove('active') 241 242 if (button && window.slam.app && window.slam.app.setIcon) { 243 window.slam.app.setIcon(button, 'i-burger') 244 } 245 }) 246 }) 247 }, 248 249 scrollToActiveTab(list) { 250 const activeItem = list.querySelector('.tabs__item.active') 251 if (!activeItem) return 252 253 const listRect = list.getBoundingClientRect() 254 const itemRect = activeItem.getBoundingClientRect() 255 256 const offsetLeft = itemRect.left - listRect.left + list.scrollLeft 257 const scrollPos = offsetLeft - (listRect.width - itemRect.width) / 2 258 259 list.scrollTo({ left: scrollPos, behavior: 'smooth' }) 260 }, 261 262 initScrollArrows() { 263 const { blocks } = this 264 265 blocks.forEach((tabs) => { 266 const btnLeft = tabs.querySelector('.js-tabs-scroll-left') 267 const btnRight = tabs.querySelector('.js-tabs-scroll-right') 268 269 if (!btnLeft || !btnRight) return 270 271 const list = tabs.querySelector('.tabs__list') 272 if (!list) return 273 274 const scrollStep = 200 275 276 const updateArrowStates = () => { 277 const { scrollLeft, scrollWidth, clientWidth } = list 278 const atStart = scrollLeft <= 0 279 const atEnd = scrollLeft + clientWidth >= scrollWidth - 1 280 281 btnLeft.classList.toggle('disabled', atStart) 282 btnRight.classList.toggle('disabled', atEnd) 283 } 284 285 this.scrollToActiveTab(list) 286 updateArrowStates() 287 288 list.addEventListener('scroll', updateArrowStates) 289 290 btnLeft.addEventListener('click', (ev) => { 291 ev.preventDefault() 292 list.scrollBy({ left: -scrollStep, behavior: 'smooth' }) 293 }) 294 295 btnRight.addEventListener('click', (ev) => { 296 ev.preventDefault() 297 list.scrollBy({ left: scrollStep, behavior: 'smooth' }) 298 }) 299 }) 300 }, 301 302 initResize() { 303 window.addEventListener('resize', () => { 304 clearTimeout(this.resizeTimeout) 305 306 this.resizeTimeout = setTimeout(() => { 307 this.initOverflow() 308 }, 150) 309 }) 310 }, 311 } 312 313 app.init() 314} 315 316if (typeof window !== 'undefined') { 317 window.addEventListener('ReactContentLoaded', TabsScript) 318 document.addEventListener('DOMContentLoaded', TabsScript) 319} 320
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.