1import { Controller } from '@hotwired/stimulus' 2 3/* stimulusFetch: 'lazy' */ 4export default class extends Controller { 5 static values = { 6 eventsUrl: String, 7 addUrlPath: false, 8 waitForMarkers: true 9 } 10 11 urlParams = new URLSearchParams(window.location.search) 12 busy = false 13 14 connect() { 15 this.urlParams.delete('bounds') 16 this.handlePaging() 17 18 if ( !this.waitForMarkers ) { 19 this.getEvents() 20 } 21 22 document.addEventListener( 23 'filterFormSubmitted', this.onFilterFormSubmitted.bind(this) 24 ) 25 } 26 27 disconnect() { 28 document.removeEventListener( 29 'filterFormSubmitted', this.onFilterFormSubmitted.bind(this) 30 ) 31 } 32 33 handlePaging() { 34 const me = this 35 36 me.element.addEventListener('click', function(e) { 37 const target = e.target 38 39 if ( target.tagName.toLowerCase() !== 'a' || 40 !target.closest('ul.pagination') ) { 41 return 42 } 43 44 e.preventDefault() 45 const url = new URL(target.getAttribute('href'), window.location.origin) 46 const cepage = url.searchParams.get('cepage') 47 48 if ( cepage ) { 49 me.urlParams.set('cepage', cepage) 50 me.getEvents() 51 52 const element = document.getElementById('churchevents') 53 54 window.scrollTo({ 55 top: element.getBoundingClientRect().top + window.pageYOffset - 200, 56 behavior: 'smooth' 57 }) 58 } 59 }) 60 } 61 62 getEvents(bounds) { 63 const me = this 64 65 if ( me.busy ) { 66 return 67 } 68 69 me.busy = true 70 71 me.element.innerHTML = ` 72 <div class="text-center mt-5"> 73 <div class="spinner-border" role="status"> 74 <span class="visually-hidden">Loading...</span> 75 </div> 76 </div> 77 ` 78 79 me.addUrlPathValue && me.urlParams.set('urlPath', location.pathname) 80 bounds && me.urlParams.set('bounds', bounds) 81 82 fetch(`${me.eventsUrlValue}${me.getQueryString(me.urlParams)}`) 83 .then((response) => response.text()) 84 .then((eventsHtml) => me.displayEvents(eventsHtml)) 85 86 .catch(() => { 87 me.busy = false 88 }) 89 } 90 91 mapZoomedOrMoved({detail}) { 92 this.urlParams.delete('cepage') 93 this.getEvents(detail.bounds) 94 } 95 96 displayEvents(churchEventsHtml) { 97 const me = this 98 me.element.innerHTML = churchEventsHtml 99 100 const accordionChurchEvents = me.element.querySelector('#accordionChurchEvents') 101 const churchEventsCount = accordionChurchEvents.childElementCount 102 103 if ( churchEventsCount > 0 ) { 104 const churchEventsTab = document.getElementById('churchEventsTab') 105 churchEventsTab.style.display = 'block' 106 107 if ( !this.hasActiveSibling(churchEventsTab) ) { 108 accordionChurchEvents.closest('.tab-pane').classList.add('active') 109 churchEventsTab.querySelector('.nav-link').classList.add('active') 110 } 111 } 112 113 me.busy = false 114 } 115 116 hasActiveSibling(tab) { 117 const siblings = Array.from(tab.parentElement.children) 118 .filter(child => child !== tab) 119 120 for ( const sibling of siblings ) { 121 if ( sibling.querySelector('.nav-link').classList.contains('active') ) { 122 return true 123 } 124 } 125 126 return false 127 } 128 129 getQueryString(params) { 130 const str = params.toString() 131 return str ? `?${str}` : '' 132 } 133 134 onFilterFormSubmitted({detail}) { 135 let startdate = detail.startdate 136 let enddate = detail.enddate 137 this.urlParams.delete('startdate') 138 this.urlParams.delete('enddate') 139 140 if ( startdate || enddate ) { 141 this.urlParams.set('startdate', startdate) 142 this.urlParams.set('enddate', enddate) 143 } 144 145 this.getEvents() 146 } 147}
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.