1(function ($, Drupal, drupalSettings) { 2 // Fetch data from the API 3 Drupal.behaviors.religiousCalendarBlock = { 4 attach: function(context, settings) { 5 6 once('religiousCalendarFetch', 'html').forEach(function (element) { 7 8 if( document.getElementById('religious-calendar') == null ) 9 return; 10 // fetch and display the data on page load 11 fetchEventData(); 12 13 async function fetchEventData() { 14 const currentDate = new Date(); 15 const currentYear = currentDate.getFullYear(); 16 const futureYear = currentYear + 3; 17 18 19 try { 20 const url = `${settings.religiousCalendarBlock.api_url}?CalendarType=Religious&EventDateStart=${currentYear}-01-01&EventDateEnd=${futureYear}-12-31`; 21 const response = await fetch(url); 22 const data = await response.json(); 23 processEventData(data.List); 24 } catch (error) { 25 console.error("Error fetching data:", error); 26 } 27 } 28 29 function processEventData(events) { 30 // create arrays to hold years and events 31 const years = []; 32 const eventsByCategoryAndName = {}; 33 34 // loop through the data and store events in the arrays 35 events.forEach(event => { 36 const category = event.MetaCategory; 37 const year = event.EventDateStart.slice(0, 4); 38 39 // ff the year is not in the years array, add it 40 if (!years.includes(year)) { 41 years.push(year); 42 } 43 44 // if the category is not in the eventsByCategoryAndName array, add it with an empty object 45 if (!eventsByCategoryAndName[category]) { 46 eventsByCategoryAndName[category] = {}; 47 } 48 49 // if the event name is not in the eventsByCategoryAndName[category] object, add it with an empty object 50 if (!eventsByCategoryAndName[category][event.EventName]) { 51 eventsByCategoryAndName[category][event.EventName] = {}; 52 } 53 54 // store the event data under the corresponding year for the given event name and category 55 eventsByCategoryAndName[category][event.EventName][year] = { 56 start: formatDate(event.EventDateStart), 57 end: formatDate(event.EventDateEnd) 58 }; 59 }); 60 61 // create table headers for each year 62 const tableHeaderRow = document.createElement("tr"); 63 tableHeaderRow.innerHTML = "<th width='25%'>Event Name</th>" + years.map(year => `<th 'width=75%'>${year}</th>`).join(""); 64 document.getElementById("religious-calendar").appendChild(tableHeaderRow); 65 66 // create rows for each category and its events 67 for (const category in eventsByCategoryAndName) { 68 const colspan = years.length + 1; 69 addEmptyRow( colspan ); 70 71 const eventsInCategory = eventsByCategoryAndName[category]; 72 const categoryRow = document.createElement("tr"); 73 categoryRow.classList.add("category-row"); // Add the class for styling 74 const categoryCell = document.createElement("td"); 75 categoryCell.setAttribute("colspan", colspan); 76 categoryCell.textContent = category; 77 categoryRow.appendChild(categoryCell); 78 document.getElementById("religious-calendar").appendChild(categoryRow); 79 80 for (const eventName in eventsInCategory) { 81 const eventRow = document.createElement("tr"); 82 eventRow.innerHTML = `<td>${eventName}</td>`;
83 const eventData = eventsInCategory[eventName]; 84 for (const year of years) { 85 if (eventData[year]) { 86 const { start, end } = eventData[year]; 87 eventRow.innerHTML += `<td>${start}${start !== end ? ' - ' + end : ''}</td>`; 88 } else { 89 eventRow.innerHTML += "<td></td>"; 90 } 91 } 92 document.getElementById("religious-calendar").appendChild(eventRow); 93 } 94 } 95 } 96 97 function addEmptyRow(colspan) { 98 const emptyRow = document.createElement("tr"); 99 emptyRow.classList.add("empty-row"); // Add the class for styling 100 const emptyCell = document.createElement("td"); 101 emptyCell.setAttribute("colspan", colspan); 102 emptyRow.appendChild(emptyCell); 103 document.getElementById("religious-calendar").appendChild(emptyRow); 104 } 105 106 // converts dates to proper format 107 function formatDate(dateString) { 108 const date = new Date(dateString); 109 const options = { year: 'numeric', month: 'long', day: 'numeric' }; 110 return date.toLocaleDateString('en-US', options); 111 } 112 113 }); 114 } 115 } 116})(jQuery, Drupal, drupalSettings);
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.