1document.addEventListener('DOMContentLoaded', function() { 2 // Cache frequently accessed elements 3 const calendarDaysContainer = document.getElementById('calendar-days'); 4 const calendarWeekDaysContainer = document.getElementById('calendar-week-days'); 5 6 const rotatingContainer = document.getElementById('rotating-container'); 7 const staticContainer = document.querySelector('.static-container'); 8 const calendarPosterHead = document.getElementById('calendar-poster-head'); 9 const calendarPosterBody = document.getElementById('calendar-poster-body'); 10 const monthTitle = document.getElementById('month-title'); 11 12 // Used to store day -> array of events 13 const daysAndEvents = new Map(); 14 15 // Prepare data for AJAX 16 const data = { 17 action: 'get_calendar_events', 18 nonce: advancedCalendarData.nonce, 19 locale: advancedCalendarData.locale 20 }; 21 22 // Fetch events data 23 jQuery.post(advancedCalendarData.ajaxurl, data, (response) => { 24 if (response.success) { 25 const eventsData = response.data; 26 if (!eventsData) { 27 console.error('No event data returned.'); 28 return; 29 } 30 31 const { 32 weekDays = [], 33 calendarPosterHeadSrc = '', 34 months = [], 35 events = [], 36 eventMonth = 1, 37 eventYear = 1970, 38 } = eventsData; 39 40 const monthIndex = parseInt(eventMonth, 10) - 1; 41 const yearNum = parseInt(eventYear, 10); 42 43 if (calendarPosterHeadSrc) { 44 calendarPosterHead.setAttribute('src', calendarPosterHeadSrc); 45 } 46 47 events.forEach(evt => { 48 const { day, header, location, link, time } = evt; 49 const formatted = formatTime(time); 50 if (!daysAndEvents.has(day)) { 51 daysAndEvents.set(day, []); 52 } 53 daysAndEvents.get(day).push({ 54 header, 55 location, 56 link, 57 time: formatted 58 }); 59 }); 60 61 daysAndEvents.forEach((evtArray) => { 62 evtArray.sort((a, b) => { 63 const timeA = new Date(`1970-01-01T${a.time}Z`); 64 const timeB = new Date(`1970-01-01T${b.time}Z`); 65 return timeA - timeB; 66 }); 67 }); 68 69 generateCalendar(monthIndex, yearNum, weekDays, months); 70 71 const blockElement = document.querySelector('.wp-block-create-block-advanced-calendar'); 72 if (blockElement) { 73 blockElement.style.visibility = 'visible'; 74 } 75 } else { 76 console.error('Failed to load calendar events.'); 77 } 78 }); 79 80 // ------------------------------------ 81 // Helper Functions 82 // ------------------------------------ 83 84 function formatTime(time = '') { 85 const timePattern = /^([01]\d|2[0-3]):([0-5]\d)$/; 86 if (timePattern.test(time)) { 87 return time; 88 } 89 let [hours = '00', minutes = '00'] = time.split(':'); 90 hours = hours.padStart(2, '0'); 91 minutes = minutes.padStart(2, '0'); 92 return `${hours}:${minutes}`; 93 } 94 95 function generateCalendar(eventMonth, eventYear, weekDays, monthsArray) { 96 monthTitle.innerHTML = monthsArray[eventMonth] || ''; 97 98 const firstDayOfMonth = new Date(eventYear, eventMonth, 1); 99 const daysInMonth = new Date(eventYear, eventMonth + 1, 0).getDate(); 100 101 const dayOfWeek = firstDayOfMonth.getDay(); 102 const adjustedDayOfWeek = (dayOfWeek === 0) ? 6 : dayOfWeek - 1; 103 104 calendarDaysContainer.innerHTML = ''; 105 calendarWeekDaysContainer.innerHTML = ''; 106 107 for (let i = 0; i < 7; i++) { 108 const li = document.createElement('li'); 109 li.textContent = weekDays[i] || ''; 110 calendarWeekDaysContainer.appendChild(li); 111 } 112 113 for (let i = 0; i < adjustedDayOfWeek; i++) { 114 const emptyLi = document.createElement('li'); 115 calendarDaysContainer.appendChild(emptyLi); 116 } 117 118 const today = new Date(); 119 for (let day = 1; day <= daysInMonth; day++) { 120 const li = document.createElement('li'); 121 li.textContent = day; 122 123 // Universal SVG: Every day gets a circle path 124 const svg = createDaySVG(); 125 svg.style.visibility = 'hidden'; 126 li.appendChild(svg); 127 128 const isToday = ( 129 today.getDate() === day && 130 today.getMonth() === eventMonth && 131 today.getFullYear() === eventYear 132 ); 133 134 if (isToday) { 135 changeBanner(day, true); 136 changeBanner(day, false); 137 if (svg) { 138 svg.style.visibility = 'visible'; 139 svg.classList.add('active-date'); 140 } 141 } 142 143 // Universal Hover: Draw animation on every date 144 li.addEventListener('mouseover', () => { 145 if (svg && !svg.classList.contains('active-date')) { 146 svg.style.visibility = 'visible'; 147 li.myVivus = new Vivus(svg); 148 } 149 }); 150 151 li.addEventListener('mouseout', () => { 152 if (li.myVivus && svg && !svg.classList.contains('active-date')) { 153 li.myVivus.destroy(); 154 svg.style.visibility = 'hidden'; 155 } 156 }); 157
158 // Universal Click: Circle every date on click 159 li.addEventListener('click', () => { 160 changeBanner(day, true); 161 162 // Hide and reset all other circles 163 document.querySelectorAll('.animation-svg').forEach((svgEl) => { 164 svgEl.style.visibility = 'hidden'; 165 svgEl.classList.remove('active-date'); 166 }); 167 168 // Show, animate, and lock THIS day's circle 169 if (svg) { 170 svg.style.visibility = 'visible'; 171 svg.classList.add('active-date'); 172 // Force a fresh draw on click 173 new Vivus(svg); 174 } 175 176 // Page turn animation 177 calendarPosterBody.classList.add('page-turn'); 178 rotatingContainer.style.overflowY = 'unset'; 179 calendarPosterBody.addEventListener('animationend', function onAnimEnd() { 180 calendarPosterBody.classList.remove('page-turn'); 181 rotatingContainer.style.overflowY = 'auto'; 182 changeBanner(day, false); 183 calendarPosterBody.removeEventListener('animationend', onAnimEnd); 184 }); 185 }); 186 187 calendarDaysContainer.appendChild(li); 188 } 189 } 190 191 function createDaySVG() { 192 const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); 193 svg.classList.add('animation-svg'); 194 svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); 195 svg.setAttribute('viewBox', '0 0 87.86 73.04'); 196 197 const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); 198 path.classList.add('animatedPath'); 199 path.setAttribute( 200 'd', 201 'M34.79,5.45c-10.68,1.22-19.11,9.85-21.58,20.1-2.8,11.66,1.2,24.49,8.79,33.55,3.74,4.47,8.52,7.84,13.97,9.9s11.75,2.96,17.7,2.89c5.41-.07,10.97-1.05,15.74-3.71,5.21-2.9,8.59-7.72,11.04-13.03,2.6-5.63,5.04-11.79,4.63-18.11s-3.29-12.03-6.7-17.18-7.1-9.46-11.93-12.88S55.32,1.34,49.21,.49c-11.97-1.68-24.58,.95-34.27,8.36C5.89,15.77-.93,27.02,.1,38.74s9.79,20.77,20.21,25.15c11.26,4.74,24.34,5.05,36.1,2.13,5.88-1.46,11.6-3.78,16.79-6.93,4.71-2.85,9.14-6.56,11.86-11.42,6.19-11.06,1.28-24.06-6.91-32.54C69.99,6.69,58.72,1.44,47.04,.44c-6.3-.54-12.75,.18-18.78,2.07-5.57,1.74-11.07,4.41-15.36,8.44C4.62,18.71,2.91,31.14,5.58,41.76s9.08,19.24,17.83,24.97c9.27,6.08,20.95,7.79,31.66,5.04,11.47-2.95,20.21-11.05,25.97-21.18,3.01-5.29,4.55-10.95,3.05-16.99-1.42-5.72-4.96-10.8-9.02-14.98-8.12-8.37-19.04-14.5-30.9-14.79-5.79-.14-11.56,1.14-16.66,3.91-1.7,.92-.18,3.51,1.51,2.59,9.86-5.35,21.85-4.16,31.52,.98,4.73,2.51,8.99,5.86,12.68,9.73s6.85,8.5,8.06,13.75c1.29,5.66-.69,10.77-3.6,15.57-2.83,4.68-6.34,9.03-10.69,12.38-9.65,5.69-20.95,8.45-32.13,8.02-10.88-.42-22.37-3.84-29.75-12.26-3.27-3.73-5.61-8.43-6.16-13.39-.62-5.64,.86-11.37,3.55-16.32C11.71,13.61,20.72,7.08,30.82,4.42c10.82-2.85,23.53-1.75,33.05,4.43,4.64,3.02,8.36,7.28,11.44,11.82,3.15,4.64,6.06,9.84,6.68,15.51s-1.55,11.76-3.97,17.07c-2.18,4.8-5,9.31-9.65,12.05-4.31,2.54-9.38,3.47-14.32,3.57-5.47,.11-11.07-.62-16.25-2.4-10.24-3.52-17.52-12.37-20.73-22.52s-2.11-21.84,5.78-29.56c3.23-3.16,7.43-5.42,11.95-5.94,1.9-.22,1.92-3.22,0-3h0Z' 202 ); 203 svg.appendChild(path); 204 return svg; 205 } 206 207 function changeBanner(day, isStatic) { 208 const currentDayEvents = daysAndEvents.get(day); 209 cleanBanner(isStatic); 210 if (!currentDayEvents) return; 211 212 const container = isStatic ? staticContainer : calendarPosterBody; 213 const prefix = isStatic ? 'static' : 'dynamic'; 214 215 currentDayEvents.forEach((evt, i) => { 216 const index = i + 1; 217 if (index > 1) { 218 const divider = document.createElement('div'); 219 divider.id = `${prefix}-divider-${index}`; 220 divider.classList.add('class-divider'); 221 container.appendChild(divider); 222 } 223 const wrapper = document.createElement('div'); 224 wrapper.id = `${prefix}-wrapper-${index}`; 225 226 const headingDiv = document.createElement('div'); 227 headingDiv.className = 'section-heading'; 228 headingDiv.id = `section-heading-id-${prefix}-${index}`; 229 headingDiv.textContent = evt.header || ''; 230 231 if (evt.link) { 232 headingDiv.style.cursor = 'pointer'; 233 headingDiv.addEventListener('click', () => { 234 window.open(evt.link, '_blank'); 235 }); 236 } 237 238 const metaDiv = document.createElement('div'); 239 metaDiv.className = 'meta-group'; 240 241 const locDiv = document.createElement('div'); 242 locDiv.className = 'section-location'; 243 locDiv.id = `section-location-id-${prefix}-${index}`; 244 locDiv.textContent = evt.location || ''; 245 246 const timeP = document.createElement('p'); 247 timeP.id = `section-time-id-${prefix}-${index}`; 248 timeP.className = 'section-time'; 249 timeP.textContent = evt.time || ''; 250 251 metaDiv.appendChild(locDiv); 252 metaDiv.appendChild(timeP); 253 254 wrapper.appendChild(headingDiv); 255 wrapper.appendChild(metaDiv); 256 container.appendChild(wrapper); 257 }); 258 } 259 260 function cleanBanner(isStatic) { 261 const prefix = isStatic ? 'static' : 'dynamic'; 262 const container = isStatic ? staticContainer : calendarPosterBody; 263 let i = 1; 264 while (true) { 265 const wrapper = document.getElementById(`${prefix}-wrapper-${i}`); 266 if (!wrapper) break; 267 container.removeChild(wrapper); 268 269 if (i > 1) { 270 const divider = document.getElementById(`${prefix}-divider-${i}`); 271 if (divider) { 272 container.removeChild(divider); 273 } 274 } 275 i++; 276 } 277 } 278});
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.