1const TerminFilter = (function() { 2 let picker = null; 3 let fromField = null; 4 let toField = null; 5 let searchWord = ''; 6 let topics = ''; // 'thema' 7 let types = ''; // 'terminart 8 let host = null; // veranstalter 9 let initialHosts = '' // this is set from plugin'' 10 let range = 0; 11 let searchDebounceTimer; 12 let lastFoundEvents = document.querySelector('#lastFoundAppointments'); 13 // coutry und catlist kann glaub ich weg 14 let requestParams = { 15 type: 98877, 16 offset: 10, 17 limit: 10, 18 mode: 'append', 19 range: 0, 20 storagePids: '', 21 detuid: '', 22 catlist: '', 23 from: '', 24 to: '', 25 host: '', 26 country: null, 27 searchWord: '', 28 types: '', 29 topics: '' 30 } 31 32 function formatToIsoDate(date) { 33 const year = date.getFullYear(); 34 const month = String(date.getMonth() + 1).padStart(2, "0"); 35 const day = String(date.getDate()).padStart(2, "0"); 36 return `${year}-${month}-${day}`; 37 } 38 39 function initializeDatepicker() { 40 var curr = new Date(); 41 picker = new Litepicker({ 42 element: document.getElementById('datepicker'), 43 numberOfMonths: 2, 44 numberOfColumns: 2, 45 inlineMode: true, 46 format: 'YYYY-MM-DD', 47 lang: 'de-DE', 48 singleMode: false, 49 showTooltip: false, 50 minDate: curr, 51 minDate: '2024-01-01', 52 onSelect: function(date1, date2) { 53 fromField.value = formatToIsoDate(date1); 54 toField.value = formatToIsoDate(date2); 55 reload(); 56 } 57 }); 58 } 59 60 function setEventListeners() { 61 const rangeTimeselects = document.querySelectorAll('button.timeselect.range'); 62 const dateTimeselects = document.querySelectorAll('button.timeselect.date'); 63 const searchInput = document.getElementById('searchInput'); 64 const terminartInputs = document.querySelectorAll('input[name="type[]"]'); 65 const hostInputs = document.querySelectorAll('input[name="host"]'); 66 const topicInputs = document.querySelectorAll('input[name="topics[]"]');
67 const loadMore = document.getElementById('loadmore'); 68 const loadMoreButton = document.getElementById('loadtermine'); 69 const abroadInputs = document.querySelectorAll('input[name="countryfilter"]'); 70 71 if (abroadInputs.length > 0) { 72 abroadInputs.forEach((el) => { 73 el.addEventListener('change', function() { 74 if (el.checked) { 75 el.setAttribute('checked', 'checked'); 76 } else { 77 el.removeAttribute('checked'); 78 } 79 requestParams.country = el.value; 80 reload(); 81 }) 82 }) 83 } 84 85 // For radio buttons (where only one can be selected) 86 if (hostInputs.length > 0) { 87 // Initialize with any pre-selected value 88 hostInputs.forEach((el) => { 89 if (el.checked) { 90 requestParams.host = el.value; 91 } 92 }); 93 94 // Handle changes 95 hostInputs.forEach((el) => { 96 el.addEventListener('change', function() { 97 // For radio buttons, just set the value directly - no need for else case 98 // since only one can be checked at a time 99 requestParams.host = el.value; 100 reload(); 101 }); 102 }); 103 } 104 105 if ( terminartInputs.length > 0 ) { 106 let terminArtArray = []; 107 terminartInputs.forEach((el) => { 108 el.addEventListener('change', function() { 109 if(el.checked) { 110 el.setAttribute('checked', 'checked'); 111 terminArtArray.push(el.value); 112 } else { 113 el.removeAttribute('checked'); 114 terminArtArray = terminArtArray.filter((type) => type !== el.value); 115 } 116 types = terminArtArray.join(','); 117 reload(); 118 }); 119 }); 120 } 121 122 if ( topicInputs.length > 0 ) { 123 let topicArray = []; 124 topicInputs.forEach((el) => { 125 el.addEventListener('change', function() { 126 if(el.checked) { 127 el.setAttribute('checked', 'checked'); 128 topicArray.push(el.value); 129 } else { 130 el.removeAttribute('checked'); 131 topicArray = topicArray.filter((topic) => topic !== el.value); 132 } 133 topics = topicArray.join(','); 134 reload(); 135 }); 136 }); 137 } 138 139 searchInput.addEventListener('keyup', function(event) { 140 const searchValue = event.target.value; 141 filterSearchInput(searchValue); 142 }) 143 searchInput.addEventListener('search', function(event) { 144 searchWord = ''; 145 reload(); 146 }); 147 148 rangeTimeselects.forEach((el) => { 149 el.addEventListener('click', function(e) { 150 e.preventDefault(); 151 document.querySelectorAll('button.timeselect.range').forEach((el) => { 152 el.classList.remove('active'); 153 }) 154 if(el.classList.contains('active')) { 155 el.classList.remove('active'); 156 } 157 else { 158 el.classList.add('active'); 159 } 160 reload(); 161 }) 162 }); 163 164 dateTimeselects.forEach((el) => { 165 el.addEventListener('click', function(e) { 166 e.preventDefault(); 167 document.querySelectorAll('button.timeselect.date').forEach((el) => { 168 el.classList.remove('active'); 169 }) 170 if(el.classList.contains('active')) { 171 el.classList.remove('active'); 172 } else { 173 el.classList.add('active'); 174 } 175 const type = el.dataset.time; 176 switch (type) { 177 case 'today': 178 const today = new Date(); 179 picker.setDateRange(new Date(), new Date()); 180 picker.hide(); 181 break; 182 case 'week': 183 picker.clearSelection(); 184 // caclulate start and end of the current week 185 // week starts on monday and ends on sunday 186 const currentDate = new Date(); 187 const currentDay = currentDate.getDay(); 188 const daysTillMonday = currentDay === 0 ? -6 : 1 - currentDay; 189 const mondayThisWeek = new Date(currentDate) 190 mondayThisWeek.setDate(currentDate.getDate() + daysTillMonday); 191 const sundayThisWeek = new Date(mondayThisWeek); 192 sundayThisWeek.setDate(mondayThisWeek.getDate() + 6); 193 194 picker.setDateRange(mondayThisWeek, sundayThisWeek); 195 picker.hide(); 196 break; 197 case 'nextweek': 198 // caclulate start and end of the next week 199 // week starts on monday and ends on sunday 200 const baseDate = new Date(); 201 const baseDay = baseDate.getDay(); 202 const daysTillNextMonday = (baseDay === 0 ? -6 : 1 - baseDay) + 7; 203 const mondayNextWeek = new Date(baseDate); 204 mondayNextWeek.setDate(baseDate.getDate() + daysTillNextMonday); 205 const sundayNextWeek = new Date(mondayNextWeek); 206 sundayNextWeek.setDate(mondayNextWeek.getDate() + 6); 207 208 picker.setDateRange(mondayNextWeek, sundayNextWeek); 209 picker.hide(); 210 break; 211 case 'all': 212 let now = new Date().getTime(); 213 picker.clearSelection(); 214 picker.hide(); 215 fromField.value = ''; 216 toField.value = ''; 217 reload(); 218 break; 219 } 220 //reload(); 221 }) 222 }); 223 filterSearchInput = (value) => { 224 searchWord = value; 225 226 clearTimeout(searchDebounceTimer) 227 228 searchDebounceTimer = setTimeout(function() { 229 clearFiltersForSearch(); 230 resetAllFiltersInFrontend(); 231 picker.clearSelection(); 232 reload(); 233 }, 1300) 234 } 235 236 resetAllFiltersInFrontend = () => { 237 filters = [ 238 terminartInputs, 239 hostInputs, 240 topicInputs, 241 dateTimeselects, 242 rangeTimeselects 243 ]
244 filters.forEach((filterType) => { 245 filterType.forEach((filter) => { 246 const type = filter.getAttribute('type'); 247 248 if (type === 'checkbox') { 249 filter.checked = false; 250 } 251 else if (type === 'radio') { 252 filter.checked = false; 253 } 254 else if (type === null) { 255 filter.classList.remove('active'); 256 removeActiveStateInCalendar = true; 257 } 258 }) 259 }) 260 } 261 262 clearFiltersForSearch = () => { 263 topics = ''; 264 types = ''; 265 host = null; 266 range = 0; 267 fromField.value = ''; 268 toField.value = ''; 269 } 270 } 271 272 /** 273 * Filter search input 274 * Debounce the search input to avoid multiple requests 275 * 276 * If a search is triggered, all other filters will be cleared 277 */ 278 279 // function filterSearchInput(value) { 280 // searchWord = value; 281 282 283 // } 284 285 function reload() {
286 const loadMoreDiv = document.getElementById('loadmore'); 287 const params = { 288 type: 98877, 289 offset: 0, 290 limit: 10, 291 mode: 'replace', 292 range: 0, 293 storagePids: loadMoreDiv.dataset.storagePids || '', 294 detuid: loadMoreDiv.dataset.detuid || '', 295 catlist: loadMoreDiv.dataset.catlist || '', 296 from: fromField ? fromField.value : '', 297 to: toField ? toField.value: '', 298 host: requestParams.host ?? '', 299 country: requestParams.country ?? null, 300 searchWord: searchWord || '', 301 types: types || '', 302 topics: topics || '' 303 }; 304 305 $('button.timeselect.range').each(function (){ 306 if($(this).hasClass('active')) { 307 if($(this).data('range') != '0') params.range = $(this).data('range'); 308 } 309 }); 310 loadMore(params); 311 } 312 313 function loadMore(params) { 314 const loadingCircle = document.getElementById('loadingCircle') 315 loadingCircle.classList.remove('d-none'); 316 317 requestParams = {...requestParams, ...params}; 318 319 320 const urlParams = new URLSearchParams(); 321 322 Object.entries(requestParams).forEach(([key, value]) => { 323 if (value !== undefined && value !== null && value !== "undefined" && value !== "") { 324 urlParams.set(key, value); 325 } 326 }) 327 328 329 // base url 330 //var url = "/?type=98877&pos="+pos+"&num="+num+"&mode="+mode+"&range="+range+"&idlist="+idlist+"&detuid="+detuid; 331 if (lastFoundEvents) lastFoundEvents.remove(); 332 $.ajax({ 333 url: '/?'+ urlParams.toString(), 334 dataType: 'json' 335 }) 336 .fail(function(response) { 337 console.log('error' + JSON.stringify(response)); 338 }) 339 .done(function(response) { 340 const data = response.html; 341 const count = response.count; 342 343 if (requestParams.mode === 'replace') { 344 document.querySelectorAll('.event-card').forEach((el) => el.remove()); 345 requestParams.mode = 'append'; 346 } 347 348 if(data !== '###NOROWS###') {
349 const loadMore = document.getElementById('loadmore'); 350 if (loadMore) { 351 loadMore.insertAdjacentHTML('beforebegin', data); 352 } 353 354 // Ladeindikator entfernen 355 const loadingCircle = document.getElementById('loadingCircle'); 356 if (loadingCircle) { 357 loadingCircle.classList.add('d-none'); 358 } 359 360 const eventCards = document.querySelectorAll('.event-card'); 361 362 const nextOffset = requestParams.offset + requestParams.limit; 363 364 loadMoreButton = loadMore.querySelector('#loadtermine'); 365 if (count < requestParams.limit) { 366 loadMoreButton.removeAttribute('onclick'); 367 loadMoreButton.setAttribute('disabled', 'disabled'); 368 loadMoreButton.style.display = 'none'; 369 } else { 370 loadMoreButton.removeAttribute('disabled'); 371 loadMoreButton.style.display = ''; 372 loadMoreButton.textContent = 'Weitere Termine laden'; 373 loadMoreButton.setAttribute('onclick', 374 `javascript:TerminFilter.handleLoadMoreClick({ 375 offset: ${nextOffset}, 376 limit: 10, 377 mode: 'append' 378 })` 379 ); 380 } 381 382 } else {
383 const loadMore = document.getElementById('loadmore'); 384 const loadMoreButton = loadMore.querySelector('#loadtermine'); 385 const loadingCircle = document.getElementById('loadingCircle'); 386 loadMoreButton.removeAttribute('onclick'); 387 loadMoreButton.setAttribute('disabled', 'disabled'); 388 loadMoreButton.style.display = 'none'; 389 if (loadingCircle) { 390 loadingCircle.classList.add('d-none'); 391 } 392 } 393 }) 394 } 395 396 return { 397 init: function() { 398 document.addEventListener('DOMContentLoaded', function() { 399 fromField = document.querySelector('input#fromDate'); 400 toField = document.querySelector('input#toDate'); 401 402 if (document.querySelectorAll('.events').length) { 403 initializeDatepicker(); 404 setEventListeners(); 405 const loadMore = document.getElementById('loadmore'); 406 if (loadMore) { 407 requestParams = { 408 ...requestParams, 409 storagePids: loadMore.dataset.storagePids || '', 410 detuid: loadMore.dataset.detuid || '', 411 catlist: loadMore.dataset.catlist || '', 412 from: loadMore.dataset.from || '', 413 to: loadMore.dataset.to || '', 414 } 415 } 416 } 417 }) 418 }, 419 // initial load more call and after filtering 420 // nice to have: after filtering only show loadmore button if there are more than $numberPerPage events 421 handleLoadMoreClick: function(params) { 422 loadMore(params); 423 } 424 425 } 426})(); 427 428TerminFilter.init(); 429
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.