1let dpDialog, dpFilters; 2let regionSearchInitialized = false; 3 4document.addEventListener('DOMContentLoaded', () => { 5 console.log('TiogaTours v2'); 6 dpDialog = document.querySelector('#dp-selection'); 7 dpFilters = document.querySelectorAll('#dp-filter > input') 8 9 initRouteSearch(); 10 initPromoNotification(); 11 updateConsentStatus(); 12 13 if ((localStorage.getItem('showConsentBar') ?? 'true') === 'true') { 14 let cookieMsgContainer = document.createElement('div'); 15 16 document.body.append(cookieMsgContainer); 17 cookieMsgContainer.outerHTML = '<div class="hidden-print" id="consentBar" style="padding:10px 0 30px 0; text-align:center; background-color:rgba(250,250,250,0.97); color: black; position: sticky; bottom:0; font-size:130%; z-index:99999; box-shadow: 0 0 7px black; ">' + 18 '<h2>Cookie-voorkeuren</h2>' + 19 '<p style="font-size:80%;"><a href="/cookies/">Lees meer over onze cookies</a></p>' + 20 '<button style="color:#1a4466; padding:8px 14px; border:2px solid #1a4466; background-color:transparent;" onclick="updateConsentStatus(false, false, false, false); hideConsentBar();">Alles weigeren</button>' + 21 '<button style="color:white; padding:8px 14px; border:2px solid #1a4466; margin-left:30px; background-color:#1a4466;" onclick="updateConsentStatus(true, true, true, true); hideConsentBar();">Alles toestaan</button> ' + 22 '<button style="color:#1a4466; padding:8px 14px; border:2px solid #1a4466; margin-left:30px; background-color:transparent;" onclick="updateConsentStatus(false, false, false, true); hideConsentBar();">Analytisch toestaan</button> ' + 23 '</div>'; 24 } 25}); 26 27const normalizeString = (string) => { 28 if (string === '' || typeof string !== 'string') return ''; 29 return string.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, ''); 30} 31 32const initRouteSearch = () => { 33 const routeSelector = document.getElementById('route-selector'); 34 if (!routeSelector) { 35 return; 36 } 37 38 const input = document.getElementById('route-selector-check'); 39 const destinations = routeSelector.querySelectorAll('.rs-route-destinations > input.hidden'); 40 destinations.forEach(destination => { 41 destination.addEventListener('change', e => { 42 input.checked = false; 43 }); 44 }); 45 46 const labels = routeSelector.querySelectorAll('.btn-switch > label'); 47 labels.forEach(label => { 48 label.addEventListener('click', e => { 49 e.preventDefault(); 50 let switcher = document.getElementById(label.htmlFor); 51 switcher.checked = !switcher.checked; 52 }); 53 }); 54} 55 56const initDestinationPicker = () => { 57 let dp = document.querySelector('#dp-container'); 58 if (!dp) { 59 return; 60 } 61 62 dp.querySelector('#dp-list') 63 .insertAdjacentHTML('beforebegin', '<div class="count"></div>') 64 65 let dpButton = dp.querySelector('.dp-button'); 66 let dpQuery = dp.querySelector('.dp-query'); 67 let dpDialog = document.querySelector('#dp-selection'); 68 69 dpButton.addEventListener('click', () => { 70 toggleDestinationPicker(dp); 71 }); 72 73 dpQuery.addEventListener('click', () => { 74 toggleDestinationPicker(dp, true); 75 }, true); 76 77 dpQuery.addEventListener('input', () => { 78 destinationFilter(); 79 }, true); 80 81 dpFilters.forEach( 82 filter => filter.addEventListener('change', () => destinationFilter()) 83 ); 84 85 dpDialog.addEventListener('close', () => { 86 document.querySelector('#dp-container').prepend(document.querySelector('.dp-form')); 87 }); 88} 89 90const toggleDestinationPicker = (container, query) => { 91 if (!isTouch) dpDialog.style.top = (container.querySelector('.dp-button').getBoundingClientRect().top + window.scrollY - 20) + 'px'; 92 93 if (regions && !regionSearchInitialized) { 94 let destinations = dpDialog.querySelectorAll('li'); 95 destinations.forEach(destination => { 96 let idDestination = parseInt(destination.dataset.idDestination); 97 regions.forEach(region => { 98 if (region.id_destination_area === idDestination) { 99 ; 100 destination.dataset.search = region.search; 101 destination.dataset.destination = region.destination_search + ' ' 102 + destination.querySelector('h3').innerText; 103 return; 104 } 105 }); 106 }); 107 regionSearchInitialized = true; 108 } 109
110 if (!dpDialog.open || query) { 111 dpDialog.showModal(); 112 dpDialog.addEventListener('click', (e) => { 113 if (e.target === dpDialog) dpDialog.close() 114 }); 115 dpDialog.prepend(document.querySelector('.dp-form')); 116 dpDialog.querySelector('.dp-query').focus(); 117 destinationFilter(); 118 } else { 119 dpDialog.querySelector('.dp-query').value = ''; 120 dpDialog.close(); 121 } 122} 123 124 125const destinationFilter = () => { 126 const queryRegex = /\&f\[query\]=[^\&]*/; 127 let nothing = document.querySelector('#dp-selection ul li.nothing') 128 let queryInput = document.querySelector('.dp-query') 129 let countryFilter = document.querySelector('#dp-filter > input:checked'); 130 let query = queryInput ? normalizeString(queryInput.value) : ''; 131 let countryFilterOption = countryFilter ? countryFilter.value : ''; 132 let count = 0; 133 let foundInOtherCountryCount = 0; 134 let matches = []; 135 let inDestinationName = false; 136 let destinations = dpDialog.querySelectorAll('li'); 137 138 if (nothing) nothing.remove(); 139 140 destinations.forEach(destination => { 141 let matchContainer = destination.querySelector('.matches'); 142 if (!matchContainer) { 143 matchContainer = document.createElement('div'); 144 matchContainer.classList.add('matches'); 145 destination.appendChild(matchContainer); 146 } 147 matchContainer.innerHTML = ''; 148 destination.classList.remove('hidden'); 149 destination.classList.remove('foundInOtherCountry'); 150 destination.classList.remove('foundInFilter'); 151 152 let destinationValue = normalizeString(destination.dataset.destination); 153 let inFilter = false; 154 155 if (query.length > 2) { 156 let found = normalizeString(destination.dataset.search).includes(query); 157 let foundInDestinationName = destinationValue.includes(query); 158 159 if ((!found && !foundInDestinationName)) { 160 destination.classList.add('hidden'); 161 } else { 162 inFilter = true; 163 destination.classList.add('foundInFilter'); 164 } 165 166 if (found) { 167 let searchableText = destination.dataset.search.split(','); 168 let maxMatches = 5; 169 matches = []; 170 searchableText.forEach(searchableString => { 171 searchableString = searchableString.trim(); 172 if (matches.indexOf(searchableString) === -1 && normalizeString(searchableString).includes(query)) { 173 matches.push(searchableString); 174 } 175 }); 176 matches.forEach(match => { 177 if (maxMatches === 0) { 178 match = 'en meerâ¦'; 179 } 180 if (maxMatches < 0) { 181 return; 182 } 183 184 let matchValue = document.createElement('span'); 185 matchValue.innerText = match; 186 matchContainer.appendChild(matchValue); 187 maxMatches--; 188 }); 189 destination.querySelectorAll('.buttons a').forEach(a => { 190 a.href = a.href.replace(queryRegex, ''); 191 if (matches.length > 0) { 192 a.href += '&f[query]=' + query; 193 } 194 }); 195 } else if (foundInDestinationName) { 196 inDestinationName = true; 197 destination.querySelectorAll('.buttons a').forEach(a => { 198 a.href = a.href.replace(queryRegex, ''); 199 }); 200 } 201 } 202 203 if (countryFilterOption) { 204 let inCountryFilter = countryFilterOption.length ? destinationValue.includes(countryFilterOption) : true; 205 206 if (!inCountryFilter) { 207 destination.classList.add('hidden'); 208 } 209 if (inFilter) { 210 foundInOtherCountryCount++; 211 destination.classList.add('foundInOtherCountry'); 212 } 213 } 214 }); 215 216 count = dpDialog.querySelectorAll('li:not(.hidden)').length; 217 showCount(count); 218 219 console.log( count, foundInOtherCountryCount); 220 if (count === 0 && foundInOtherCountryCount !== 0) {
221 dpDialog.querySelectorAll('.foundInOtherCountry').forEach(destination => { 222 destination.classList.remove('hidden'); 223 }); 224 nothingFound(query, 225 `Gevonden, alleen valt deze bestemming nèt buiten je filters. ð <br /> 226 We laten hem je toch even zien:` 227 ); 228 } 229 230 231 if (!inDestinationName && query.length > 2 && count === 0 && foundInOtherCountryCount === 0) { 232 nothingFound(query); 233 } 234 235 if (query.length > 2) { 236 showCount(count); 237 } 238} 239 240const showCount = (count) => { 241 let message = ''; 242 if (count > 1) { 243 message = count + ' bestemmingen'; 244 } else if (count > 0) { 245 message = count + ' bestemming'; 246 } 247 document.querySelector('#dp-container .count').innerText = message; 248} 249 250const nothingFound = (query, message) => { 251 let nothing = document.createElement('li'); 252 let defaultMessage = 253 `Hmm, daar hebben we geen resultaten voor in onze routes.<br /> 254 Je kan hier zoeken op plaatsen en regio's<br /> 255 <br /> 256 <a href="/zoeken/?q=${query}">Je kan ook op de hele website zoeken naar "${query}".</a>`; 257 message = message ?? defaultMessage; 258 259 nothing.innerHTML = `<p style="grid-column-start: 1; grid-column-end: 3">${message}</p>`; 260 nothing.classList.add('nothing'); 261 document.querySelector('#dp-selection ul').prepend(nothing); 262 263} 264 265const initPromoNotification = () => { 266 267 let container = document.getElementById('promo-notifications'); 268 let balloons = Array.from(container?.querySelectorAll('.variant') ?? []); 269 let banner = Array.from(document.querySelectorAll('.banner-container') ?? []); 270 271 let variants = [], 272 pickedVariant, 273 closeEl = document.createElement('a'), 274 storage = storageAvailable('localStorage') ? localStorage : null, 275 hiddenBalloons = storage && storage.getItem('promo-notification-hidden') && JSON.parse(storage.getItem('promo-notification-hidden')) || []; 276 277 closeEl.innerHTML = '×'; 278 closeEl.classList.add('close'); 279 closeEl.href = 'javascript: void null'; 280 281 if ( 282 balloons.length === 0 || 283 document.getElementById('map') || 284 (banner.length === 0 && document.location.pathname !== "/") 285 ) { 286 return; 287 } 288 289 balloons.forEach(t => { 290 291 let num = t.getAttribute('data-chance') ? parseInt(t.getAttribute('data-chance')) : 1, 292 now = new Date().getTime(), 293 valid = ( 294 t.getAttribute('data-valid-from') ? new Date(t.getAttribute('data-valid-from')).getTime() < now : true 295 ) && ( 296 t.getAttribute('data-valid-till') ? new Date(t.getAttribute('data-valid-till')).getTime() > now : true 297 ), 298 i = 0; 299 300 if (hiddenBalloons.indexOf(t.innerText.trim()) !== -1) { 301 return; 302 } 303 304 if (valid === true) { 305 for (i; i < num; i++) { 306 variants.push(t); 307 } 308 } 309 }); 310 311 if (variants.length === 0) { 312 return; 313 } 314 315 pickedVariant = variants[Math.floor(Math.random() * variants.length)]; 316 pickedVariant.prepend(closeEl); 317 318 closeEl.addEventListener('click', e => { 319 let variant = e.currentTarget.parentElement; 320 variant.classList.remove('active'); 321 e.currentTarget.remove(); 322 hiddenBalloons.push(pickedVariant.innerText.trim()); 323 if (storage) { 324 storage.setItem('promo-notification-hidden', JSON.stringify(hiddenBalloons)); 325 } 326 }); 327 328 pickedVariant.classList.add('active'); 329} 330 331const storageAvailable = (type) => { 332 try { 333 var storage = window[type], 334 x = '__storage_test__'; 335 storage.setItem(x, x); 336 storage.removeItem(x); 337 return true; 338 } catch (e) { 339 return false; 340 } 341} 342 343function updateConsentStatus(ad_user_data, ad_personalization, ad_storage, analytics_storage) { 344 const localStatus = JSON.parse(localStorage.getItem('consentStatus') ?? '{}'); 345 const consentStatus = { 346 ad_user_data: ad_user_data ?? ((localStatus.ad_user_data ?? 'denied') === 'granted') ? 'granted' : 'denied', 347 ad_personalization: ad_personalization ?? ((localStatus.ad_personalization ?? 'denied') === 'granted') ? 'granted' : 'denied', 348 ad_storage: ad_storage ?? ((localStatus.ad_storage ?? 'denied') === 'granted') ? 'granted' : 'denied', 349 analytics_storage: analytics_storage ?? ((localStatus.analytics_storage ?? 'denied') === 'granted') ? 'granted' : 'denied', 350 }; 351 352 localStorage.setItem('consentStatus', JSON.stringify(consentStatus)); 353 354 if (window.gtag) gtag('consent', 'update', consentStatus); 355 if (window.fbq) fbq('consent', ad_storage ?? ((localStatus.ad_storage ?? 'denied') === 'granted') ? 'grant' : 'revoke'); 356} 357 358function hideConsentBar() { 359 localStorage.setItem('showConsentBar', 'false'); 360 const consentBar = document.getElementById('consentBar'); 361 consentBar.parentNode.removeChild(consentBar); 362}
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.