diff --git a/server/scripts/index.js b/server/scripts/index.js index bfd5f4f..695e29f 100644 --- a/server/scripts/index.js +++ b/server/scripts/index.js @@ -1,5 +1,5 @@ 'use strict'; -/* globals NoSleep, states, navigation, UNITS */ +/* globals NoSleep, states, navigation, UNITS, utils */ document.addEventListener('DOMContentLoaded', () => { index.init(); }); @@ -170,35 +170,27 @@ const index = (() => { postMessage('units', Units); }; - const autocompleteOnSelect = (suggestion) => { - let request; - + const autocompleteOnSelect = async (suggestion) => { // Do not auto get the same city twice. if (this.previousSuggestionValue === suggestion.value) return; if (overrides[suggestion.value]) { doRedirectToGeometry(overrides[suggestion.value]); } else { - request = $.ajax({ -<<<<<<< Updated upstream - url: 'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find', -======= - url: location.protocol + 'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find', ->>>>>>> Stashed changes + const data = await utils.fetch.json('https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find', { data: { text: suggestion.value, magicKey: suggestion.data, f: 'json', }, }); - request.done((data) => { - const loc = data.locations[0]; - if (loc) { - doRedirectToGeometry(loc.feature.geometry); - } else { - alert('An unexpected error occurred. Please try a different search string.'); - } - }); + + const loc = data.locations[0]; + if (loc) { + doRedirectToGeometry(loc.feature.geometry); + } else { + alert('An unexpected error occurred. Please try a different search string.'); + } } }; @@ -501,8 +493,7 @@ const index = (() => { let data; try { - data = await $.ajax({ - url: location.protocol + '//geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/reverseGeocode', + data = await utils.fetch.json(location.protocol + '//geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/reverseGeocode', { data: { location: longitude + ',' + latitude, distance: 1000, // Find location up to 1 KM. diff --git a/server/scripts/modules/currentweather.js b/server/scripts/modules/currentweather.js index e1c94ff..e74b4e3 100644 --- a/server/scripts/modules/currentweather.js +++ b/server/scripts/modules/currentweather.js @@ -17,22 +17,14 @@ class CurrentWeather extends WeatherDisplay { let observations, station; try { // station observations - const observationsPromise = $.ajaxCORS({ - type: 'GET', - url: `https://api.weather.gov/stations/${weatherParameters.stationId}/observations`, + const observationsPromise = utils.fetch.json(`https://api.weather.gov/stations/${weatherParameters.stationId}/observations`,{ + cors: true, data: { limit: 2, }, - dataType: 'json', - crossDomain: true, }); // station info - const stationPromise = $.ajax({ - type: 'GET', - url: `https://api.weather.gov/stations/${weatherParameters.stationId}`, - dataType: 'json', - crossDomain: true, - }); + const stationPromise = utils.fetch.json(`https://api.weather.gov/stations/${weatherParameters.stationId}`); // wait for the promises to resolve [observations, station] = await Promise.all([observationsPromise, stationPromise]); @@ -40,7 +32,7 @@ class CurrentWeather extends WeatherDisplay { // TODO: add retry for further stations if observations are unavailable } catch (e) { console.error('Unable to get current observations'); - console.error(e.status, e.responseJSON); + console.error(e); this.setStatus(STATUS.failed); return; } diff --git a/server/scripts/modules/extendedforecast.js b/server/scripts/modules/extendedforecast.js index b7cd22e..45bfd79 100644 --- a/server/scripts/modules/extendedforecast.js +++ b/server/scripts/modules/extendedforecast.js @@ -25,14 +25,10 @@ class ExtendedForecast extends WeatherDisplay { if (navigation.units() === UNITS.metric) units = 'si'; let forecast; try { - forecast = await $.ajax({ - type: 'GET', - url: weatherParameters.forecast, + forecast = await utils.fetch.json(weatherParameters.forecast,{ data: { units, }, - dataType: 'json', - crossDomain: true, }); } catch (e) { console.error('Unable to get extended forecast'); diff --git a/server/scripts/modules/latestobservations.js b/server/scripts/modules/latestobservations.js index 175d020..c30767d 100644 --- a/server/scripts/modules/latestobservations.js +++ b/server/scripts/modules/latestobservations.js @@ -31,12 +31,7 @@ class LatestObservations extends WeatherDisplay { // get data for regional stations const allConditions = await Promise.all(regionalStations.map(async station => { try { - const data = await $.ajax({ - type: 'GET', - url: `https://api.weather.gov/stations/${station.id}/observations/latest`, - dataType: 'json', - crossDomain: true, - }); + const data = await utils.fetch.json(`https://api.weather.gov/stations/${station.id}/observations/latest`); // format the return values return Object.assign({}, data.properties, { StationId: station.id, diff --git a/server/scripts/modules/localforecast.js b/server/scripts/modules/localforecast.js index 67b752f..1a656ba 100644 --- a/server/scripts/modules/localforecast.js +++ b/server/scripts/modules/localforecast.js @@ -94,14 +94,10 @@ class LocalForecast extends WeatherDisplay { let units = 'us'; if (navigation.units() === UNITS.metric) units = 'si'; try { - return await $.ajax({ - type: 'GET', - url: weatherParameters.forecast, + return await utils.fetch.json(weatherParameters.forecast, { data: { units, }, - dataType: 'json', - crossDomain: true, }); } catch (e) { diff --git a/server/scripts/modules/navigation.js b/server/scripts/modules/navigation.js index 8f7fb99..3402f64 100644 --- a/server/scripts/modules/navigation.js +++ b/server/scripts/modules/navigation.js @@ -57,7 +57,7 @@ const navigation = (() => { const point = await utils.weather.getPoint(latLon.lat, latLon.lon); // get stations - const stations = utils.fetch.json(point.properties.observationStations); + const stations = await utils.fetch.json(point.properties.observationStations); const StationId = stations.features[0].properties.stationIdentifier; @@ -68,7 +68,6 @@ const navigation = (() => { city = city.split('/')[0]; } - // populate the weather parameters weatherParameters.latitude = latLon.lat; weatherParameters.longitude = latLon.lon; diff --git a/server/scripts/modules/radar.js b/server/scripts/modules/radar.js index ccb48e6..944ccff 100644 --- a/server/scripts/modules/radar.js +++ b/server/scripts/modules/radar.js @@ -59,15 +59,10 @@ class Radar extends WeatherDisplay { let radarHtml; try { // get a list of available radars - radarHtml = await $.ajaxCORS({ - type: 'GET', - url: baseUrl, - dataType: 'text', - crossDomain: true, - }); + radarHtml = await utils.fetch.text(baseUrl, {cors: true}); } catch (e) { - console.error('Unable to get list of radars'); - console.error(e.status, e.responseJSON); + console.log('Unable to get list of radars'); + console.error(e); this.setStatus(STATUS.failed); return; } @@ -143,19 +138,13 @@ class Radar extends WeatherDisplay { context.imageSmoothingEnabled = false; // get the image - const [blob, status, xhr] = await (()=>new Promise((resolve, reject) => { - $.ajaxCORS({ - type: 'GET', - url: baseUrl + url, - xhrFields: { - responseType: 'blob', - }, - crossDomain: true, - success: (blob, status, xhr) => resolve([blob,status,xhr]), - error: (xhr, status, e) => reject(e), - }); + const response = await fetch(utils.cors.rewriteUrl(baseUrl + url)); - }))(); + // test response + if (!response.ok) throw new Error(`Unable to fetch radar error ${response.status} ${response.statusText} from ${response.url}`); + + // get the blob + const blob = await response.blob(); // store the time const timeMatch = url.match(/_(\d{4})(\d\d)(\d\d)_(\d\d)(\d\d)_/); @@ -171,7 +160,7 @@ class Radar extends WeatherDisplay { zone: 'UTC', }).setZone(); } else { - time = DateTime.fromHTTP(xhr.getResponseHeader('Last-Modified')).setZone(); + time = DateTime.fromHTTP(response.headers.get('last-modified')).setZone(); } // assign to an html image element diff --git a/server/scripts/modules/regionalforecast.js b/server/scripts/modules/regionalforecast.js index b833ce3..43da263 100644 --- a/server/scripts/modules/regionalforecast.js +++ b/server/scripts/modules/regionalforecast.js @@ -74,11 +74,7 @@ class RegionalForecast extends WeatherDisplay { // start off the observation task const observationPromise = this.getRegionalObservation(point, city); - const forecast = await $.ajax({ - url: point.properties.forecast, - dataType: 'json', - crossDomain: true, - }); + const forecast = await utils.fetch.json(point.properties.forecast); // get XY on map for city const cityXY = this.getXYForCity(city, minMaxLatLon.maxLat, minMaxLatLon.minLon, weatherParameters.state); @@ -109,8 +105,8 @@ class RegionalForecast extends WeatherDisplay { this.buildForecast(forecast.properties.periods[2], city, cityXY), ]; } catch (e) { - console.log(`No regional forecast data for '${city.Name}'`); - console.error(e.status, e.responseJSON); + console.log(`No regional forecast data for '${city.name}'`); + console.log(e); return false; } }); @@ -151,22 +147,12 @@ class RegionalForecast extends WeatherDisplay { async getRegionalObservation (point, city) { try { // get stations - const stations = await $.ajax({ - type: 'GET', - url: point.properties.observationStations, - dataType: 'json', - crossDomain: true, - }); + const stations = await utils.fetch.json(point.properties.observationStations); // get the first station const station = stations.features[0].id; // get the observation data - const observation = await $.ajax({ - type: 'GET', - url: `${station}/observations/latest`, - dataType: 'json', - crossDomain: true, - }); + const observation = await utils.fetch.json(`${station}/observations/latest`); // preload the image utils.image.preload(icons.getWeatherRegionalIconFromIconLink(observation.properties.icon, !observation.properties.daytime)); // return the observation diff --git a/server/scripts/modules/travelforecast.js b/server/scripts/modules/travelforecast.js index 51445fe..fa7416b 100644 --- a/server/scripts/modules/travelforecast.js +++ b/server/scripts/modules/travelforecast.js @@ -35,11 +35,7 @@ class TravelForecast extends WeatherDisplay { try { // get point then forecast const point = await utils.weather.getPoint(city.Latitude, city.Longitude); - const forecast = await $.ajax({ - url: point.properties.forecast, - dataType: 'json', - crossDomain: true, - }); + const forecast = await utils.fetch.json(point.properties.forecast); // determine today or tomorrow (shift periods by 1 if tomorrow) const todayShift = forecast.properties.periods[0].isDaytime? 0:1; // return a pared-down forecast diff --git a/server/scripts/modules/utilities.js b/server/scripts/modules/utilities.js index 58e191c..4597bc9 100644 --- a/server/scripts/modules/utilities.js +++ b/server/scripts/modules/utilities.js @@ -7,16 +7,10 @@ const utils = (() => { // ****************************** weather data ******************************** const getPoint = async (lat, lon) => { try { - return await $.ajax({ - type: 'GET', - url: `https://api.weather.gov/points/${lat},${lon}`, - dataType: 'json', - crossDomain: true, - }); + return await json(`https://api.weather.gov/points/${lat},${lon}`); } catch (e) { - console.error('Unable to get point'); - console.error(lat,lon); - console.error(e.status, e.responseJSON); + console.log(`Unable to get point ${lat}, ${lon}`); + console.error(e); return false; } }; @@ -176,22 +170,56 @@ const utils = (() => { // ********************************* cors ******************************************** // rewrite some urls for local server const rewriteUrl = (url) => { - url = url.replace('https://api.weather.gov/', ''); - url = url.replace('https://radar.weather.gov/', ''); - url = url.replace('https://www.cpc.ncep.noaa.gov/', ''); + url = url.replace('https://api.weather.gov/', window.location.href); + url = url.replace('https://radar.weather.gov/', window.location.href); + url = url.replace('https://www.cpc.ncep.noaa.gov/', window.location.href); return url; }; // ********************************* fetch ******************************************** - const json = async (url) => { - const response = await fetch(url, { + const json = (url, params) => fetchAsync(url, 'json', params); + const text = (url, params) => fetchAsync(url, 'text', params); + const raw = (url, params) => fetchAsync(url, '', params); + const blob = (url, params) => fetchAsync(url, 'blob', params); + + const fetchAsync = async (_url, responseType, _params={}) => { + // combine default and provided parametersutils + const params = Object.assign({}, { method: 'GET', mode: 'cors', type: 'GET', - }); + }, + _params); + // build a url, including the rewrite for cors if necessary + let corsUrl = _url; + if (params.cors === true) corsUrl = rewriteUrl(_url); + const url = new URL(corsUrl); + // add parameters if necessary + if (params.data) { + Object.keys(params.data).forEach((key) => { + // get the value + const value = params.data[key]; + // add to the url + url.searchParams.append(key, value); + }); + } - if (!response.ok) throw new Error(`Fetch error ${response.status} ${response.statusText} while fetching ${url}`); - return await response.json(); + // make the request + const response = await fetch(url, params); + + // check for ok response + if (!response.ok) throw new Error(`Fetch error ${response.status} ${response.statusText} while fetching ${response.url}`); + // return the requested response + switch (responseType) { + case 'json': + return await response.json(); + case 'text': + return await response.text(); + case 'blob': + return await response.blob(); + default: + return response; + } }; // return an orderly object @@ -233,15 +261,9 @@ const utils = (() => { }, fetch: { json, - } + text, + raw, + blob, + }, }; -})(); - -// pass data through local server as CORS workaround -$.ajaxCORS = function (e) { - // modify the URL - e.url = utils.cors.rewriteUrl(e.url); - - // call the ajax function - return $.ajax(e); -}; \ No newline at end of file +})(); \ No newline at end of file diff --git a/version.js b/version.js index 0e73bc4..a9d7e97 100644 --- a/version.js +++ b/version.js @@ -1 +1 @@ -module.exports = '3.5.1'; \ No newline at end of file +module.exports = '3.6.0'; \ No newline at end of file