1var $toggleTrigger = $('[data-toggle_trigger]'), 2 $toggleContent = $('[data-toggle_content]'), 3 toggleTriggerCounter = 0, 4 $win = $(window), 5 $tpForm, 6 $tpFormOffset, 7 $tpFomrBottomPos, 8 $tpMap = $('.tp_map'), 9 $mapToggle = $('.map_expand'), 10 scrollPos = $win.scrollTop(); 11 12if ($('.tp_sidebar').length) { 13 $tpForm = $('.tp_sidebar'); 14 $tpFormOffset = $tpForm.length ? $tpForm.offset().top : null; 15 $tpFomrBottomPos = $tpForm.length ? $tpForm.offset().top + $tpForm.outerHeight(true) : null; 16} 17 18$win.on('resize', function () { 19 moveSaLink(); 20}); 21 22$win.on('scroll', function () { 23 scrollPos = $win.scrollTop(); 24 if ($tpFormOffset <= scrollPos) { 25 $mapToggle.addClass('showB'); 26 } else { 27 $mapToggle.removeClass('showB'); 28 $tpMap.removeClass('show') 29 } 30}); 31 32$mapToggle.on('click', function () { 33 $tpMap.toggleClass('show'); 34}); 35 36$toggleTrigger.each(function () { 37 var $this = $(this), 38 targetData = $this.data('toggle_trigger'), 39 triggerText = $.trim($this.text()).replace(/\s/g, '') + toggleTriggerCounter, 40 $target = $("[data-toggle_content='" + targetData + "']"); 41 42 // Ensure non-button elements behave like buttons 43 if (!$this.is('button')) { 44 $this.attr({ 45 'role': 'button', 46 'tabindex': '0' 47 }); 48 } 49 50 $this.on('click', function (e) { 51 e.stopPropagation(); // Prevent bubbling to document 52 53 let isNested = $this.closest('[data-toggle_content].open').length > 0; 54 55 if (!$target.hasClass('open')) { 56 // Alert togglers do not close any other open accordions 57 if (!$target.hasClass('alert_toggled')) { 58 // Close other accordions only if the clicked one is not nested 59 if (!isNested) { 60 $toggleTrigger.attr('aria-expanded', 'false').parent().removeClass('open'); 61 $toggleContent.removeClass('open') 62 .attr('aria-hidden', 'true') 63 .slideUp(250); 64 } 65 } 66 67 if ($target.hasClass('_grid')) { 68 $target.addClass('open') 69 .attr('aria-hidden', 'false') 70 .slideDown({ 71 start: function () { 72 $(this).css({ 73 display: "flex" 74 }) 75 } 76 }); 77 78 } else { 79 $target.addClass('open') 80 .attr('aria-hidden', 'false') 81 .slideDown(250); 82 } 83 84 // Open the clicked toggle 85 $this.attr('aria-expanded', 'true').parent().addClass('open'); 86 $target.addClass('open'); 87 //positionDropdown(); 88 $target.attr('aria-hidden', 'false') 89 .slideDown(250); 90 91 } else { 92 // Close the current toggle 93 $this.attr('aria-expanded', 'false').parent().removeClass('open'); 94 $target.removeClass('open') 95 .attr('aria-hidden', 'true') 96 .slideUp(250); 97 98 } 99 }); 100 101 // Set roles for accessibility 102 $this.parent().attr('role', 'presentation'); 103 104 // Add accessibility attributes to trigger 105 $this.attr({ 106 'aria-expanded': 'false', 107 'id': triggerText, 108 'aria-controls': 'ctrl-' + triggerText, 109 'type': 'button' 110 }); 111 112 // Add accessibility attributes to content 113 $target.attr({ 114 'id': $this.attr('aria-controls'), 115 'role': 'region', 116 'aria-labelledby': $this.attr('id'), 117 'aria-hidden': 'true' 118 }); 119 120 $(document).click(function (e) { 121 var $clickTarget = $(e.target); 122 123 // Ignore clicks inside the current trigger or its content panel. 124 if ($clickTarget.closest($this).length || $clickTarget.closest($target).length) { 125 return; 126 } 127 128 if ($target.is('.route_dd_list, .ru_toggle_item')) { 129 $this.attr('aria-expanded', 'false').parent().removeClass('open'); 130 $target.removeClass('open') 131 .attr('aria-hidden', 'true') 132 .slideUp(250); 133 } 134 }); 135 136 toggleTriggerCounter++; 137}); 138 139// Open only the first trip accordion on load 140var $firstTripItem = $('.trip_item').first(); 141if ($firstTripItem.length) { 142 var $firstTrigger = $firstTripItem.find('[data-toggle_trigger]').first(), 143 firstTargetData = $firstTrigger.data('toggle_trigger'), 144 $firstTarget = $firstTripItem 145 .find("[data-toggle_content='" + firstTargetData + "']") 146 .first(); 147 148 if ($firstTrigger.length && $firstTarget.length) { 149 $firstTrigger 150 .attr('aria-expanded', 'true') 151 .parent() 152 .addClass('open'); 153 154 $firstTarget 155 .removeAttr('hidden') 156 .addClass('open') 157 .attr('aria-hidden', 'false'); 158 159 if ($firstTarget.hasClass('_grid')) { 160 $firstTarget.css('display', 'flex'); 161 } else { 162 $firstTarget.show(); 163 } 164 } 165} 166 167 168$('.exp_slider').slack({ 169 variableWidth: false, 170 slidesToShow: 1, 171 dots: false 172}); 173 174$('.s4_notif').slick({ 175 dots: false, 176 arrows: true, 177 infinite: true 178}); 179
180var $saLink = $('.sa_link'), 181 $saCount = $('.sa_count'), 182 $logo = $('#logo'), 183 headerHeight = $logo.outerHeight(true); 184 185function moveSaLink() { 186 if ($('#burgerNavStyle').css("display") === "block") { 187 headerHeight = $logo.outerHeight(true); 188 $saLink.show().css({ 189 'padding': 0, 190 'position': 'absolute', 191 'top': 0, 192 'width': 'auto', 193 'right': 65 + 'px', 194 'height': headerHeight + 'px', 195 'display': 'flex', 196 'flex-direction': 'column', 197 'justify-content': 'center' 198 }).addClass('with_burg').insertBefore('#burgerNavStyle'); 199 } else { 200 $saLink.removeAttr('style').removeClass('with_burg').appendTo('.sa_link_wrap'); 201 } 202}; 203moveSaLink(); 204 205 206$(function () { 207 var $window = $(window); 208 var $header = $('#site-header'); 209 var $originalWrap = $('.service_buttons_wrap'); 210 var $stickyToggle = $('.sticky_service_toggle'); 211 var $stickyButton = $stickyToggle.find('.service_buttons_toggle'); 212 var $stickyListContainer = $stickyToggle.find('.service_buttons_list'); 213 214 // Clone the original button list content into the sticky one 215 var $clonedList = $originalWrap.find('.service_buttons_list').clone(true, true); 216 $clonedList.removeAttr('hidden'); // Remove hidden attr since we'll use class-based visibility 217 $clonedList.removeAttr('id'); // Remove duplicate ID if necessary 218 $stickyListContainer.replaceWith($clonedList); 219 220 // Reassign the variable after replacement 221 $stickyListContainer = $stickyToggle.find('.service_buttons_list'); 222 223 // Scroll check to determine when to show sticky toggle 224 function checkVisibility() { 225 var headerHeight = $header.outerHeight(); 226 var wrapTop = $originalWrap.offset() ? $originalWrap.offset().top : 0; 227 var wrapBottom = wrapTop + $originalWrap.outerHeight(); 228 var scrollTop = $window.scrollTop(); 229 230 // If we've scrolled past the bottom of the original button block (with header offset) 231 if (scrollTop + headerHeight >= wrapBottom) { 232 $stickyToggle.attr('aria-hidden', 'false'); 233 } else { 234 $stickyToggle.attr('aria-hidden', 'true'); 235 $stickyButton.attr('aria-expanded', 'false'); 236 $stickyListContainer.removeClass('show'); 237 } 238 } 239 240 // Toggle the buttons panel when clicking the toggle button 241 $stickyButton.on('click', function () { 242 var isExpanded = $(this).attr('aria-expanded') === 'true'; 243 var $list = $stickyToggle.find('.service_buttons_list'); 244 245 $(this).attr('aria-expanded', String(!isExpanded)); 246 247 if (!isExpanded) { 248 // Opening: add show class to trigger CSS transition 249 $list.addClass('show'); 250 } else { 251 // Closing: remove show class 252 $list.removeClass('show'); 253 } 254 }); 255 256 $(document).on('click', function (e) { 257 var $target = $(e.target); 258 var isInside = $target.closest('.sticky_service_toggle').length > 0; 259 260 if (!isInside) { 261 var isExpanded = $stickyButton.attr('aria-expanded') === 'true'; 262 263 if (isExpanded) { 264 $stickyButton.attr('aria-expanded', 'false'); 265 $stickyListContainer.removeClass('show'); 266 } 267 } 268 }); 269 // Run scroll check on page load and scroll/resize 270 $window.on('scroll resize', checkVisibility); 271 checkVisibility(); 272}); 273 274const $el = $('.firstRow_pod [data-slick]'); // adjust selector as needed 275 276document.querySelectorAll('.wrap-slash').forEach(el => { 277 el.innerHTML = el.textContent.replace(/\//g, '/<wbr>'); 278}); 279 280// --- Timetable sticky first-column top scrollbar sync --- 281(function () { 282 function initTtScrollSync(tripTable) { 283 var scroller = tripTable.querySelector('.table_scroller'); 284 var scrollerTop = tripTable.querySelector('.table_scroller_top'); 285 var scrollerTopInner = tripTable.querySelector('.table_scroller_top_inner'); 286 var table = tripTable.querySelector('.tt_actual'); 287 if (!scroller || !scrollerTop || !scrollerTopInner || !table) return; 288 if (scroller._ttSyncInit) return; 289 scroller._ttSyncInit = true; 290 291 function syncWidth() { 292 scrollerTopInner.style.width = table.scrollWidth + 'px'; 293 } 294 syncWidth(); 295 296 var syncing = false;
297 scroller.addEventListener('scroll', function () { 298 if (!syncing) { syncing = true; scrollerTop.scrollLeft = scroller.scrollLeft; syncing = false; } 299 }); 300 scrollerTop.addEventListener('scroll', function () { 301 if (!syncing) { syncing = true; scroller.scrollLeft = scrollerTop.scrollLeft; syncing = false; } 302 }); 303 304 new ResizeObserver(syncWidth).observe(table); 305 } 306 307 // Init any trip_table already visible on load (first-opened accordions) 308 document.querySelectorAll('.trip_table').forEach(function (tt) { 309 if (tt.offsetParent !== null) { 310 initTtScrollSync(tt); 311 } 312 }); 313 314 // Watch for trip_tables that become visible when accordions are opened 315 var observer = new MutationObserver(function (mutations) { 316 mutations.forEach(function (m) { 317 var tt = m.target; 318 if (tt.classList && tt.classList.contains('trip_table') && tt.style.display !== 'none' && tt.style.display !== '') { 319 initTtScrollSync(tt); 320 } 321 }); 322 }); 323 document.querySelectorAll('.trip_table').forEach(function (tt) { 324 observer.observe(tt, { attributes: true, attributeFilter: ['style'] }); 325 }); 326}());
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.