1function toggleFilters() { 2 //none or flex 3 const filtersContainer = document.getElementById('filters_container'); 4 const toggleButtonContainer = document.getElementsByClassName('filters__mobile_button')[0]; 5 const toggleButtons = document.querySelectorAll('.filters__mobile_button__toggle'); 6 const applyButtons = document.querySelectorAll('.filters__mobile_button__apply'); 7 8 if (filtersContainer.style.display === 'none' || filtersContainer.style.display === '') { 9 // Show filters 10 filtersContainer.style.display = 'flex'; 11 toggleButtonContainer.style.position = 'fixed'; 12 // Hide toggle buttons 13 toggleButtons.forEach(button => button.style.display = 'none'); 14 // Show apply buttons 15 applyButtons.forEach(button => button.style.display = 'flex'); 16 } 17 else { 18 // Hide filters 19 filtersContainer.style.display = 'none'; 20 toggleButtonContainer.style.position = 'absolute'; 21 // Show toggle buttons 22 toggleButtons.forEach(button => button.style.display = 'flex'); 23 // Hide apply buttons 24 applyButtons.forEach(button => button.style.display = 'none'); 25 } 26} 27 28 29function clearFilters() { 30 window.store.dispatch(window.searchResultsActions.resetFilters()); 31 //initDefaultFilters(); 32 initFilters(); 33 constructReservationTiles(); 34 console.log('All filters cleared'); 35} 36 37function clearSort() { 38 window.store.dispatch(window.searchResultsActions.resetFilters()); 39 initSortBar(); 40 console.log('Sort cleared'); 41} 42 43function toggleSort() { 44 //none or flex 45 const filtersContainer = document.getElementById('sort_container'); 46 const toggleButtonContainer = document.getElementsByClassName('filters__mobile_button')[0]; 47 const toggleButtons = document.querySelectorAll('.filters__mobile_button__toggle'); 48 const applyButtons = document.querySelectorAll('.filters__mobile_button__sort_apply'); 49 50 if (filtersContainer.style.display === 'none' || filtersContainer.style.display === '') { 51 // Show filters 52 filtersContainer.style.display = 'flex'; 53 toggleButtonContainer.style.position = 'fixed'; 54 // Hide toggle buttons 55 toggleButtons.forEach(button => button.style.display = 'none'); 56 // Show apply buttons 57 applyButtons.forEach(button => button.style.display = 'flex'); 58 } 59 else { 60 // Hide filters 61 filtersContainer.style.display = 'none'; 62 toggleButtonContainer.style.position = 'absolute'; 63 // Show toggle buttons 64 toggleButtons.forEach(button => button.style.display = 'flex'); 65 // Hide apply buttons 66 applyButtons.forEach(button => button.style.display = 'none'); 67 } 68} 69 70function initDefaultFilters() { 71 const state = window.store?.getState(); 72 if (!state) return; 73 const { filters } = state.searchResults; 74 const departFilterList = document.querySelectorAll('.filter-checkbox.depart'); 75 departFilterList.forEach(filter => { 76 if (filter.value === filters.depart.from + '-' + filters.depart.to) { 77 filter.checked = true; 78 } else { 79 filter.checked = false; 80 } 81 }); 82 const arrivalFilterList = document.querySelectorAll('.filter-checkbox.arrival'); 83 arrivalFilterList.forEach(filter => { 84 if (filter.value === filters.arrival.from + '-' + filters.arrival.to) { 85 filter.checked = true; 86 } else { 87 filter.checked = false; 88 } 89 }); 90 const busTypeFilterList = document.querySelectorAll('.filter-checkbox.busType'); 91 busTypeFilterList.forEach(filter => { 92 if (filters.busTypes.includes(filter.value)) { 93 filter.checked = true; 94 } else { 95 filter.checked = false; 96 } 97 }); 98} 99 100function handleTimeFilterChange(e) { 101 const value = e.value; 102 const type = e.getAttribute('filter-type') || 'arrival'; 103 const timeRange = value.split('-'); 104 const filterList = document.querySelectorAll(`.filter-checkbox.${type}`); 105 startLoading('.searchResults_container'); 106 filterList.forEach(filter => { 107 if (filter.value === value) { 108 if (filter.checked == false) { 109 window.store.dispatch(window.searchResultsActions.setFilterRange({ 110 [type]: { 111 from: "00:00", 112 to: "24:00" 113 } 114 })); 115 return false;
116 } 117 filter.checked = true; 118 console.log(`Filter changed: ${value}, Type: ${type}`); 119 window.store.dispatch(window.searchResultsActions.setFilterRange({ 120 [type]: { 121 from: timeRange[0], 122 to: timeRange[1] 123 } 124 })); 125 } else { 126 filter.checked = false; 127 } 128 }); 129 constructReservationTiles(); 130} 131 132function handleBusFilterChange(e) { 133 startLoading('.searchResults_container'); 134 const state = window.store?.getState(); 135 if (!state) return; 136 const { 137 init: { 138 isReturnService, isRoundtripJourney 139 }, 140 searchResults: { 141 filters: onWardFilters, 142 returnJourney: { 143 filters: returnFilters, 144 }, 145 }, 146 } = state; 147 const filters = isReturnService && isRoundtripJourney ? returnFilters : onWardFilters; 148 const busTypes = filters.busTypes || []; 149 const value = e.value; 150 if (busTypes.includes(value)) { 151 e.checked = false; 152 } 153 window.store.dispatch(window.searchResultsActions.setBusTypeFilter(e.value)); 154 constructReservationTiles(); 155} 156 157function handleBoardingPointChange(e) { 158 startLoading('.searchResults_container'); 159 const state = window.store?.getState(); 160 if (!state) return; 161 const { 162 init: { 163 isReturnService, isRoundtripJourney 164 }, 165 searchResults: { 166 filters: onWardFilters, 167 returnJourney: { 168 filters: returnFilters, 169 }, 170 }, 171 } = state; 172 const filters = isReturnService && isRoundtripJourney ? returnFilters : onWardFilters; 173 const boardingPoints = filters.boardingPoints || []; 174 const value = e.value; 175 if (boardingPoints.includes(value)) { 176 e.checked = false; 177 } 178 window.store.dispatch(window.searchResultsActions.setBoardingFilter(e.value)); 179 constructReservationTiles(); 180} 181 182function handleDroppingPointChange(e) { 183 startLoading('.searchResults_container'); 184 const state = window.store?.getState(); 185 if (!state) return; 186 const { 187 init: { 188 isReturnService, isRoundtripJourney 189 }, 190 searchResults: { 191 filters: onWardFilters, 192 returnJourney: { 193 filters: returnFilters, 194 }, 195 }, 196 } = state; 197 const filters = isReturnService && isRoundtripJourney ? returnFilters : onWardFilters; 198 const droppingPoints = filters.droppingPoints || []; 199 const value = e.value; 200 if (droppingPoints.includes(value)) { 201 e.checked = false; 202 } 203 window.store.dispatch(window.searchResultsActions.setDroppingFilter(e.value)); 204 constructReservationTiles(); 205} 206 207function initFilters() { 208 const state = window.store?.getState(); 209 if (!state) return; 210 const { 211 searchResults: { 212 filters: onWardFilters, 213 boarding_stages: boardingStages, 214 dropoff_stages: droppingStages, 215 returnJourney: { 216 filters: returnFilters, 217 boarding_stages: returnBoardingStages, 218 dropoff_stages: ReturnDroppingStages, 219 }, 220 bimaSearchResults: { bima_reservations }, 221 }, 222 } = state; 223 const { isReturnService, isRoundtripJourney } = state.init; 224 const filters = isReturnService && isRoundtripJourney ? returnFilters : onWardFilters; 225 if (!filters) return; 226 const selectedArrivalValue = `${filters.arrival.from}-${filters.arrival.to}`; 227 const selectedDepartureValue = `${filters.depart.from}-${filters.depart.to}`; 228 const selectedBusTypes = filters.busTypes || []; 229 const selectedBoardingPoints = filters.boardingPoints || []; 230 const selectedDroppingPoints = filters.droppingPoints || []; 231 const boardingPoints = isReturnService && isRoundtripJourney ? returnBoardingStages : boardingStages; 232 const droppingPoints = isReturnService && isRoundtripJourney ? ReturnDroppingStages : droppingStages; 233 234 const boardingContainer = document.getElementById('boardingPointFilter'); 235 const droppingContainer = document.getElementById('droppingPointFilter'); 236 const className = boardingContainer.className 237 // remove all the filters_1__content__option from the above containers except the first child 238 boardingContainer.querySelectorAll(`.${className}__option`).forEach((child, index) => { 239 boardingContainer.removeChild(child); 240 }); 241 droppingContainer.querySelectorAll(`.${className}__option`).forEach((child, index) => { 242 droppingContainer.removeChild(child); 243 }); 244
245 boardingPoints.forEach(point => { 246 if (point[1] == -1 || point[1] == '-1') return; 247 let html = ''; 248 html += ` <div class="${className}__option">` 249 html += ` <input type="checkbox" id="boardingPoints_${point[1]}" name="boardingPoint" onchange="handleBoardingPointChange(this)" class="filter-checkbox boarding" value="${point[0]}" data-label="${point[1]}"/>` 250 html += ` <label for="boardingPoints_${point[1]}">${point[0]}</label>` 251 html += ` <span class="filters_1__count">(0)</span>` 252 html += ` </div>` 253 boardingContainer.insertAdjacentHTML('beforeend', html); 254 html = ''; 255 }); 256 257 droppingPoints.forEach(point => { 258 if (point[1] == -1 || point[1] == '-1') return; 259 let html = ''; 260 html += ` <div class="${className}__option">` 261 html += ` <input type="checkbox" id="droppingPoints_${point[1]}" name="droppingPoint" onchange="handleDroppingPointChange(this)" class="filter-checkbox dropping" value="${point[0]}" data-label="${point[1]}"/>` 262 html += ` <label for="droppingPoints_${point[1]}">${point[0]}</label>` 263 html += ` <span class="filters_1__count">(0)</span>` 264 html += ` </div>` 265 droppingContainer.insertAdjacentHTML('beforeend', html); 266 html = ''; 267 }); 268 269 document.querySelectorAll('[name="departureTime"]').forEach(e => { 270 if (e.value === selectedDepartureValue) { 271 e.checked = true; 272 } else { 273 e.checked = false; 274 } 275 }); 276 277 //boardingPoint 278 document.querySelectorAll('[name="boardingPoint"]')?.forEach(e => { 279 if (selectedBoardingPoints.includes(e.value)) { 280 e.checked = true; 281 } else { 282 e.checked = false; 283 } 284 }); 285 286 //droppingPoint 287 document.querySelectorAll('[name="droppingPoint"]')?.forEach(e => { 288 if (selectedDroppingPoints.includes(e.value)) { 289 e.checked = true; 290 } else { 291 e.checked = false; 292 } 293 }); 294 295 //arrivalTime 296 document.querySelectorAll('[name="arrivalTime"]').forEach(e => { 297 if (e.value === selectedArrivalValue) { 298 e.checked = true; 299 } else { 300 e.checked = false; 301 } 302 }); 303 304 305 //busType 306 document.querySelectorAll('[name="busType"]').forEach(e => { 307 if (selectedBusTypes.includes(e.value)) { 308 e.checked = true; 309 } else { 310 e.checked = false; 311 } 312 }); 313 314 315 316 // init VirtualSelect for departureTime 317 let departureTime_filter_dropdown = document.getElementById('departureTime_filter'); 318 if (departureTime_filter_dropdown) { 319 VirtualSelect.init({ 320 ele: departureTime_filter_dropdown, 321 noOptionsText: 'No options found', 322 hideClearButton: true, 323 popupDropboxBreakpoint: '200px', 324 }); 325 } 326 327 // init VirtualSelect for boardingPoint_filter 328 let boardingPoint_filter_dropdown = document.getElementById('boardingPoint_filter'); 329 if (boardingPoint_filter_dropdown) { 330 VirtualSelect.init({ 331 ele: boardingPoint_filter_dropdown, 332 noOptionsText: 'No options found', 333 hideClearButton: true, 334 multiple: true, 335 popupDropboxBreakpoint: '200px', 336 }); 337 } 338 339 // init VirtualSelect for droppingPoint_filter 340 let droppingPoint_filter_dropdown = document.getElementById('droppingPoint_filter'); 341 if (droppingPoint_filter_dropdown) { 342 VirtualSelect.init({ 343 ele: droppingPoint_filter_dropdown, 344 noOptionsText: 'No options found', 345 hideClearButton: true, 346 multiple: true, 347 popupDropboxBreakpoint: '200px', 348 }); 349 } 350 351 // init VirtualSelect for arrivalTime_filter 352 let arrivalTime_filter_dropdown = document.getElementById('arrivalTime_filter'); 353 if (arrivalTime_filter_dropdown) { 354 VirtualSelect.init({
355 ele: arrivalTime_filter_dropdown, 356 noOptionsText: 'No options found', 357 hideClearButton: true, 358 popupDropboxBreakpoint: '200px', 359 }); 360 } 361 362 // init VirtualSelect for busType_filter 363 let busType_filter_dropdown = document.getElementById('busType_filter'); 364 if (busType_filter_dropdown) { 365 VirtualSelect.init({ 366 ele: busType_filter_dropdown, 367 noOptionsText: 'No options found', 368 hideClearButton: true, 369 multiple: true, 370 popupDropboxBreakpoint: '200px', 371 }); 372 } 373 374 departureTime_filter_dropdown = document.getElementById('departureTime_filter'); 375 boardingPoint_filter_dropdown = document.getElementById('boardingPoint_filter'); 376 droppingPoint_filter_dropdown = document.getElementById('droppingPoint_filter'); 377 arrivalTime_filter_dropdown = document.getElementById('arrivalTime_filter'); 378 busType_filter_dropdown = document.getElementById('busType_filter'); 379 380 departureTime_filter_dropdown?.setValue(selectedDepartureValue || '00:00-24:00'); 381 boardingPoint_filter_dropdown?.setValue(filters.boardingPoints || []); 382 droppingPoint_filter_dropdown?.setValue(filters.droppingPoints || []); 383 arrivalTime_filter_dropdown?.setValue(selectedArrivalValue || '00:00-24:00'); 384 busType_filter_dropdown?.setValue(filters.busTypes || []); 385 initFilterCount(); 386} 387 388function sortServices(sortType) { 389 desktopSortServices(sortType); 390 // const className = document.querySelector('#sort_container').className; 391 // const mobileSortBarItems = document.querySelectorAll(`.${className}__content__option.sort_option`); 392 // mobileSortBarItems.forEach(item => { 393 // const radio = item.querySelector('input[type="radio"]'); 394 // const icon = item.querySelector('img.sort_bar_item_icon'); 395 // if (radio.id === sortType) { 396 // radio.checked = true; 397 // icon.src = `${window.domain}/common/assets/images/${filters.order === 'ASC' ? 'upArrow' : 'downArrow'}.svg`; 398 // } else { 399 // radio.checked = false; 400 // icon.src = `${window.domain}/common/assets/images/sortBarIcon.svg`; 401 // } 402 // }); 403 window.store.dispatch(window.searchResultsActions.sortBy(sortType)); 404 constructReservationTiles(); 405} 406 407function desktopSortServices(sortType) { 408 const state = window.store?.getState(); 409 if (!state) return; 410 const { filters } = state.searchResults; 411 const sortBarItems = document.querySelectorAll('.sort_bar_item'); 412 sortBarItems.forEach(item => { 413 if (item.id === sortType) { 414 // add class active 415 // toggle between ASC and DESC 416 // default is DESC on first click 417 if (item.classList.contains('active')) { 418 if (item.classList.contains('ASC')) { 419 item.classList.remove('ASC'); 420 item.classList.add('DESC'); 421 item.querySelector('img.sort_bar_item_icon').src = `${window.domain}/common/assets/images/upArrow.svg`; 422 } else { 423 item.classList.remove('DESC'); 424 item.classList.add('ASC'); 425 item.querySelector('img.sort_bar_item_icon').src = `${window.domain}/common/assets/images/downArrow.svg`; 426 } 427 } else { 428 // set to ASC by default 429 item.classList.add('active', 'DESC'); 430 item.querySelector('img.sort_bar_item_icon').src = `${window.domain}/common/assets/images/upArrow.svg`; 431 } 432 } else { 433 item.querySelector('img.sort_bar_item_icon').src = `${window.domain}/common/assets/images/sortBarIcon.svg`; 434 item.classList.remove('active', 'ASC', 'DESC'); 435 } 436 }); 437} 438 439function mobileSortServices(sortType) { 440 const state = window.store?.getState(); 441 if (!state) return; 442 const className = document.querySelector('#sort_container').className; 443 const mobileSortBarItems = document.querySelectorAll(`.${className}__content__option.sort_option`); 444 mobileSortBarItems.forEach(item => { 445 const radio = item.querySelector('input[type="radio"]'); 446 if (radio.id === sortType) { 447 radio.checked = true; 448 } else { 449 radio.checked = false; 450 } 451 }); 452 const sortTypeValues = sortType.split('_'); 453 desktopSortServices(sortTypeValues[0]); 454 window.store.dispatch(window.searchResultsActions.sortByOrder(sortTypeValues[0], sortTypeValues[1])); 455 constructReservationTiles(); 456} 457 458function initSortBar() { 459 const state = window.store?.getState(); 460 if (!state) return; 461 const { filters } = state.searchResults; 462 const sortBarItems = document.querySelectorAll('.sort_bar_item');
463 sortBarItems.forEach(item => { 464 if (item.id === filters.sortedColumn) { 465 item.classList.add('active', filters.order); 466 item.querySelector('img.sort_bar_item_icon').src = `${window.domain}/common/assets/images/${filters.order === 'ASC' ? 'downArrow' : 'upArrow'}.svg`; 467 } else { 468 item.classList.remove('active', 'ASC', 'DESC'); 469 item.querySelector('img.sort_bar_item_icon').src = `${window.domain}/common/assets/images/sortBarIcon.svg`; 470 } 471 }); 472 const className = document.querySelector('#sort_container').className; 473 const mobileSortBarItems = document.querySelectorAll(`.${className}__content__option.sort_option`); 474 mobileSortBarItems.forEach(item => { 475 const radio = item.querySelector('input[type="radio"]'); 476 if (radio.id === `${filters.sortedColumn}_${filters.order}`) { 477 radio.checked = true; 478 } else { 479 radio.checked = false; 480 } 481 }); 482} 483 484function initFilterCount() { 485 const state = window.store?.getState(); 486 if (!state) return; 487 const { reservations, returnJourney } = state.searchResults; 488 const { isReturnService, isRoundtripJourney } = state.init; 489 const tripReservations = isReturnService && isRoundtripJourney ? returnJourney.reservations : reservations; 490 const defaultFilter = { 491 depart: { 492 from: "00:00", 493 to: "24:00", 494 }, 495 arrival: { 496 from: "00:00", 497 to: "24:00", 498 }, 499 fare: { 500 from: null, 501 to: null, 502 }, 503 boardingPoints: [], 504 droppingPoints: [], 505 busTypes: [], 506 sortedColumn: "DEPARTURE", 507 order: "DESC", 508 }; 509 /* departure time*/ 510 document.querySelectorAll('[name="departureTime"]').forEach(e => { 511 const timeRange = e.value.split('-'); 512 let departureFilter = { ...defaultFilter, depart: { from: timeRange[0], to: timeRange[1] } }; 513 const filteredReservations = filterReservationsOnlyChart(tripReservations, departureFilter); 514 const countSpan = e.parentElement.querySelector('.filters_1__count'); 515 if (countSpan) { 516 countSpan.innerText = `(${filteredReservations.length})`; 517 } 518 }); 519 520 /* boarding points*/ 521 522 document.querySelectorAll('[name="boardingPoint"]')?.forEach(e => { 523 let boardingFilter = { ...defaultFilter, boardingPoints: [e.value] }; 524 const filteredReservations = filterReservationsOnlyChart(tripReservations, boardingFilter); 525 const countSpan = e.parentElement.querySelector('.filters_1__count'); 526 if (countSpan) { 527 countSpan.innerText = `(${filteredReservations.length})`; 528 529 } 530 }); 531 532 /* dropping points*/ 533 534 document.querySelectorAll('[name="droppingPoint"]')?.forEach(e => { 535 let droppingFilter = { ...defaultFilter, droppingPoints: [e.value] }; 536 const filteredReservations = filterReservationsOnlyChart(tripReservations, droppingFilter); 537 const countSpan = e.parentElement.querySelector('.filters_1__count'); 538 if (countSpan) { 539 countSpan.innerText = `(${filteredReservations.length})`; 540 } 541 }); 542 543 /* Arrival time*/ 544 545 document.querySelectorAll('[name="arrivalTime"]').forEach(e => { 546 const timeRange = e.value.split('-'); 547 let arrivalFilter = { ...defaultFilter, arrival: { from: timeRange[0], to: timeRange[1] } }; 548 const filteredReservations = filterReservationsOnlyChart(tripReservations, arrivalFilter); 549 const countSpan = e.parentElement.querySelector('.filters_1__count'); 550 if (countSpan) { 551 countSpan.innerText = `(${filteredReservations.length})`; 552 } 553 }); 554 555 /* bus types*/ 556 557 document.querySelectorAll('[name="busType"]').forEach(e => { 558 let busTypeFilter = { ...defaultFilter, busTypes: [e.value] }; 559 const filteredReservations = filterReservationsOnlyChart(tripReservations, busTypeFilter); 560 const countSpan = e.parentElement.querySelector('.filters_1__count'); 561 if (countSpan) { 562 countSpan.innerText = `(${filteredReservations.length})`; 563 } 564 }); 565 566}
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.