PageSourceSearch

https://www.fujisan-climb.jp/wp-content/themes/mtfuji-climbing-official-web/assets/js/jma-alert.js?ver=1.0

js fujisan-climb.jp collected 2026-10-02 03:18:39 UTC 8,370 bytes, 279 lines download raw bytes

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.