1document.addEventListener("DOMContentLoaded", () => { 2 3 /* ============================= 4 state 5 ============================= */ 6 7 let current = new Date(); 8 let currentData = []; 9 let holidays = {}; 10 11 /* ============================= 12 DOM cache 13 ============================= */ 14 15 const calendarEl = document.getElementById("ecb-calendar"); 16 const eventsEl = document.getElementById("ecb-events"); 17 const loadingEl = document.getElementById("ecb-loading"); 18 const titleEl = document.getElementById("ecb-title"); 19 const prevBtn = document.getElementById("ecb-prev"); 20 const nextBtn = document.getElementById("ecb-next"); 21 const areaSelect = document.getElementById("ecb-area"); 22 const headerEl = document.querySelector(".header"); 23 const updatedEl = document.getElementById("ecb-updated"); 24 25 /* ============================= 26 ã¨ãªã¢å¤æ´ 27 ============================= */ 28 29 if(areaSelect){ 30 areaSelect.addEventListener("change",()=>{ 31 loadCalendar(current.getFullYear(),current.getMonth()+1); 32 }); 33 } 34 35 /* ============================= 36 util 37 ============================= */ 38 39 const pad = n => String(n).padStart(2,"0"); 40 41 const formatDate = date => { 42 const d = new Date(date); 43 return `${d.getFullYear()}å¹´${d.getMonth()+1}æ${d.getDate()}æ¥`; 44 }; 45 46 const formatNow = () => { 47 const d = new Date(); 48 return `${d.getFullYear()}å¹´${d.getMonth()+1}æ${d.getDate()}æ¥ ${d.getHours()}ææ´æ°`; 49 }; 50 51 const showLoading = () => { 52 loadingEl.style.display = "flex"; 53 calendarEl.style.display = "none"; 54 }; 55 56 const hideLoading = () => { 57 loadingEl.style.display = "none"; 58 calendarEl.style.display = "block"; 59 }; 60 61 /* ============================= 62 ç¥æ¥API 63 ============================= */ 64 65 async function loadHolidays(){ 66 try{ 67 const res = await fetch("https://holidays-jp.github.io/api/v1/date.json"); 68 holidays = await res.json(); 69 }catch(e){ 70 console.error("ç¥æ¥åå¾å¤±æ", e); 71 holidays = {}; 72 } 73 } 74 75 /* ============================= 76 API 77 ============================= */ 78 79 async function loadCalendar(year, month){ 80 81 showLoading(); 82 83 try{ 84 const area = areaSelect.value; 85 86 const res = await fetch(ECB.ajax_url,{ 87 method:"POST", 88 headers:{ 89 "Content-Type":"application/x-www-form-urlencoded" 90 }, 91 body:new URLSearchParams({ 92 action:"ecb_get_calendar", 93 nonce:ECB.nonce, 94 year:year, 95 month:month, 96 pref:area 97 }) 98 }); 99 100 const data = await res.json(); 101 102 hideLoading(); 103 104 if(!data.success){ 105 calendarEl.innerHTML = "<p>èªã¿è¾¼ã¿å¤±æ</p>"; 106 return; 107 } 108 109 /* æ´æ°æ¥æï¼ç¢ºå®çï¼ */ 110 if(updatedEl){ 111 updatedEl.textContent = "æçµæ´æ°ï¼" + formatNow(); 112 } 113 114 /* ãã¼ã¿ã»ãã */ 115 currentData = data.data.calendar; 116 117 titleEl.textContent = `${year}å¹´ ${month}æ`; 118 119 renderCalendar(year,month); 120 121 showTodayEvents(); 122 123 }catch(e){ 124 125 hideLoading(); 126 calendarEl.innerHTML = "<p>ã¨ã©ã¼çºç</p>"; 127 console.error("ã¨ã©ã¼å 容:", e); 128 129 } 130 } 131 132 /* ============================= 133 calendar render 134 ============================= */ 135 136 function renderCalendar(year,month){ 137 138 const firstDate = new Date(year,month-1,1); 139 const firstDay = firstDate.getDay(); 140 141 const lastDate = new Date(year,month,0).getDate(); 142 const prevLast = new Date(year,month-1,0).getDate(); 143 144 let html = `<table class="ecb-table">`; 145 146 /* weekday */ 147 148 html += `<tr class="week-head">`; 149 150 ["æ¥","æ","ç«","æ°´","æ¨","é","å"].forEach((w,i)=>{ 151 const cls = i===0 ? "sun" : i===6 ? "sat" : ""; 152 html += `<th class="${cls}">${w}</th>`; 153 }); 154 155 html += "</tr><tr>"; 156 157 let cellCount = 0; 158 159 /* prev month */ 160 161 for(let i=0;i<firstDay;i++){ 162 const d = prevLast - firstDay + i + 1; 163 html += `<td class="other-month">${d}</td>`; 164 cellCount++; 165 } 166 167 /* current month */ 168 169 for(let d=1; d<=lastDate; d++){ 170 171 const dateStr = `${year}-${pad(month)}-${pad(d)}`; 172 173 let cls = ""; 174 175 const isHoliday = holidays[dateStr]; 176 const dayObj = currentData.find(x => x.date === dateStr); 177 178 const weekIndex = cellCount % 7; 179 180 if(weekIndex===0) cls+=" sun"; 181 if(weekIndex===6) cls+=" sat"; 182 183 if(isHoliday){ 184 cls += " holiday"; 185 } 186 187 if(dayObj){ 188 if(dayObj.today) cls+=" today"; 189 if(dayObj.past) cls+=" past"; 190 if(dayObj.events.length) cls+=" has-event"; 191 } 192 193 html += ` 194 <td class="${cls}" data-date="${dateStr}"> 195 <div class="day">${d}</div> 196 ${isHoliday ? `<div class="holiday-name">${isHoliday}</div>` : ""} 197 </td> 198 `; 199 200 cellCount++; 201 202 if(cellCount % 7 === 0 && d !== lastDate){ 203 html += "</tr><tr>"; 204 } 205 206 } 207 208 /* next month */ 209 210 const totalCells = firstDay + lastDate; 211 const rows = Math.ceil(totalCells / 7); 212 const maxCells = rows * 7; 213 214 for(let i=totalCells;i<maxCells;i++){ 215 const nextDay = i-totalCells+1; 216 html += `<td class="other-month">${nextDay}</td>`; 217 } 218 219 html += "</tr></table>"; 220 221 calendarEl.innerHTML = html; 222 223 const todayCell = calendarEl.querySelector("td.today"); 224 if(todayCell) todayCell.classList.add("active"); 225 } 226 227 /* ============================= 228 event card html 229 ============================= */ 230 231 function createEventHTML(ev){ 232 233 const priceClass = 234 ev.price_name === "ææ" ? "is-paid" : "is-free"; 235 236 const inoutClass = 237 ev.inout_name === "å±å¤" ? "is-outdoor" : "is-indoor"; 238 239 const imgSrc = ev.img 240 ? `https://api.eventbank.jp/image/${ev.img}` 241 : `${ECB.plugin_url}assets/img/noimage.jpg`; 242 243 return ` 244 <div class="event-card"> 245 <a href="${ECB.site_url}
245eventdetail/?eid=${ev.id}"> 246 <div class="event-card__top"> 247 <img src="${imgSrc}" alt="${ev.title}"> 248 <div class="txt"> 249 <h4>${ev.title}</h4> 250 <p>${ev.catchcopy}</p> 251 <div class="cat"> 252 <span class="price_text ${priceClass}">${ev.price_name}</span> 253 <span class="city">${ev.city_name}</span> 254 <span class="inout_name ${inoutClass}">${ev.inout_name}</span> 255 </div> 256 </div> 257 </div> 258 <table> 259 <tr> 260 <th>ä¼å ´</th> 261 <td>${ev.place}</td> 262 </tr> 263 <tr> 264 <th>é嬿é</th> 265 <td>${ev.date_display}</td> 266 </tr> 267 </table> 268 </a> 269 </div> 270 `; 271 } 272 273 /* ============================= 274 仿¥ã¤ãã³ã 275 ============================= */ 276 277 function showTodayEvents(){ 278 279 const todayData = currentData.find(d => d.today); 280 if(!todayData) return; 281 282 let html = `<h3>${formatDate(todayData.date)}</h3>`; 283 284 if(todayData.events.length){ 285 html += todayData.events.map(createEventHTML).join(""); 286 }else{ 287 html += "<p>ã¤ãã³ãã¯ããã¾ããã</p>"; 288 } 289 290 eventsEl.innerHTML = html; 291 } 292 293 /* ============================= 294 click 295 ============================= */ 296 297 calendarEl.addEventListener("click", e => { 298 299 const td = e.target.closest("td[data-date]"); 300 if(!td) return; 301 302 const date = td.dataset.date; 303 304 const dayData = currentData.find(x => x.date === date); 305 306 let html = `<h3>${formatDate(date)}</h3>`; 307 308 if(dayData && dayData.events.length){ 309 html += dayData.events.map(createEventHTML).join(""); 310 }else{ 311 html += "<p>ã¤ãã³ãã¯ããã¾ããã</p>"; 312 } 313 314 eventsEl.innerHTML = html; 315 316 scrollToEvents(); 317 318 calendarEl.querySelectorAll("td").forEach(td=>{ 319 td.classList.remove("active"); 320 }); 321 322 td.classList.add("active"); 323 324 }); 325 326 /* ============================= 327 scroll 328 ============================= */ 329 330 function scrollToEvents(){ 331 332 const headerHeight = 333 headerEl ? headerEl.offsetHeight : 0; 334 335 const rect = eventsEl.getBoundingClientRect(); 336 337 const pos = 338 window.scrollY + rect.top - headerHeight; 339 340 window.scrollTo({ 341 top:pos, 342 behavior:"smooth" 343 }); 344 } 345 346 /* ============================= 347 navigation 348 ============================= */ 349 350 prevBtn.addEventListener("click", () => { 351 current.setMonth(current.getMonth()-1); 352 loadCalendar(current.getFullYear(), current.getMonth()+1); 353 }); 354 355 nextBtn.addEventListener("click", () => { 356 current.setMonth(current.getMonth()+1); 357 loadCalendar(current.getFullYear(), current.getMonth()+1); 358 }); 359 360 /* ============================= 361 init 362 ============================= */ 363 364 (async () => { 365 await loadHolidays(); 366 loadCalendar(current.getFullYear(), current.getMonth()+1); 367 })(); 368 369});
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.