Compare commits

..

No commits in common. "ea8c3bf6022cb941e942f00aaaba94e16a92a168" and "439b792baf0779ceb1780fbc81ff5c59f30053ad" have entirely different histories.

24 changed files with 36 additions and 74 deletions

View file

@ -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);

View file

@ -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,
}); });

View file

@ -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,
}); });

View file

@ -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,
};

View file

@ -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',
}); });

View file

@ -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) {

View file

@ -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;

View file

@ -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`;
}; };
/** /**

View file

@ -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,31 +20,31 @@ 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];
} }
}; };

View file

@ -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;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 269 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 760 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 269 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 760 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB