PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.7
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.7
2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / weather-widget / frontend.js

frontend.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.7, at blocks/weather-widget/frontend.js

209 lines 9.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 document.addEventListener('DOMContentLoaded', function () {
2 document.querySelectorAll('.bkbg-ww-app').forEach(function (root) {
3 var opts = JSON.parse(root.dataset.opts || '{}');
4 new WeatherWidget(root, opts);
5 });
6 });
7
8 function WeatherWidget(root, opts) {
9 var self = this;
10 self.root = root;
11 self.opts = opts;
12 self.apiKey = opts.apiKey || '';
13 self.city = opts.city || 'London';
14 self.units = opts.units || 'metric';
15 self.lang = opts.lang || 'en';
16 self.refreshMs = (opts.refreshInterval || 0) * 60 * 1000;
17 self.timer = null;
18 self.lat = null;
19 self.lon = null;
20 self.current = null;
21
22 if (!self.apiKey) {
23 root.innerHTML = '<div class="bkbg-ww-loading">⚠️ No OpenWeatherMap API key set. Add it in the block settings.</div>';
24 return;
25 }
26
27 if (opts.autoLocation && navigator.geolocation) {
28 navigator.geolocation.getCurrentPosition(
29 function (pos) {
30 self.lat = pos.coords.latitude;
31 self.lon = pos.coords.longitude;
32 self.fetchWeather();
33 },
34 function () { self.fetchWeather(); }
35 );
36 } else {
37 self.fetchWeather();
38 }
39 }
40
41 WeatherWidget.prototype.fetchWeather = function () {
42 var self = this;
43 var base = 'https://api.openweathermap.org/data/2.5/';
44 var unitStr = '&units=' + self.units + '&lang=' + self.lang;
45 var locStr = self.lat ? ('lat=' + self.lat + '&lon=' + self.lon) : ('q=' + encodeURIComponent(self.city));
46 var currentUrl = base + 'weather?' + locStr + unitStr + '&appid=' + self.apiKey;
47 var forecastUrl = base + 'forecast?' + locStr + unitStr + '&cnt=40&appid=' + self.apiKey;
48
49 self.root.innerHTML = '<div class="bkbg-ww-loading">🌐 Loading weather…</div>';
50
51 Promise.all([
52 fetch(currentUrl).then(function (r) { return r.json(); }),
53 self.opts.showForecast ? fetch(forecastUrl).then(function (r) { return r.json(); }) : Promise.resolve(null)
54 ]).then(function (data) {
55 var current = data[0];
56 var forecast = data[1];
57 if (current.cod && current.cod !== 200) {
58 self.root.innerHTML = '<div class="bkbg-ww-error">❌ ' + (current.message || 'API error') + '</div>';
59 return;
60 }
61 self.current = current;
62 self.render(current, forecast);
63 if (self.refreshMs > 0) {
64 clearInterval(self.timer);
65 self.timer = setInterval(function () { self.fetchWeather(); }, self.refreshMs);
66 }
67 }).catch(function (err) {
68 self.root.innerHTML = '<div class="bkbg-ww-error">❌ Failed to load weather data. Check your API key and city name.</div>';
69 });
70 };
71
72 WeatherWidget.prototype.render = function (current, forecast) {
73 var self = this;
74 var opts = self.opts;
75 var a = opts;
76
77 var deg = a.units === 'imperial' ? '°F' : a.units === 'standard' ? 'K' : '°C';
78 var temp = Math.round(current.main.temp);
79 var feelsLike = Math.round(current.main.feels_like);
80 var tempMax = Math.round(current.main.temp_max);
81 var tempMin = Math.round(current.main.temp_min);
82 var humidity = current.main.humidity;
83 var windSpeed = Math.round(current.wind.speed * (a.units === 'metric' ? 3.6 : 1));
84 var windUnit = a.units === 'metric' ? 'km/h' : a.units === 'imperial' ? 'mph' : 'm/s';
85 var pressure = current.main.pressure;
86 var visibility = current.visibility ? Math.round(current.visibility / 1000) + ' km' : '--';
87 var condition = current.weather[0].description;
88 var iconCode = current.weather[0].icon;
89 var cityName = current.name + (current.sys && current.sys.country ? ', ' + current.sys.country : '');
90 var isNight = iconCode.endsWith('n');
91
92 /* determine bg class */
93 var mainId = current.weather[0].id;
94 var bgClass;
95 if (a.backgroundStyle === 'custom') {
96 bgClass = 'bkbg-ww-bg-custom';
97 } else if (a.backgroundStyle === 'transparent') {
98 bgClass = '';
99 } else {
100 if (isNight) bgClass = 'bkbg-ww-bg-night';
101 else if (mainId >= 200 && mainId < 300) bgClass = 'bkbg-ww-bg-thunderstorm';
102 else if (mainId >= 300 && mainId < 600) bgClass = 'bkbg-ww-bg-rain';
103 else if (mainId >= 600 && mainId < 700) bgClass = 'bkbg-ww-bg-snow';
104 else if (mainId >= 700 && mainId < 800) bgClass = 'bkbg-ww-bg-mist';
105 else if (mainId === 800) bgClass = 'bkbg-ww-bg-clear';
106 else bgClass = 'bkbg-ww-bg-clouds';
107 }
108
109 var weatherEmoji = iconToEmoji(iconCode);
110
111 /* CSS vars */
112 var wrapStyle = 'color:' + a.textColor + ';padding:' + a.padding + 'px;border-radius:' + a.borderRadius + 'px;';
113 if (a.backgroundStyle === 'custom') wrapStyle += '--ww-bg:' + a.customBg + ';';
114 if (a.layout === 'card') wrapStyle += 'max-width:' + a.maxWidth + 'px;margin:0 auto;';
115
116 var cardStyle = 'background:' + a.cardBg + ';backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border-radius:' + a.cardRadius + 'px;padding:24px;border:1px solid rgba(255,255,255,0.2);';
117
118 /* forecast daily groups (pick one item per day ~noon) */
119 var forecastHTML = '';
120 if (a.showForecast && forecast && forecast.list) {
121 var days = [];
122 var seen = {};
123 forecast.list.forEach(function (item) {
124 var d = new Date(item.dt * 1000);
125 var dayKey = d.toLocaleDateString('en', { weekday: 'short' });
126 var dayDate = d.toDateString();
127 if (!seen[dayDate] && days.length < a.forecastDays) {
128 seen[dayDate] = true;
129 days.push({
130 day: dayKey,
131 emoji: iconToEmoji(item.weather[0].icon),
132 hi: Math.round(item.main.temp_max),
133 lo: Math.round(item.main.temp_min),
134 });
135 }
136 });
137 var fcDays = days.map(function (f) {
138 return '<div class="bkbg-ww-fc-day" style="background:' + a.forecastBg + ';border-radius:' + a.cardRadius + 'px;">' +
139 '<div class="bkbg-ww-fc-name">' + f.day + '</div>' +
140 '<div class="bkbg-ww-fc-icon">' + f.emoji + '</div>' +
141 '<div class="bkbg-ww-fc-hi">' + f.hi + deg + '</div>' +
142 '<div class="bkbg-ww-fc-lo">' + f.lo + deg + '</div>' +
143 '</div>';
144 }).join('');
145 forecastHTML = '<div class="bkbg-ww-forecast-label">5-Day Forecast</div>' +
146 '<div class="bkbg-ww-forecast">' + fcDays + '</div>';
147 }
148
149 var statsHTML = '';
150 if (a.showHumidity || a.showWind || a.showPressure || a.showVisibility) {
151 var stats = [];
152 if (a.showHumidity) stats.push({ icon: '💧', val: humidity + '%', lbl: 'Humidity' });
153 if (a.showWind) stats.push({ icon: '💨', val: windSpeed + ' ' + windUnit, lbl: 'Wind' });
154 if (a.showPressure) stats.push({ icon: '🌡', val: pressure + ' hPa', lbl: 'Pressure' });
155 if (a.showVisibility) stats.push({ icon: '👁', val: visibility, lbl: 'Visibility' });
156 statsHTML = '<div class="bkbg-ww-stats" style="margin-bottom:' + (a.showForecast ? '24' : '0') + 'px;">' +
157 stats.map(function (s) {
158 return '<div class="bkbg-ww-stat">' +
159 '<div class="bkbg-ww-stat-icon">' + s.icon + '</div>' +
160 '<div class="bkbg-ww-stat-val">' + s.val + '</div>' +
161 '<div class="bkbg-ww-stat-lbl">' + s.lbl + '</div>' +
162 '</div>';
163 }).join('') + '</div>';
164 }
165
166 var feelsLikeHTML = a.showFeelsLike
167 ? '<div class="bkbg-ww-feelslike">Feels like ' + feelsLike + deg + '&nbsp;&nbsp;·&nbsp;&nbsp;H: ' + tempMax + deg + '&nbsp;&nbsp;L: ' + tempMin + deg + '</div>'
168 : '';
169
170 var refreshBtn = '<button class="bkbg-ww-refresh-btn" data-ww-refresh>↻ Refresh</button>';
171
172 var html = '<div class="bkbg-ww-wrap bkbg-ww-' + a.layout + ' ' + bgClass + '" style="' + wrapStyle + '">' +
173 '<div class="bkbg-ww-card-inner" style="' + cardStyle + '">' +
174 '<div class="bkbg-ww-top">' +
175 '<div>' +
176 '<div class="bkbg-ww-city-label">📍 ' + cityName + '</div>' +
177 '<div class="bkbg-ww-temp">' + temp + deg + '</div>' +
178 '<div class="bkbg-ww-condition">' + condition + '</div>' +
179 '</div>' +
180 (a.showAnimatedIcon ? '<div class="bkbg-ww-icon-lg">' + weatherEmoji + '</div>' : '') +
181 '</div>' +
182 feelsLikeHTML +
183 statsHTML +
184 forecastHTML +
185 '<div style="text-align:right;margin-top:12px;">' + refreshBtn + '</div>' +
186 '</div>' +
187 '</div>';
188
189 self.root.innerHTML = html;
190 self.root.querySelector('[data-ww-refresh]').addEventListener('click', function () {
191 self.fetchWeather();
192 });
193 };
194
195 function iconToEmoji(code) {
196 if (!code) return '🌤';
197 var c = String(code);
198 if (c.startsWith('01d')) return '☀️';
199 if (c.startsWith('01n')) return '🌙';
200 if (c.startsWith('02')) return '�
201 ';
202 if (c.startsWith('03') || c.startsWith('04')) return '☁️';
203 if (c.startsWith('09') || c.startsWith('10')) return '🌧';
204 if (c.startsWith('11')) return '';
205 if (c.startsWith('13')) return '❄️';
206 if (c.startsWith('50')) return '🌫';
207 return '🌤';
208 }
209