forked from extern/the-glorious-startpage
Add Geolocation for Weather (#25)
* add location mode ui option * toggleable locator * toggleable locator with working update * update and cleanup * readme * cleanup
This commit is contained in:
parent
57d8884baf
commit
1ca7c94480
15
README.md
15
README.md
@ -28,7 +28,7 @@
|
||||
+ Web Search Suggestions
|
||||
+ Mobile Support with Swipe Gestures
|
||||
+ Theme Settings - Change colors on-the-fly
|
||||
+ Weather Forecast - OpenWeatherMap Integration
|
||||
+ Weather Forecast - OpenWeatherMap and Geolocation Integration
|
||||
+ Search Engine Selection
|
||||
+ Dynamic Background
|
||||
+ Web Menu with Fuzzy Search
|
||||
@ -117,10 +117,17 @@ Setting up your OpenWeatherMap credential is a breeze.
|
||||
- OpenWeatherMap is the weather provider, so go to OpenWeatherMap's [website](https://home.openweathermap.org/).
|
||||
- Register, log-in, and then go [here](https://home.openweathermap.org/api_keys) to generate your very own API keys.
|
||||
|
||||
+ After getting you API key, you have to get your City ID.
|
||||
+ Put your API key and City ID in the `Weather Settings`.
|
||||
+ After this you can choose two locator modes - `Geolocation` and `City`.
|
||||
+ In City Mode, you have to get your City ID in OpenWeatherMap website.
|
||||
+ While `Geolocation` mode offers GPS tracking. You don't need to get an ID. Note that you must allow the location permission request.
|
||||
+ Put your API key in the `Weather Settings`.
|
||||
+ It's recommended to still put your City ID if you plan to use the `geolocation` mode.
|
||||
+ Apply.
|
||||
|
||||
**Note:**
|
||||
|
||||
+ If you're using firefox and you're planning to use the `geolocation`, make sure to set the value of `geo.provider.network.url` to `https://location.services.mozilla.com/v1/geolocate?key=test` in `about:config`. **Google changed its policies, so now it requires a valid API key when accessing their geolocation service. This tells us that you need a valid API key in place of** `%GOOGLE_LOCATION_SERVICE_API_KEY%`. - [Citation](https://stackoverflow.com/questions/61032115/unknown-error-acquiring-position-geolocationpositionerror-code-2-firefox-linux).
|
||||
|
||||
#### Changing the default search engine
|
||||
|
||||
Google is the default search engine of the search bar, if you want to change it to DuckDuckGo or something:
|
||||
@ -151,6 +158,8 @@ The background image changes based on time.
|
||||
|
||||
+ If you're using firefox and blur effect is not enabled, open `about:config`, accept the risks, find `layout.css.backdrop-filter.enabled`, and set it to true to enable it. Refresh the startpage.
|
||||
|
||||
+ If you're using firefox and planning to use the geolocation, set the value of `geo.provider.network.url` to `https://location.services.mozilla.com/v1/geolocate?key=test` in `about:config`.
|
||||
|
||||
+ The code could be better, this is my first time writing a startpage from the ground up. I will improve this from time to time.
|
||||
|
||||
+ Found a bug, error or do you have a suggestion? Feel free to open an issue or pull request.
|
||||
|
@ -46,6 +46,8 @@
|
||||
height: auto;
|
||||
width: 100%;
|
||||
margin-top: 5px;
|
||||
|
||||
transition: all var(--transition-speed);
|
||||
}
|
||||
|
||||
.weatherSettingsLabels {
|
||||
@ -55,6 +57,14 @@
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.hideWeatherSettings {
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: height var(--transition-speed),
|
||||
opacity var(--transition-speed);
|
||||
}
|
||||
|
||||
.weatherSettingsInputs {
|
||||
height: 32px;
|
||||
width: 100%;
|
||||
@ -76,7 +86,8 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#weatherSelectUnits {
|
||||
#weatherSelectUnits,
|
||||
#weatherSelectLocator {
|
||||
background: var(--base-container);
|
||||
color: var(--base-color);
|
||||
|
||||
@ -85,23 +96,27 @@
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
#weatherSelectUnits:hover {
|
||||
#weatherSelectUnits:hover,
|
||||
#weatherSelectLocator:hover {
|
||||
outline: none !important;
|
||||
cursor: pointer;
|
||||
background: var(--base-hover-bg) !important;
|
||||
}
|
||||
|
||||
#weatherSelectUnits:focus {
|
||||
#weatherSelectUnits:focus,
|
||||
#weatherSelectLocator:focus {
|
||||
outline: none !important;
|
||||
background: var(--base-focus-bg) !important;
|
||||
}
|
||||
|
||||
#weatherSelectUnits:active {
|
||||
#weatherSelectUnits:active,
|
||||
#weatherSelectLocator:active {
|
||||
outline: none !important;
|
||||
background: var(--base-active-bg) !important;
|
||||
}
|
||||
|
||||
#weatherSelectUnits option {
|
||||
#weatherSelectUnits option,
|
||||
#weatherSelectLocator option {
|
||||
color: initial;
|
||||
border: none;
|
||||
}
|
||||
|
@ -101,6 +101,14 @@
|
||||
<input type='text' class='weatherSettingsInputs' id='apiKeySet' autocomplete='off' placeholder='API KEY'/>
|
||||
</div>
|
||||
|
||||
<div class='weatherSettingsGroups' id='weatherSettingsUnitsSelect'>
|
||||
<label for='weatherSelectUnits' class='weatherSettingsLabels'>Locator Mode</label>
|
||||
<select class='weatherSettingsInputs' id='weatherSelectLocator'>
|
||||
<option value='geolocation'>Geolocation</option>
|
||||
<option value='city'>City</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class='weatherSettingsGroups' id='weatherSettingsCityID'>
|
||||
<label for='cityIDSet' class='weatherSettingsLabels'>City ID</label>
|
||||
<input type='text' class='weatherSettingsInputs' id='cityIDSet' autocomplete='off' placeholder='City ID'/>
|
||||
|
@ -163,7 +163,7 @@ class WeatherScreen {
|
||||
request.send();
|
||||
}
|
||||
|
||||
getWeatherData = (appID, cityID, units) => {
|
||||
getWeatherDataViaCity = (appID, cityID, units) => {
|
||||
|
||||
const requestString = `https://api.openweathermap.org/data/2.5/weather?APPID=${appID}&id=${cityID}&units=${units}`;
|
||||
|
||||
@ -173,7 +173,7 @@ class WeatherScreen {
|
||||
};
|
||||
|
||||
|
||||
getForecastData = (appID, cityID, units) => {
|
||||
getForecastDataViaCity = (appID, cityID, units) => {
|
||||
|
||||
const requestString = `https://api.openweathermap.org/data/2.5/forecast?APPID=${appID}&id=${cityID}&units=${units}`;
|
||||
|
||||
@ -182,6 +182,25 @@ class WeatherScreen {
|
||||
this._fetchOpenWeatherMapDate(requestString, this._processForecastData);
|
||||
}
|
||||
|
||||
getWeatherDataViaGeo = (appID, units, lon, lat) => {
|
||||
|
||||
const requestString = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&APPID=${appID}&units=${units}`;
|
||||
|
||||
this._tempSymbol = (units === 'metric') ? '°C' : '°F';
|
||||
|
||||
this._fetchOpenWeatherMapDate(requestString, this._processWeatherData);
|
||||
};
|
||||
|
||||
|
||||
getForecastDataViaGeo = (appID, units, lon, lat) => {
|
||||
|
||||
const requestString = `https://api.openweathermap.org/data/2.5/forecast?lat=${lat}&lon=${lon}&APPID=${appID}&units=${units}`;
|
||||
|
||||
this._tempSymbol = (units === 'metric') ? '°C' : '°F';
|
||||
|
||||
this._fetchOpenWeatherMapDate(requestString, this._processForecastData);
|
||||
}
|
||||
|
||||
_processForecastData = data => {
|
||||
|
||||
// Empty forecast container to avoid duplication
|
||||
|
@ -7,17 +7,35 @@ class WeatherSettings {
|
||||
this._appID = '';
|
||||
this._cityID = '';
|
||||
this._units = '';
|
||||
this._locatorMode = '';
|
||||
|
||||
// Geolocation data
|
||||
this._origLongitude = 0;
|
||||
this._origLatitude = 0;
|
||||
this._watchPositionID = 0;
|
||||
|
||||
this._watchGeoOptions = {
|
||||
enableHighAccuracy: false,
|
||||
timeout: 5000,
|
||||
maximumAge: 0
|
||||
};
|
||||
|
||||
this._apiKeySet = document.querySelector('#apiKeySet');
|
||||
this._cityIDSet = document.querySelector('#cityIDSet');
|
||||
|
||||
this._weatherSelectLocator = document.querySelector('#weatherSelectLocator');
|
||||
this._weatherSelectUnits = document.querySelector('#weatherSelectUnits');
|
||||
|
||||
this._weatherSettingsReset = document.querySelector('#weatherSettingsReset');
|
||||
this._weatherSettingsApply = document.querySelector('#weatherSettingsApply');
|
||||
|
||||
this.getWeatherData = weatherScreen.getWeatherData;
|
||||
this.getForecastData = weatherScreen.getForecastData;
|
||||
this._weatherSettingsCityIDGroup = document.querySelector('#weatherSettingsCityID');
|
||||
|
||||
this._getWeatherDataViaCity = weatherScreen.getWeatherDataViaCity;
|
||||
this._getForecastDataViaCity = weatherScreen.getForecastDataViaCity;
|
||||
|
||||
this._getWeatherDataViaGeo = weatherScreen.getWeatherDataViaGeo;
|
||||
this._getForecastDataViaGeo = weatherScreen.getForecastDataViaGeo;
|
||||
|
||||
this._init();
|
||||
}
|
||||
@ -26,6 +44,7 @@ class WeatherSettings {
|
||||
this._updateWeatherSettings();
|
||||
this._registerWeatherResetOnClickEvent();
|
||||
this._registerWeatherApplyOnClickEvent();
|
||||
this._registerWeatherSelectLocatorOnChangeEvent();
|
||||
}
|
||||
|
||||
// Clear credentials
|
||||
@ -33,6 +52,7 @@ class WeatherSettings {
|
||||
this._localStorage.removeItem('apiKey');
|
||||
this._localStorage.removeItem('cityID');
|
||||
this._localStorage.removeItem('units');
|
||||
this._localStorage.removeItem('locatorMode');
|
||||
}
|
||||
|
||||
// Reset textboxes
|
||||
@ -40,20 +60,23 @@ class WeatherSettings {
|
||||
this._apiKeySet.value = '';
|
||||
this._cityIDSet.value = '';
|
||||
this._weatherSelectUnits.value = 'metric';
|
||||
this._weatherSelectLocator.value = 'geolocation';
|
||||
}
|
||||
|
||||
// Apply credentials
|
||||
_applyWeatherSettings = (key, city, units) => {
|
||||
_applyWeatherSettings = (key, city, units, locator) => {
|
||||
this._localStorage.setItem('apiKey', key);
|
||||
this._localStorage.setItem('cityID', city);
|
||||
this._localStorage.setItem('units', units);
|
||||
this._localStorage.setItem('locatorMode', locator);
|
||||
}
|
||||
|
||||
// Update credential variables
|
||||
_updateCredentialVariables = () => {
|
||||
this._appID = localStorage.getItem('apiKey') || 'API Key';
|
||||
this._cityID = localStorage.getItem('cityID') || 'City ID';
|
||||
this._units = localStorage.getItem('units') || 'metric';
|
||||
this._appID = this._localStorage.getItem('apiKey') || 'API Key';
|
||||
this._cityID = this._localStorage.getItem('cityID') || 'City ID';
|
||||
this._units = this._localStorage.getItem('units') || 'metric';
|
||||
this._locatorMode = this._localStorage.getItem('locatorMode') || 'geolocation';
|
||||
}
|
||||
|
||||
// Update textbox placeholders
|
||||
@ -61,6 +84,108 @@ class WeatherSettings {
|
||||
this._apiKeySet.placeholder = this._appID;
|
||||
this._cityIDSet.placeholder = this._cityID;
|
||||
this._weatherSelectUnits.value = this._units;
|
||||
this._weatherSelectLocator.value = this._locatorMode;
|
||||
}
|
||||
|
||||
// Stop geolocating
|
||||
_stopGeolocating = () => {
|
||||
|
||||
// Unregister the handler
|
||||
navigator.geolocation.clearWatch(this._watchPositionID);
|
||||
|
||||
// Reset positions
|
||||
this._origLongitude = 0;
|
||||
this._origLatitude = 0;
|
||||
}
|
||||
|
||||
// You denied the permission request
|
||||
_deniedGeolocation = () => {
|
||||
|
||||
alert(`You denied the request to access your location. As a consequence for your action, ` +
|
||||
`you need to allow it on your browser's settings if you want to use the geolocation functionality. You can just use the City Mode, though.`);
|
||||
|
||||
}
|
||||
|
||||
// Watch
|
||||
_watchGeoSuccess = pos => {
|
||||
|
||||
const currentCoord = pos.coords;
|
||||
|
||||
if ((this._origLongitude !== currentCoord.longitude) || (this._origLatitude !== currentCoord.latitude)) {
|
||||
|
||||
console.log('update current position');
|
||||
|
||||
// Update origPositions
|
||||
this._origLongitude = currentCoord.longitude;
|
||||
this._origLatitude = currentCoord.latitude;
|
||||
|
||||
// fetch and update widget
|
||||
this._getWeatherDataViaGeo(this._appID, this._units, this._origLongitude, this._origLatitude);
|
||||
this._getForecastDataViaGeo(this._appID, this._units, this._origLongitude, this._origLatitude);
|
||||
}
|
||||
}
|
||||
|
||||
// Error
|
||||
_watchGeoError = err => {
|
||||
|
||||
console.warn('ERROR(' + err.code + '): ' + err.message);
|
||||
|
||||
if (err.code == err.PERMISSION_DENIED) {
|
||||
|
||||
this._deniedGeolocation();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Start watching location
|
||||
_watchGeoPosition = () => {
|
||||
this._watchPositionID = navigator.geolocation.watchPosition(this._watchGeoSuccess, this._watchGeoError, this._watchGeoOptions);
|
||||
}
|
||||
|
||||
// Check permission
|
||||
_checkGeoPermission = () => {
|
||||
|
||||
navigator.permissions.query({name:'geolocation'}).then(result => {
|
||||
|
||||
if ((result.state === 'prompt') || (result.state == 'granted')) {
|
||||
|
||||
this._watchGeoPosition();
|
||||
|
||||
} else if (result.state === 'denied') {
|
||||
|
||||
alert('Manually enable the geolocation in your browser settings. How? Who knows?');
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// Locator mode on change event
|
||||
_weatherSelectLocatorOnChangeEvent = e => {
|
||||
|
||||
this._locatorMode = this._weatherSelectLocator.options[this._weatherSelectLocator.selectedIndex].value;
|
||||
|
||||
if (this._locatorMode === 'geolocation') {
|
||||
|
||||
console.log('geolocation');
|
||||
|
||||
this._weatherSettingsCityIDGroup.classList.add('hideWeatherSettings');
|
||||
|
||||
} else if (this._locatorMode === 'city') {
|
||||
|
||||
console.log('city');
|
||||
|
||||
this._weatherSettingsCityIDGroup.classList.remove('hideWeatherSettings');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Register on change event
|
||||
_registerWeatherSelectLocatorOnChangeEvent = () => {
|
||||
|
||||
this._weatherSelectLocator.onchange = this._weatherSelectLocatorOnChangeEvent;
|
||||
|
||||
}
|
||||
|
||||
// Update weather settings
|
||||
@ -69,13 +194,35 @@ class WeatherSettings {
|
||||
// Update cred vars
|
||||
this._updateCredentialVariables();
|
||||
|
||||
if (this._locatorMode === 'geolocation') {
|
||||
|
||||
this._weatherSettingsCityIDGroup.classList.add('hideWeatherSettings');
|
||||
|
||||
if (navigator.geolocation) {
|
||||
|
||||
this._checkGeoPermission();
|
||||
|
||||
} else {
|
||||
|
||||
alert(`Oof! It seems your browser doesn't support geolocation.`);
|
||||
|
||||
}
|
||||
|
||||
} else if (this._locatorMode === 'city') {
|
||||
|
||||
this._weatherSettingsCityIDGroup.classList.remove('hideWeatherSettings');
|
||||
|
||||
// Stop geolocating
|
||||
this._stopGeolocating();
|
||||
|
||||
// Update weather forecast elements
|
||||
this.getWeatherData(this._appID, this._cityID, this._units);
|
||||
this.getForecastData(this._appID, this._cityID, this._units);
|
||||
this._getWeatherDataViaCity(this._appID, this._cityID, this._units);
|
||||
this._getForecastDataViaCity(this._appID, this._cityID, this._units);
|
||||
|
||||
}
|
||||
|
||||
this._deleteWeatherSettingsValue();
|
||||
this._updateWeatherSettingsPlaceholder();
|
||||
|
||||
}
|
||||
|
||||
// Reset
|
||||
@ -83,6 +230,10 @@ class WeatherSettings {
|
||||
// Reset keys
|
||||
this._clearWeatherCredentials();
|
||||
|
||||
// Stop geolocating
|
||||
this._stopGeolocating();
|
||||
|
||||
// Update
|
||||
this._updateCredentialVariables();
|
||||
this._deleteWeatherSettingsValue();
|
||||
this._updateWeatherSettingsPlaceholder();
|
||||
@ -96,7 +247,8 @@ class WeatherSettings {
|
||||
this._applyWeatherSettings(
|
||||
this._apiKeySet.value || this._apiKeySet.placeholder,
|
||||
this._cityIDSet.value || this._cityIDSet.placeholder,
|
||||
this._weatherSelectUnits.options[this._weatherSelectUnits.selectedIndex].value
|
||||
this._weatherSelectUnits.options[this._weatherSelectUnits.selectedIndex].value,
|
||||
this._weatherSelectLocator.options[this._weatherSelectLocator.selectedIndex].value
|
||||
);
|
||||
|
||||
this._updateWeatherSettings();
|
||||
|
Loading…
Reference in New Issue
Block a user