1(() => { 2 const API_URL = '/wp-json/fuji-weather/v1/wake'; 3 4 const TARGET_CITIES = [ 5 { key: 'å¯å£«åç°å¸', labels: { ja: 'å¯å£«åç°å¸ï¼åç°å£ï¼', en: 'Fujiyoshida City (Yoshida Trail)' } }, 6 { key: 'å°å±±çº', labels: { ja: 'å°å±±çºï¼é èµ°å£ï¼', en: 'Oyama Town (Subashiri Trail)' } }, 7 { key: 'å¾¡æ®¿å ´å¸', labels: { ja: 'å¾¡æ®¿å ´å¸ï¼å¾¡æ®¿å ´å£ï¼', en: 'Gotemba City (Gotemba Trail)' } }, 8 { key: 'å¯å£«å®®å¸', labels: { ja: 'å¯å£«å®®å¸ï¼å¯å£«å®®å£ï¼', en: 'Fujinomiya City (Fujinomiya Trail)' } } 9 ]; 10 11 const I18N = { 12 ja: { 13 none: 'çºè¡¨ãªã', 14 fetchError: 'åå¾å¤±æ', 15 updatedFallback: '---', 16 released: 'è§£é¤', 17 weatherCodes: { 18 '00': 'è§£é¤', 19 '02': 'æ´é¢¨éªè¦å ±', 20 '03': '大é¨è¦å ±', 21 '04': '洪水è¦å ±', 22 '05': 'æ´é¢¨è¦å ±', 23 '06': '大éªè¦å ±', 24 '07': '波浪è¦å ±', 25 '08': '髿½®è¦å ±', 26 '10': '大鍿³¨æå ±', 27 '12': 'å¤§éªæ³¨æå ±', 28 '13': 'é¢¨éªæ³¨æå ±', 29 '14': 'é·æ³¨æå ±', 30 '15': '強風注æå ±', 31 '16': '波浪注æå ±', 32 '17': 'èéªæ³¨æå ±', 33 '18': '洪水注æå ±', 34 '19': '髿½®æ³¨æå ±', 35 '20': 'æ¿é§æ³¨æå ±', 36 '21': 'ä¹¾ç¥æ³¨æå ±', 37 '22': 'ãªã ãæ³¨æå ±', 38 '23': '使¸©æ³¨æå ±', 39 '24': 'éæ³¨æå ±', 40 '25': 'çæ°·æ³¨æå ±', 41 '26': 'çéªæ³¨æå ±', 42 '27': 'ãã®ä»ã®æ³¨æå ±', 43 '31': '大é¨ç¹å¥è¦å ±ï¼åç ç½å®³ï¼', 44 '32': 'æ´é¢¨éªç¹å¥è¦å ±', 45 '33': '大é¨ç¹å¥è¦å ±ï¼æµ¸æ°´å®³ï¼', 46 '35': 'æ´é¢¨ç¹å¥è¦å ±', 47 '36': '大éªç¹å¥è¦å ±', 48 '37': '波浪ç¹å¥è¦å ±', 49 '38': '髿½®ç¹å¥è¦å ±', 50 '39': '大é¨ç¹å¥è¦å ±ï¼åç ç½å®³ã浸水害ï¼' 51 } 52 }, 53 en: { 54 none: 'None', 55 fetchError: 'Failed to load', 56 updatedFallback: '---', 57 released: 'Cancelled', 58 weatherCodes: { 59 '00': 'Cancelled', 60 '02': 'Blizzard Warning', 61 '03': 'Heavy Rain Warning', 62 '04': 'Flood Warning', 63 '05': 'Storm Warning', 64 '06': 'Heavy Snow Warning', 65 '07': 'High Wave Warning', 66 '08': 'Storm Surge Warning', 67 '10': 'Heavy Rain Advisory', 68 '12': 'Heavy Snow Advisory', 69 '13': 'Snowstorm Advisory', 70 '14': 'Thunder Advisory', 71 '15': 'Strong Wind Advisory', 72 '16': 'High Wave Advisory', 73 '17': 'Snowmelt Advisory', 74 '18': 'Flood Advisory', 75 '19': 'Storm Surge Advisory', 76 '20': 'Dense Fog Advisory', 77 '21': 'Dry Air Advisory', 78 '22': 'Avalanche Advisory', 79 '23': 'Low Temperature Advisory', 80 '24': 'Frost Advisory', 81 '25': 'Ice Accretion Advisory', 82 '26': 'Snow Accretion Advisory', 83 '27': 'Other Advisory', 84 '31': 'Emergency Heavy Rain Warning (Landslide)', 85 '32': 'Emergency Blizzard Warning', 86 '33': 'Emergency Heavy Rain Warning (Flooding)', 87 '35': 'Emergency Storm Warning', 88 '36': 'Emergency Heavy Snow Warning', 89 '37': 'Emergency High Wave Warning', 90 '38': 'Emergency Storm Surge Warning', 91 '39': 'Emergency Heavy Rain Warning (Landslide / Flooding)' 92 } 93 } 94 }; 95 96 const updatedEl = () => document.getElementById('weather-wake-time'); 97 const emptyEl = () => document.getElementById('weather-wake-empty'); 98 99 function detectLang() { 100 const urlLang = new URLSearchParams(window.location.search).get('gtlang'); 101 const htmlLang = document.documentElement.getAttribute('lang') || ''; 102 103 const raw = (urlLang || htmlLang || 'ja').toLowerCase(); 104 105 if (raw.startsWith('ja')) return 'ja'; 106 return 'en'; 107 } 108 109 const LANG = detectLang(); 110 const t = I18N[LANG] || I18N.ja; 111 112 function getRow(city) { 113 return document.querySelector(`.weather-wake__row[data-city="${city}"]`); 114 } 115 116 function getAlertNames(codeString) { 117 const codes = String(codeString || '').match(/.{1,2}/g) || []; 118 119 return codes 120 .map((code) => t.weatherCodes[code] || '') 121 .filter((name) => name && name !== t.released); 122 } 123 124 function getBadgeClass(name) { 125 if (LANG === 'en') { 126 if (name.includes('Emergency')) return 'is-emergency'; 127 if (name.includes('Warning')) return 'is-warning'; 128 if (name.includes('Advisory')) return 'is-advisory'; 129 return 'is-normal'; 130 } 131 132 if (name.includes('ç¹å¥è¦å ±')) return 'is-emergency'; 133 if (name.includes('è¦å ±')) return 'is-warning'; 134 if (name.includes('注æå ±')) return 'is-advisory'; 135 return 'is-normal'; 136 } 137 138 function formatTimestamp(ts) {
139 const value = String(ts || '').trim(); 140 if (!/^\d{10}$/.test(value)) return ''; 141 142 const year = `20${value.slice(0, 2)}`; 143 const month = value.slice(2, 4); 144 const day = value.slice(4, 6); 145 const hour = value.slice(6, 8); 146 const minute = value.slice(8, 10); 147 148 if (LANG === 'en') { 149 return `${year}-${month}-${day} ${hour}:${minute}`; 150 } 151 152 return `${year}.${month}.${day} ${hour}:${minute}`; 153 } 154 155 function mergeRows(json) { 156 const rows4900 = Array.isArray(json['4900']) ? json['4900'] : []; 157 const rows5000 = Array.isArray(json['5000']) ? json['5000'] : []; 158 return [...rows4900, ...rows5000]; 159 } 160 161 function pickLatestByCity(rows) { 162 const latestMap = {}; 163 164 rows.forEach((row) => { 165 const city = row.city; 166 if (!city) return; 167 168 if (!latestMap[city]) { 169 latestMap[city] = row; 170 return; 171 } 172 173 const currentTs = String(row.timestamp || ''); 174 const savedTs = String(latestMap[city].timestamp || ''); 175 176 if (currentTs > savedTs) { 177 latestMap[city] = row; 178 } 179 }); 180 181 return latestMap; 182 } 183 184 function renderWake(json) { 185 const allRows = mergeRows(json); 186 const latestMap = pickLatestByCity(allRows); 187 188 let hasAnyAlert = false; 189 let latestTimestamp = ''; 190 191 TARGET_CITIES.forEach(({ key, labels }) => { 192 const rowEl = getRow(key); 193 if (!rowEl) return; 194 195 const cityLabelEl = rowEl.querySelector('.weather-wake__city'); 196 if (cityLabelEl) { 197 cityLabelEl.textContent = labels[LANG] || labels.ja; 198 } 199 200 const alertsEl = rowEl.querySelector('.weather-wake__alerts'); 201 if (!alertsEl) return; 202 203 alertsEl.innerHTML = ''; 204 205 const row = latestMap[key]; 206 if (!row) { 207 alertsEl.innerHTML = `<span class="weather-wake__none">${t.none}</span>`; 208 return; 209 } 210 211 if (String(row.timestamp || '') > latestTimestamp) { 212 latestTimestamp = String(row.timestamp || ''); 213 } 214 215 const alertNames = getAlertNames(row.codes); 216 217 if (!alertNames.length) { 218 alertsEl.innerHTML = `<span class="weather-wake__none">${t.none}</span>`; 219 return; 220 } 221 222 hasAnyAlert = true; 223 224 alertNames.forEach((name) => { 225 const badge = document.createElement('span'); 226 badge.className = `weather-wake__badge ${getBadgeClass(name)}`; 227 badge.textContent = name; 228 alertsEl.appendChild(badge); 229 }); 230 }); 231 232 if (updatedEl()) { 233 updatedEl().textContent = latestTimestamp ? formatTimestamp(latestTimestamp) : t.updatedFallback; 234 } 235 236 if (emptyEl()) { 237 emptyEl().hidden = hasAnyAlert; 238 } 239 } 240 241 async function initWake() { 242 try { 243 const res = await fetch(API_URL, { cache: 'no-store' }); 244 if (!res.ok) { 245 throw new Error('Failed to fetch wake data'); 246 } 247 248 const json = await res.json(); 249 renderWake(json); 250 } catch (error) { 251 console.error(error); 252 253 TARGET_CITIES.forEach(({ key, labels }) => { 254 const rowEl = getRow(key); 255 if (!rowEl) return; 256 257 const cityLabelEl = rowEl.querySelector('.weather-wake__city'); 258 if (cityLabelEl) { 259 cityLabelEl.textContent = labels[LANG] || labels.ja; 260 } 261 262 const alertsEl = rowEl.querySelector('.weather-wake__alerts'); 263 if (!alertsEl) return; 264 265 alertsEl.innerHTML = `<span class="weather-wake__none">${t.fetchError}</span>`; 266 }); 267 268 if (updatedEl()) { 269 updatedEl().textContent = t.fetchError; 270 } 271 272 if (emptyEl()) { 273 emptyEl().hidden = true; 274 } 275 } 276 } 277 278 document.addEventListener('DOMContentLoaded', initWake); 279})();
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.