Compare commits
No commits in common. "ea8c3bf6022cb941e942f00aaaba94e16a92a168" and "439b792baf0779ceb1780fbc81ff5c59f30053ad" have entirely different histories.
ea8c3bf602
...
439b792baf
|
|
@ -1,7 +1,6 @@
|
||||||
import largeIcon from './icons/icons-large.mjs';
|
import largeIcon from './icons/icons-large.mjs';
|
||||||
import smallIcon from './icons/icons-small.mjs';
|
import smallIcon from './icons/icons-small.mjs';
|
||||||
import hourlyIcon from './icons/icons-hourly.mjs';
|
import hourlyIcon from './icons/icons-hourly.mjs';
|
||||||
import { withBasePath } from './utils/base-path.mjs';
|
|
||||||
|
|
||||||
const getWeatherGovTokenFromWmoCode = (code) => {
|
const getWeatherGovTokenFromWmoCode = (code) => {
|
||||||
switch (Number(code)) {
|
switch (Number(code)) {
|
||||||
|
|
@ -45,7 +44,7 @@ const getWeatherGovTokenFromWmoCode = (code) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildSyntheticIconUrl = (code, isDaytime = true) => withBasePath(`icons/land/${isDaytime ? 'day' : 'night'}/${getWeatherGovTokenFromWmoCode(code)}`);
|
const buildSyntheticIconUrl = (code, isDaytime = true) => `/icons/land/${isDaytime ? 'day' : 'night'}/${getWeatherGovTokenFromWmoCode(code)}`;
|
||||||
|
|
||||||
const getLargeIconFromWmoCode = (code, isDaytime = true) => largeIcon(buildSyntheticIconUrl(code, isDaytime), !isDaytime);
|
const getLargeIconFromWmoCode = (code, isDaytime = true) => largeIcon(buildSyntheticIconUrl(code, isDaytime), !isDaytime);
|
||||||
const getSmallIconFromWmoCode = (code, isDaytime = true) => smallIcon(buildSyntheticIconUrl(code, isDaytime), !isDaytime);
|
const getSmallIconFromWmoCode = (code, isDaytime = true) => smallIcon(buildSyntheticIconUrl(code, isDaytime), !isDaytime);
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import STATUS from './status.mjs';
|
||||||
import WeatherDisplay from './weatherdisplay.mjs';
|
import WeatherDisplay from './weatherdisplay.mjs';
|
||||||
import { registerDisplay } from './navigation.mjs';
|
import { registerDisplay } from './navigation.mjs';
|
||||||
import { debugFlag } from './utils/debug.mjs';
|
import { debugFlag } from './utils/debug.mjs';
|
||||||
import { withBasePath } from './utils/base-path.mjs';
|
|
||||||
|
|
||||||
const STORIES_PER_PAGE = 2;
|
const STORIES_PER_PAGE = 2;
|
||||||
const PAGE_DURATION_MS = 9000;
|
const PAGE_DURATION_MS = 9000;
|
||||||
|
|
@ -18,7 +17,7 @@ class LinuxNews extends WeatherDisplay {
|
||||||
if (!super.getData(weatherParameters, refresh)) return;
|
if (!super.getData(weatherParameters, refresh)) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await safeJson(withBasePath('api/linux-news'), {
|
const response = await safeJson('/api/linux-news', {
|
||||||
retryCount: 0,
|
retryCount: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import STATUS from './status.mjs';
|
||||||
import WeatherDisplay from './weatherdisplay.mjs';
|
import WeatherDisplay from './weatherdisplay.mjs';
|
||||||
import { registerDisplay } from './navigation.mjs';
|
import { registerDisplay } from './navigation.mjs';
|
||||||
import { debugFlag } from './utils/debug.mjs';
|
import { debugFlag } from './utils/debug.mjs';
|
||||||
import { withBasePath } from './utils/base-path.mjs';
|
|
||||||
|
|
||||||
const LINES_PER_PAGE = 4;
|
const LINES_PER_PAGE = 4;
|
||||||
const PAGE_DURATION_MS = 7000;
|
const PAGE_DURATION_MS = 7000;
|
||||||
|
|
@ -20,7 +19,7 @@ class ServerObservations extends WeatherDisplay {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Fetch server info from the API
|
// Fetch server info from the API
|
||||||
const response = await safeJson(withBasePath('api/server-info'), {
|
const response = await safeJson('/api/server-info', {
|
||||||
retryCount: 0,
|
retryCount: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
const normalizeBasePath = (pathname) => {
|
|
||||||
if (!pathname) return '/';
|
|
||||||
if (pathname.endsWith('/index.html')) {
|
|
||||||
const trimmed = pathname.slice(0, -'index.html'.length);
|
|
||||||
return trimmed.endsWith('/') ? trimmed : `${trimmed}/`;
|
|
||||||
}
|
|
||||||
if (pathname.endsWith('/')) return pathname;
|
|
||||||
const lastSlash = pathname.lastIndexOf('/');
|
|
||||||
if (lastSlash === -1) return '/';
|
|
||||||
return `${pathname.slice(0, lastSlash + 1)}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getBasePath = () => normalizeBasePath(window.location.pathname);
|
|
||||||
|
|
||||||
const withBasePath = (relativePath = '') => {
|
|
||||||
const sanitizedPath = relativePath.replace(/^\/+/, '');
|
|
||||||
const basePath = getBasePath();
|
|
||||||
if (basePath === '/') return `/${sanitizedPath}`;
|
|
||||||
return `${basePath}${sanitizedPath}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export {
|
|
||||||
getBasePath,
|
|
||||||
withBasePath,
|
|
||||||
};
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { rewriteUrl } from './url-rewrite.mjs';
|
import { rewriteUrl } from './url-rewrite.mjs';
|
||||||
import { withBasePath } from './base-path.mjs';
|
|
||||||
|
|
||||||
// Clear cache utility for client-side use
|
// Clear cache utility for client-side use
|
||||||
const clearCacheEntry = async (url, baseUrl = '') => {
|
const clearCacheEntry = async (url, baseUrl = '') => {
|
||||||
|
|
@ -16,7 +15,7 @@ const clearCacheEntry = async (url, baseUrl = '') => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the cache clear endpoint
|
// Call the cache clear endpoint
|
||||||
const fetchUrl = baseUrl ? `${baseUrl}/cache${cachePath}` : withBasePath(`cache${cachePath}`);
|
const fetchUrl = baseUrl ? `${baseUrl}/cache${cachePath}` : `/cache${cachePath}`;
|
||||||
const response = await fetch(fetchUrl, {
|
const response = await fetch(fetchUrl, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
// Data loader utility for fetching JSON data with cache-busting
|
// Data loader utility for fetching JSON data with cache-busting
|
||||||
|
|
||||||
import { withBasePath } from './base-path.mjs';
|
|
||||||
|
|
||||||
let dataCache = {};
|
let dataCache = {};
|
||||||
|
|
||||||
// Load data with version-based cache busting
|
// Load data with version-based cache busting
|
||||||
|
|
@ -11,7 +9,7 @@ const loadData = async (dataType, version = '') => {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const url = withBasePath(`data/${dataType}.json${version ? `?_=${version}` : ''}`);
|
const url = `/data/${dataType}.json${version ? `?_=${version}` : ''}`;
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,12 @@ import { loadData } from './data-loader.mjs';
|
||||||
import { getSmallIconFromWmoCode } from '../icons.mjs';
|
import { getSmallIconFromWmoCode } from '../icons.mjs';
|
||||||
import { getOpenMeteoObservationSnapshot } from './weather.mjs';
|
import { getOpenMeteoObservationSnapshot } from './weather.mjs';
|
||||||
import { temperature } from './units.mjs';
|
import { temperature } from './units.mjs';
|
||||||
import { withBasePath } from './base-path.mjs';
|
|
||||||
|
|
||||||
const getBaseMapUrl = () => (window.WS4KP_SERVER_AVAILABLE
|
const getBaseMapUrl = () => (window.WS4KP_SERVER_AVAILABLE
|
||||||
? withBasePath('arcgis-server/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}')
|
? '/arcgis-server/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}'
|
||||||
: 'https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}');
|
: 'https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}');
|
||||||
const getBoundaryMapUrl = () => (window.WS4KP_SERVER_AVAILABLE
|
const getBoundaryMapUrl = () => (window.WS4KP_SERVER_AVAILABLE
|
||||||
? withBasePath('arcgis-services/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/{z}/{y}/{x}')
|
? '/arcgis-services/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/{z}/{y}/{x}'
|
||||||
: 'https://services.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/{z}/{y}/{x}');
|
: 'https://services.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/{z}/{y}/{x}');
|
||||||
const DEFAULT_MAX_NEARBY_MARKERS = 7;
|
const DEFAULT_MAX_NEARBY_MARKERS = 7;
|
||||||
const MIN_CITY_DISTANCE_METERS = 25000;
|
const MIN_CITY_DISTANCE_METERS = 25000;
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@
|
||||||
|
|
||||||
import { safeJson } from './fetch.mjs';
|
import { safeJson } from './fetch.mjs';
|
||||||
import { debugFlag } from './debug.mjs';
|
import { debugFlag } from './debug.mjs';
|
||||||
import { withBasePath } from './base-path.mjs';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse MapClick date format to JavaScript Date
|
* Parse MapClick date format to JavaScript Date
|
||||||
|
|
@ -179,7 +178,7 @@ const convertMapClickIcon = (weatherImage) => {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return withBasePath(`icons/land/${timeOfDay}/${condition}?size=medium`);
|
return `/icons/land/${timeOfDay}/${condition}?size=medium`;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
import { withBasePath } from './base-path.mjs';
|
|
||||||
|
|
||||||
const THEME_STORAGE_KEY = 'settings-theme-select';
|
const THEME_STORAGE_KEY = 'settings-theme-select';
|
||||||
const DEFAULT_THEME = 'default';
|
const DEFAULT_THEME = 'default';
|
||||||
|
|
||||||
const BUILTIN_ASSETS = {
|
const BUILTIN_ASSETS = {
|
||||||
background1: 'images/backgrounds/1.png',
|
background1: '../images/backgrounds/1.png',
|
||||||
background1Chart: 'images/backgrounds/1-chart.png',
|
background1Chart: '../images/backgrounds/1-chart.png',
|
||||||
background2: 'images/backgrounds/2.png',
|
background2: '../images/backgrounds/2.png',
|
||||||
background3: 'images/backgrounds/3.png',
|
background3: '../images/backgrounds/3.png',
|
||||||
background4: 'images/backgrounds/4.png',
|
background4: '../images/backgrounds/4.png',
|
||||||
background5: 'images/backgrounds/5.png',
|
background5: '../images/backgrounds/5.png',
|
||||||
logoCorner: 'images/logos/logo-corner.png',
|
logoCorner: 'images/logos/logo-corner.png',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -23,33 +20,33 @@ const getStoredTheme = () => {
|
||||||
|
|
||||||
const getThemeAssetUrl = (themeName, assetKey) => {
|
const getThemeAssetUrl = (themeName, assetKey) => {
|
||||||
if (themeName === DEFAULT_THEME) {
|
if (themeName === DEFAULT_THEME) {
|
||||||
return withBasePath(BUILTIN_ASSETS[assetKey]);
|
return BUILTIN_ASSETS[assetKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
const themeAssetAvailability = getThemeAssets()[themeName] ?? {};
|
const themeAssetAvailability = getThemeAssets()[themeName] ?? {};
|
||||||
if (!themeAssetAvailability[assetKey]) {
|
if (!themeAssetAvailability[assetKey]) {
|
||||||
return withBasePath(BUILTIN_ASSETS[assetKey]);
|
return BUILTIN_ASSETS[assetKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (assetKey) {
|
switch (assetKey) {
|
||||||
case 'background1':
|
case 'background1':
|
||||||
return withBasePath(`themes/${themeName}/1.png`);
|
return `../themes/${themeName}/1.png`;
|
||||||
case 'background1Chart':
|
case 'background1Chart':
|
||||||
return withBasePath(`themes/${themeName}/1-chart.png`);
|
return `../themes/${themeName}/1-chart.png`;
|
||||||
case 'background2':
|
case 'background2':
|
||||||
return withBasePath(`themes/${themeName}/2.png`);
|
return `../themes/${themeName}/2.png`;
|
||||||
case 'background3':
|
case 'background3':
|
||||||
return withBasePath(`themes/${themeName}/3.png`);
|
return `../themes/${themeName}/3.png`;
|
||||||
case 'background4':
|
case 'background4':
|
||||||
return withBasePath(`themes/${themeName}/4.png`);
|
return `../themes/${themeName}/4.png`;
|
||||||
case 'background5':
|
case 'background5':
|
||||||
return withBasePath(`themes/${themeName}/5.png`);
|
return `../themes/${themeName}/5.png`;
|
||||||
case 'logoCorner':
|
case 'logoCorner':
|
||||||
return withBasePath(`themes/${themeName}/logo-corner.png`);
|
return `themes/${themeName}/logo-corner.png`;
|
||||||
default:
|
default:
|
||||||
return withBasePath(BUILTIN_ASSETS[assetKey]);
|
return BUILTIN_ASSETS[assetKey];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const applyTheme = (themeName) => {
|
const applyTheme = (themeName) => {
|
||||||
const selectedTheme = getAvailableThemes().includes(themeName) ? themeName : DEFAULT_THEME;
|
const selectedTheme = getAvailableThemes().includes(themeName) ? themeName : DEFAULT_THEME;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
// rewrite URLs to use local proxy server
|
// rewrite URLs to use local proxy server
|
||||||
import { withBasePath } from './base-path.mjs';
|
|
||||||
|
|
||||||
const rewriteUrl = (_url) => {
|
const rewriteUrl = (_url) => {
|
||||||
if (!_url) {
|
if (!_url) {
|
||||||
throw new Error(`rewriteUrl called with invalid argument: '${_url}' (${typeof _url})`);
|
throw new Error(`rewriteUrl called with invalid argument: '${_url}' (${typeof _url})`);
|
||||||
|
|
@ -27,44 +25,44 @@ const rewriteUrl = (_url) => {
|
||||||
if (url.origin === 'https://api.weather.gov') {
|
if (url.origin === 'https://api.weather.gov') {
|
||||||
url.protocol = window.location.protocol;
|
url.protocol = window.location.protocol;
|
||||||
url.host = window.location.host;
|
url.host = window.location.host;
|
||||||
url.pathname = withBasePath(`api${url.pathname}`);
|
url.pathname = `/api${url.pathname}`;
|
||||||
} else if (url.origin === 'https://forecast.weather.gov') {
|
} else if (url.origin === 'https://forecast.weather.gov') {
|
||||||
url.protocol = window.location.protocol;
|
url.protocol = window.location.protocol;
|
||||||
url.host = window.location.host;
|
url.host = window.location.host;
|
||||||
url.pathname = withBasePath(`forecast${url.pathname}`);
|
url.pathname = `/forecast${url.pathname}`;
|
||||||
} else if (url.origin === 'https://www.spc.noaa.gov') {
|
} else if (url.origin === 'https://www.spc.noaa.gov') {
|
||||||
url.protocol = window.location.protocol;
|
url.protocol = window.location.protocol;
|
||||||
url.host = window.location.host;
|
url.host = window.location.host;
|
||||||
url.pathname = withBasePath(`spc${url.pathname}`);
|
url.pathname = `/spc${url.pathname}`;
|
||||||
} else if (url.origin === 'https://radar.weather.gov') {
|
} else if (url.origin === 'https://radar.weather.gov') {
|
||||||
url.protocol = window.location.protocol;
|
url.protocol = window.location.protocol;
|
||||||
url.host = window.location.host;
|
url.host = window.location.host;
|
||||||
url.pathname = withBasePath(`radar${url.pathname}`);
|
url.pathname = `/radar${url.pathname}`;
|
||||||
} else if (url.origin === 'https://mesonet.agron.iastate.edu') {
|
} else if (url.origin === 'https://mesonet.agron.iastate.edu') {
|
||||||
url.protocol = window.location.protocol;
|
url.protocol = window.location.protocol;
|
||||||
url.host = window.location.host;
|
url.host = window.location.host;
|
||||||
url.pathname = withBasePath(`mesonet${url.pathname}`);
|
url.pathname = `/mesonet${url.pathname}`;
|
||||||
} else if (url.origin === 'https://api.open-meteo.com') {
|
} else if (url.origin === 'https://api.open-meteo.com') {
|
||||||
url.protocol = window.location.protocol;
|
url.protocol = window.location.protocol;
|
||||||
url.host = window.location.host;
|
url.host = window.location.host;
|
||||||
url.pathname = withBasePath(`open-meteo${url.pathname}`);
|
url.pathname = `/open-meteo${url.pathname}`;
|
||||||
} else if (url.origin === 'https://api.rainviewer.com') {
|
} else if (url.origin === 'https://api.rainviewer.com') {
|
||||||
url.protocol = window.location.protocol;
|
url.protocol = window.location.protocol;
|
||||||
url.host = window.location.host;
|
url.host = window.location.host;
|
||||||
url.pathname = withBasePath(`rainviewer${url.pathname}`);
|
url.pathname = `/rainviewer${url.pathname}`;
|
||||||
} else if (url.origin === 'https://server.arcgisonline.com') {
|
} else if (url.origin === 'https://server.arcgisonline.com') {
|
||||||
url.protocol = window.location.protocol;
|
url.protocol = window.location.protocol;
|
||||||
url.host = window.location.host;
|
url.host = window.location.host;
|
||||||
url.pathname = withBasePath(`arcgis-server${url.pathname}`);
|
url.pathname = `/arcgis-server${url.pathname}`;
|
||||||
} else if (url.origin === 'https://services.arcgisonline.com') {
|
} else if (url.origin === 'https://services.arcgisonline.com') {
|
||||||
url.protocol = window.location.protocol;
|
url.protocol = window.location.protocol;
|
||||||
url.host = window.location.host;
|
url.host = window.location.host;
|
||||||
url.pathname = withBasePath(`arcgis-services${url.pathname}`);
|
url.pathname = `/arcgis-services${url.pathname}`;
|
||||||
} else if (typeof OVERRIDES !== 'undefined' && OVERRIDES?.RADAR_HOST && url.origin === `https://${OVERRIDES.RADAR_HOST}`) {
|
} else if (typeof OVERRIDES !== 'undefined' && OVERRIDES?.RADAR_HOST && url.origin === `https://${OVERRIDES.RADAR_HOST}`) {
|
||||||
// Handle override radar host
|
// Handle override radar host
|
||||||
url.protocol = window.location.protocol;
|
url.protocol = window.location.protocol;
|
||||||
url.host = window.location.host;
|
url.host = window.location.host;
|
||||||
url.pathname = withBasePath(`mesonet${url.pathname}`);
|
url.pathname = `/mesonet${url.pathname}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 234 KiB |
|
Before Width: | Height: | Size: 269 KiB |
|
Before Width: | Height: | Size: 295 KiB |
|
Before Width: | Height: | Size: 244 KiB |
|
Before Width: | Height: | Size: 760 KiB |
|
Before Width: | Height: | Size: 225 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 234 KiB |
|
Before Width: | Height: | Size: 269 KiB |
|
Before Width: | Height: | Size: 295 KiB |
|
Before Width: | Height: | Size: 244 KiB |
|
Before Width: | Height: | Size: 760 KiB |
|
Before Width: | Height: | Size: 225 KiB |
|
Before Width: | Height: | Size: 13 KiB |