Merge develop
|
@ -14,6 +14,14 @@ A string, but allows input of longer strings more comfortably (a text area)
|
|||
|
||||
A date
|
||||
|
||||
## direction
|
||||
|
||||
A geographical direction, in degrees. 0° is north, 90° is east, ... Will return a value between 0 (incl) and 360 (excl)
|
||||
|
||||
## length
|
||||
|
||||
A geographical length in meters (rounded at two points). Will give an extra minimap with a measurement tool. Arguments: [ zoomlevel, preferredBackgroundMapType (comma seperated) ], e.g. `["21", "map,photo"]
|
||||
|
||||
## wikidata
|
||||
|
||||
A wikidata identifier, e.g. Q42
|
||||
|
@ -30,10 +38,6 @@ A positive number or zero
|
|||
|
||||
A strict positive number
|
||||
|
||||
## direction
|
||||
|
||||
A geographical direction, in degrees. 0° is north, 90° is east, ... Will return a value between 0 (incl) and 360 (excl)
|
||||
|
||||
## float
|
||||
|
||||
A decimal
|
||||
|
|
|
@ -588,6 +588,25 @@
|
|||
"description": "Layer 'Bike stations (repair, pump or both)' shows manometer=broken with a fixed text, namely 'There is manometer but it is broken' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
|
||||
"value": "broken"
|
||||
},
|
||||
{
|
||||
"key": "level",
|
||||
"description": "Layer 'Bike stations (repair, pump or both)' shows and asks freeform values for key 'level' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')"
|
||||
},
|
||||
{
|
||||
"key": "location",
|
||||
"description": "Layer 'Bike stations (repair, pump or both)' shows location=underground with a fixed text, namely 'Located underground' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
|
||||
"value": "underground"
|
||||
},
|
||||
{
|
||||
"key": "level",
|
||||
"description": "Layer 'Bike stations (repair, pump or both)' shows level=0 with a fixed text, namely 'Located on the ground floor' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"key": "level",
|
||||
"description": "Layer 'Bike stations (repair, pump or both)' shows level=1 with a fixed text, namely 'Located on the first floor' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"key": "service:bicycle:cleaning:charge",
|
||||
"description": "Layer 'Bike stations (repair, pump or both)' shows and asks freeform values for key 'service:bicycle:cleaning:charge' (in the MapComplete.osm.be theme 'Cyclofix - an open map for cyclists')"
|
||||
|
|
55
Docs/TagInfo/mapcomplete_openwindpowermap.json
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"data_format": 1,
|
||||
"project": {
|
||||
"name": "MapComplete OpenWindPowerMap",
|
||||
"description": "A map for showing and editing wind turbines",
|
||||
"project_url": "https://mapcomplete.osm.be/openwindpowermap",
|
||||
"doc_url": "https://github.com/pietervdvn/MapComplete/tree/master/assets/themes/",
|
||||
"icon_url": "https://mapcomplete.osm.be/assets/themes/openwindpowermap/wind_turbine.svg",
|
||||
"contact_name": "Pieter Vander Vennet, Seppe Santens",
|
||||
"contact_email": "pietervdvn@posteo.net"
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"key": "generator:source",
|
||||
"description": "The MapComplete theme OpenWindPowerMap has a layer wind turbine showing features with this tag",
|
||||
"value": "wind"
|
||||
},
|
||||
{
|
||||
"key": "generator:output:electricity",
|
||||
"description": "Layer 'wind turbine' shows and asks freeform values for key 'generator:output:electricity' (in the MapComplete.osm.be theme 'OpenWindPowerMap')"
|
||||
},
|
||||
{
|
||||
"key": "operator",
|
||||
"description": "Layer 'wind turbine' shows and asks freeform values for key 'operator' (in the MapComplete.osm.be theme 'OpenWindPowerMap')"
|
||||
},
|
||||
{
|
||||
"key": "height",
|
||||
"description": "Layer 'wind turbine' shows and asks freeform values for key 'height' (in the MapComplete.osm.be theme 'OpenWindPowerMap')"
|
||||
},
|
||||
{
|
||||
"key": "rotor:diameter",
|
||||
"description": "Layer 'wind turbine' shows and asks freeform values for key 'rotor:diameter' (in the MapComplete.osm.be theme 'OpenWindPowerMap')"
|
||||
},
|
||||
{
|
||||
"key": "start_date",
|
||||
"description": "Layer 'wind turbine' shows and asks freeform values for key 'start_date' (in the MapComplete.osm.be theme 'OpenWindPowerMap')"
|
||||
},
|
||||
{
|
||||
"key": "image",
|
||||
"description": "The layer 'wind turbine allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
|
||||
},
|
||||
{
|
||||
"key": "mapillary",
|
||||
"description": "The layer 'wind turbine allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
|
||||
},
|
||||
{
|
||||
"key": "wikidata",
|
||||
"description": "The layer 'wind turbine allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
|
||||
},
|
||||
{
|
||||
"key": "wikipedia",
|
||||
"description": "The layer 'wind turbine allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -20,158 +20,138 @@ the URL-parameters are stated in the part between the `?` and the `#`. There are
|
|||
Finally, the URL-hash is the part after the `#`. It is `node/1234` in this case.
|
||||
|
||||
|
||||
backend
|
||||
---------
|
||||
|
||||
The OSM backend to use - can be used to redirect mapcomplete to the testing backend when using 'osm-test' The default value is _osm_
|
||||
|
||||
|
||||
test
|
||||
------
|
||||
|
||||
If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org The default value is _false_
|
||||
|
||||
|
||||
layout
|
||||
--------
|
||||
|
||||
The layout to load into MapComplete The default value is __
|
||||
|
||||
|
||||
userlayout
|
||||
------------
|
||||
|
||||
If not 'false', a custom (non-official) theme is loaded. This custom layout can be done in multiple ways:
|
||||
|
||||
- The hash of the URL contains a base64-encoded .json-file containing the theme definition
|
||||
- The hash of the URL contains a lz-compressed .json-file, as generated by the custom theme generator
|
||||
- The parameter itself is an URL, in which case that URL will be downloaded. It should point to a .json of a theme The default value is _false_
|
||||
|
||||
|
||||
layer-control-toggle
|
||||
layer-control-toggle
|
||||
----------------------
|
||||
|
||||
Whether or not the layer control is shown The default value is _false_
|
||||
Whether or not the layer control is shown The default value is _false_
|
||||
|
||||
|
||||
tab
|
||||
tab
|
||||
-----
|
||||
|
||||
The tab that is shown in the welcome-message. 0 = the explanation of the theme,1 = OSM-credits, 2 = sharescreen, 3 = more themes, 4 = about mapcomplete (user must be logged in and have >50 changesets) The default value is _0_
|
||||
The tab that is shown in the welcome-message. 0 = the explanation of the theme,1 = OSM-credits, 2 = sharescreen, 3 = more themes, 4 = about mapcomplete (user must be logged in and have >50 changesets) The default value is _0_
|
||||
|
||||
|
||||
z
|
||||
z
|
||||
---
|
||||
|
||||
The initial/current zoom level The default value is _14_
|
||||
The initial/current zoom level The default value is _0_
|
||||
|
||||
|
||||
lat
|
||||
lat
|
||||
-----
|
||||
|
||||
The initial/current latitude The default value is _51.2095_
|
||||
The initial/current latitude The default value is _0_
|
||||
|
||||
|
||||
lon
|
||||
lon
|
||||
-----
|
||||
|
||||
The initial/current longitude of the app The default value is _3.2228_
|
||||
The initial/current longitude of the app The default value is _0_
|
||||
|
||||
|
||||
fs-userbadge
|
||||
fs-userbadge
|
||||
--------------
|
||||
|
||||
Disables/Enables the user information pill (userbadge) at the top left. Disabling this disables logging in and thus disables editing all together, effectively putting MapComplete into read-only mode. The default value is _true_
|
||||
Disables/Enables the user information pill (userbadge) at the top left. Disabling this disables logging in and thus disables editing all together, effectively putting MapComplete into read-only mode. The default value is _true_
|
||||
|
||||
|
||||
fs-search
|
||||
fs-search
|
||||
-----------
|
||||
|
||||
Disables/Enables the search bar The default value is _true_
|
||||
Disables/Enables the search bar The default value is _true_
|
||||
|
||||
|
||||
fs-layers
|
||||
fs-layers
|
||||
-----------
|
||||
|
||||
Disables/Enables the layer control The default value is _true_
|
||||
Disables/Enables the layer control The default value is _true_
|
||||
|
||||
|
||||
fs-add-new
|
||||
fs-add-new
|
||||
------------
|
||||
|
||||
Disables/Enables the 'add new feature'-popup. (A theme without presets might not have it in the first place) The default value is _true_
|
||||
Disables/Enables the 'add new feature'-popup. (A theme without presets might not have it in the first place) The default value is _true_
|
||||
|
||||
|
||||
fs-welcome-message
|
||||
fs-welcome-message
|
||||
--------------------
|
||||
|
||||
Disables/enables the help menu or welcome message The default value is _true_
|
||||
Disables/enables the help menu or welcome message The default value is _true_
|
||||
|
||||
|
||||
fs-iframe
|
||||
fs-iframe
|
||||
-----------
|
||||
|
||||
Disables/Enables the iframe-popup The default value is _false_
|
||||
Disables/Enables the iframe-popup The default value is _false_
|
||||
|
||||
|
||||
fs-more-quests
|
||||
fs-more-quests
|
||||
----------------
|
||||
|
||||
Disables/Enables the 'More Quests'-tab in the welcome message The default value is _true_
|
||||
Disables/Enables the 'More Quests'-tab in the welcome message The default value is _true_
|
||||
|
||||
|
||||
fs-share-screen
|
||||
fs-share-screen
|
||||
-----------------
|
||||
|
||||
Disables/Enables the 'Share-screen'-tab in the welcome message The default value is _true_
|
||||
Disables/Enables the 'Share-screen'-tab in the welcome message The default value is _true_
|
||||
|
||||
|
||||
fs-geolocation
|
||||
fs-geolocation
|
||||
----------------
|
||||
|
||||
Disables/Enables the geolocation button The default value is _true_
|
||||
Disables/Enables the geolocation button The default value is _true_
|
||||
|
||||
|
||||
fs-all-questions
|
||||
fs-all-questions
|
||||
------------------
|
||||
|
||||
Always show all questions The default value is _false_
|
||||
Always show all questions The default value is _false_
|
||||
|
||||
|
||||
fs-export
|
||||
fs-export
|
||||
-----------
|
||||
|
||||
If set, enables the 'download'-button to download everything as geojson The default value is _false_
|
||||
If set, enables the 'download'-button to download everything as geojson The default value is _false_
|
||||
|
||||
|
||||
fake-user
|
||||
test
|
||||
------
|
||||
|
||||
If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org The default value is _false_
|
||||
|
||||
|
||||
fake-user
|
||||
-----------
|
||||
|
||||
If true, 'dryrun' mode is activated and a fake user account is loaded The default value is _false_
|
||||
If true, 'dryrun' mode is activated and a fake user account is loaded The default value is _false_
|
||||
|
||||
|
||||
debug
|
||||
debug
|
||||
-------
|
||||
|
||||
If true, shows some extra debugging help such as all the available tags on every object The default value is _false_
|
||||
If true, shows some extra debugging help such as all the available tags on every object The default value is _false_
|
||||
|
||||
|
||||
custom-css
|
||||
backend
|
||||
---------
|
||||
|
||||
The OSM backend to use - can be used to redirect mapcomplete to the testing backend when using 'osm-test' The default value is _osm_
|
||||
|
||||
|
||||
custom-css
|
||||
------------
|
||||
|
||||
If specified, the custom css from the given link will be loaded additionaly The default value is __
|
||||
If specified, the custom css from the given link will be loaded additionaly The default value is __
|
||||
|
||||
|
||||
background
|
||||
background
|
||||
------------
|
||||
|
||||
The id of the background layer to start with The default value is _osm_
|
||||
The id of the background layer to start with The default value is _osm_
|
||||
|
||||
|
||||
oauth_token
|
||||
-------------
|
||||
|
||||
Used to complete the login No default value set
|
||||
layer-<layer-id>
|
||||
------------------
|
||||
|
||||
|
|
|
@ -1,262 +1,265 @@
|
|||
import * as L from "leaflet";
|
||||
import { UIEventSource } from "../UIEventSource";
|
||||
import { Utils } from "../../Utils";
|
||||
import {UIEventSource} from "../UIEventSource";
|
||||
import {Utils} from "../../Utils";
|
||||
import Svg from "../../Svg";
|
||||
import Img from "../../UI/Base/Img";
|
||||
import { LocalStorageSource } from "../Web/LocalStorageSource";
|
||||
import {LocalStorageSource} from "../Web/LocalStorageSource";
|
||||
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||
import { VariableUiElement } from "../../UI/Base/VariableUIElement";
|
||||
import {VariableUiElement} from "../../UI/Base/VariableUIElement";
|
||||
|
||||
export default class GeoLocationHandler extends VariableUiElement {
|
||||
/**
|
||||
* Wether or not the geolocation is active, aka the user requested the current location
|
||||
* @private
|
||||
*/
|
||||
private readonly _isActive: UIEventSource<boolean>;
|
||||
/**
|
||||
* Wether or not the geolocation is active, aka the user requested the current location
|
||||
* @private
|
||||
*/
|
||||
private readonly _isActive: UIEventSource<boolean>;
|
||||
|
||||
/**
|
||||
* Wether or not the geolocation is locked, aka the user requested the current location and wants the crosshair to follow the user
|
||||
* @private
|
||||
*/
|
||||
private readonly _isLocked: UIEventSource<boolean>;
|
||||
/**
|
||||
* Wether or not the geolocation is locked, aka the user requested the current location and wants the crosshair to follow the user
|
||||
* @private
|
||||
*/
|
||||
private readonly _isLocked: UIEventSource<boolean>;
|
||||
|
||||
/**
|
||||
* The callback over the permission API
|
||||
* @private
|
||||
*/
|
||||
private readonly _permission: UIEventSource<string>;
|
||||
/***
|
||||
* The marker on the map, in order to update it
|
||||
* @private
|
||||
*/
|
||||
private _marker: L.Marker;
|
||||
/**
|
||||
* Literally: _currentGPSLocation.data != undefined
|
||||
* @private
|
||||
*/
|
||||
private readonly _hasLocation: UIEventSource<boolean>;
|
||||
private readonly _currentGPSLocation: UIEventSource<{
|
||||
latlng: any;
|
||||
accuracy: number;
|
||||
}>;
|
||||
/**
|
||||
* Kept in order to update the marker
|
||||
* @private
|
||||
*/
|
||||
private readonly _leafletMap: UIEventSource<L.Map>;
|
||||
/**
|
||||
* The date when the user requested the geolocation. If we have a location, it'll autozoom to it the first 30 secs
|
||||
* @private
|
||||
*/
|
||||
private _lastUserRequest: Date;
|
||||
/**
|
||||
* A small flag on localstorage. If the user previously granted the geolocation, it will be set.
|
||||
* On firefox, the permissions api is broken (probably fingerprint resistiance) and "granted + don't ask again" doesn't stick between sessions.
|
||||
*
|
||||
* Instead, we set this flag. If this flag is set upon loading the page, we start geolocating immediately.
|
||||
* If the user denies the geolocation this time, we unset this flag
|
||||
* @private
|
||||
*/
|
||||
private readonly _previousLocationGrant: UIEventSource<string>;
|
||||
private readonly _layoutToUse: UIEventSource<LayoutConfig>;
|
||||
/**
|
||||
* The callback over the permission API
|
||||
* @private
|
||||
*/
|
||||
private readonly _permission: UIEventSource<string>;
|
||||
/***
|
||||
* The marker on the map, in order to update it
|
||||
* @private
|
||||
*/
|
||||
private _marker: L.Marker;
|
||||
/**
|
||||
* Literally: _currentGPSLocation.data != undefined
|
||||
* @private
|
||||
*/
|
||||
private readonly _hasLocation: UIEventSource<boolean>;
|
||||
private readonly _currentGPSLocation: UIEventSource<{
|
||||
latlng: any;
|
||||
accuracy: number;
|
||||
}>;
|
||||
/**
|
||||
* Kept in order to update the marker
|
||||
* @private
|
||||
*/
|
||||
private readonly _leafletMap: UIEventSource<L.Map>;
|
||||
/**
|
||||
* The date when the user requested the geolocation. If we have a location, it'll autozoom to it the first 30 secs
|
||||
* @private
|
||||
*/
|
||||
private _lastUserRequest: Date;
|
||||
/**
|
||||
* A small flag on localstorage. If the user previously granted the geolocation, it will be set.
|
||||
* On firefox, the permissions api is broken (probably fingerprint resistiance) and "granted + don't ask again" doesn't stick between sessions.
|
||||
*
|
||||
* Instead, we set this flag. If this flag is set upon loading the page, we start geolocating immediately.
|
||||
* If the user denies the geolocation this time, we unset this flag
|
||||
* @private
|
||||
*/
|
||||
private readonly _previousLocationGrant: UIEventSource<string>;
|
||||
private readonly _layoutToUse: UIEventSource<LayoutConfig>;
|
||||
|
||||
constructor(
|
||||
currentGPSLocation: UIEventSource<{ latlng: any; accuracy: number }>,
|
||||
leafletMap: UIEventSource<L.Map>,
|
||||
layoutToUse: UIEventSource<LayoutConfig>
|
||||
) {
|
||||
const hasLocation = currentGPSLocation.map(
|
||||
(location) => location !== undefined
|
||||
);
|
||||
const previousLocationGrant = LocalStorageSource.Get(
|
||||
"geolocation-permissions"
|
||||
);
|
||||
const isActive = new UIEventSource<boolean>(false);
|
||||
const isLocked = new UIEventSource<boolean>(false);
|
||||
|
||||
super(
|
||||
hasLocation.map(
|
||||
(hasLocationData) => {
|
||||
if (isLocked.data) {
|
||||
return Svg.crosshair_locked_ui();
|
||||
} else if (hasLocationData) {
|
||||
return Svg.crosshair_blue_ui();
|
||||
} else if (isActive.data) {
|
||||
return Svg.crosshair_blue_center_ui();
|
||||
} else {
|
||||
return Svg.crosshair_ui();
|
||||
}
|
||||
},
|
||||
[isActive, isLocked]
|
||||
)
|
||||
);
|
||||
this._isActive = isActive;
|
||||
this._isLocked = isLocked;
|
||||
this._permission = new UIEventSource<string>("");
|
||||
this._previousLocationGrant = previousLocationGrant;
|
||||
this._currentGPSLocation = currentGPSLocation;
|
||||
this._leafletMap = leafletMap;
|
||||
this._layoutToUse = layoutToUse;
|
||||
this._hasLocation = hasLocation;
|
||||
const self = this;
|
||||
|
||||
const currentPointer = this._isActive.map(
|
||||
(isActive) => {
|
||||
if (isActive && !self._hasLocation.data) {
|
||||
return "cursor-wait";
|
||||
}
|
||||
return "cursor-pointer";
|
||||
},
|
||||
[this._hasLocation]
|
||||
);
|
||||
currentPointer.addCallbackAndRun((pointerClass) => {
|
||||
self.SetClass(pointerClass);
|
||||
});
|
||||
|
||||
this.onClick(() => {
|
||||
if (self._hasLocation.data) {
|
||||
self._isLocked.setData(!self._isLocked.data);
|
||||
}
|
||||
self.init(true);
|
||||
});
|
||||
this.init(false);
|
||||
|
||||
this._currentGPSLocation.addCallback((location) => {
|
||||
self._previousLocationGrant.setData("granted");
|
||||
|
||||
const timeSinceRequest =
|
||||
(new Date().getTime() - (self._lastUserRequest?.getTime() ?? 0)) / 1000;
|
||||
if (timeSinceRequest < 30) {
|
||||
self.MoveToCurrentLoction(16);
|
||||
} else if (self._isLocked.data) {
|
||||
self.MoveToCurrentLoction();
|
||||
}
|
||||
|
||||
let color = "#1111cc";
|
||||
try {
|
||||
color = getComputedStyle(document.body).getPropertyValue(
|
||||
"--catch-detail-color"
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
const icon = L.icon({
|
||||
iconUrl: Img.AsData(Svg.crosshair.replace(/#000000/g, color)),
|
||||
iconSize: [40, 40], // size of the icon
|
||||
iconAnchor: [20, 20], // point of the icon which will correspond to marker's location
|
||||
});
|
||||
|
||||
const map = self._leafletMap.data;
|
||||
|
||||
const newMarker = L.marker(location.latlng, { icon: icon });
|
||||
newMarker.addTo(map);
|
||||
|
||||
if (self._marker !== undefined) {
|
||||
map.removeLayer(self._marker);
|
||||
}
|
||||
self._marker = newMarker;
|
||||
});
|
||||
}
|
||||
|
||||
private init(askPermission: boolean) {
|
||||
const self = this;
|
||||
|
||||
if (self._isActive.data) {
|
||||
self.MoveToCurrentLoction(16);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
navigator?.permissions
|
||||
?.query({ name: "geolocation" })
|
||||
?.then(function (status) {
|
||||
console.log("Geolocation is already", status);
|
||||
if (status.state === "granted") {
|
||||
self.StartGeolocating(false);
|
||||
}
|
||||
self._permission.setData(status.state);
|
||||
status.onchange = function () {
|
||||
self._permission.setData(status.state);
|
||||
};
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
if (askPermission) {
|
||||
self.StartGeolocating(true);
|
||||
} else if (this._previousLocationGrant.data === "granted") {
|
||||
this._previousLocationGrant.setData("");
|
||||
self.StartGeolocating(false);
|
||||
}
|
||||
}
|
||||
|
||||
private MoveToCurrentLoction(targetZoom?: number) {
|
||||
const location = this._currentGPSLocation.data;
|
||||
this._lastUserRequest = undefined;
|
||||
|
||||
if (
|
||||
this._currentGPSLocation.data.latlng[0] === 0 &&
|
||||
this._currentGPSLocation.data.latlng[1] === 0
|
||||
constructor(
|
||||
currentGPSLocation: UIEventSource<{ latlng: any; accuracy: number }>,
|
||||
leafletMap: UIEventSource<L.Map>,
|
||||
layoutToUse: UIEventSource<LayoutConfig>
|
||||
) {
|
||||
console.debug("Not moving to GPS-location: it is null island");
|
||||
return;
|
||||
}
|
||||
const hasLocation = currentGPSLocation.map(
|
||||
(location) => location !== undefined
|
||||
);
|
||||
const previousLocationGrant = LocalStorageSource.Get(
|
||||
"geolocation-permissions"
|
||||
);
|
||||
const isActive = new UIEventSource<boolean>(false);
|
||||
const isLocked = new UIEventSource<boolean>(false);
|
||||
|
||||
// We check that the GPS location is not out of bounds
|
||||
const b = this._layoutToUse.data.lockLocation;
|
||||
let inRange = true;
|
||||
if (b) {
|
||||
if (b !== true) {
|
||||
// B is an array with our locklocation
|
||||
inRange =
|
||||
b[0][0] <= location.latlng[0] &&
|
||||
location.latlng[0] <= b[1][0] &&
|
||||
b[0][1] <= location.latlng[1] &&
|
||||
location.latlng[1] <= b[1][1];
|
||||
}
|
||||
}
|
||||
if (!inRange) {
|
||||
console.log(
|
||||
"Not zooming to GPS location: out of bounds",
|
||||
b,
|
||||
location.latlng
|
||||
);
|
||||
} else {
|
||||
this._leafletMap.data.setView(location.latlng, targetZoom);
|
||||
}
|
||||
}
|
||||
super(
|
||||
hasLocation.map(
|
||||
(hasLocationData) => {
|
||||
if (isLocked.data) {
|
||||
return Svg.crosshair_locked_ui();
|
||||
} else if (hasLocationData) {
|
||||
return Svg.crosshair_blue_ui();
|
||||
} else if (isActive.data) {
|
||||
return Svg.crosshair_blue_center_ui();
|
||||
} else {
|
||||
return Svg.crosshair_ui();
|
||||
}
|
||||
},
|
||||
[isActive, isLocked]
|
||||
)
|
||||
);
|
||||
this._isActive = isActive;
|
||||
this._isLocked = isLocked;
|
||||
this._permission = new UIEventSource<string>("");
|
||||
this._previousLocationGrant = previousLocationGrant;
|
||||
this._currentGPSLocation = currentGPSLocation;
|
||||
this._leafletMap = leafletMap;
|
||||
this._layoutToUse = layoutToUse;
|
||||
this._hasLocation = hasLocation;
|
||||
const self = this;
|
||||
|
||||
private StartGeolocating(zoomToGPS = true) {
|
||||
const self = this;
|
||||
console.log("Starting geolocation");
|
||||
|
||||
this._lastUserRequest = zoomToGPS ? new Date() : new Date(0);
|
||||
if (self._permission.data === "denied") {
|
||||
self._previousLocationGrant.setData("");
|
||||
return "";
|
||||
}
|
||||
if (this._currentGPSLocation.data !== undefined) {
|
||||
this.MoveToCurrentLoction(16);
|
||||
}
|
||||
|
||||
console.log("Searching location using GPS");
|
||||
|
||||
if (self._isActive.data) {
|
||||
return;
|
||||
}
|
||||
self._isActive.setData(true);
|
||||
|
||||
navigator.geolocation.watchPosition(
|
||||
function (position) {
|
||||
self._currentGPSLocation.setData({
|
||||
latlng: [position.coords.latitude, position.coords.longitude],
|
||||
accuracy: position.coords.accuracy,
|
||||
const currentPointer = this._isActive.map(
|
||||
(isActive) => {
|
||||
if (isActive && !self._hasLocation.data) {
|
||||
return "cursor-wait";
|
||||
}
|
||||
return "cursor-pointer";
|
||||
},
|
||||
[this._hasLocation]
|
||||
);
|
||||
currentPointer.addCallbackAndRun((pointerClass) => {
|
||||
self.SetClass(pointerClass);
|
||||
});
|
||||
},
|
||||
function () {
|
||||
console.warn("Could not get location with navigator.geolocation");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
this.onClick(() => {
|
||||
if (self._hasLocation.data) {
|
||||
self._isLocked.setData(!self._isLocked.data);
|
||||
}
|
||||
self.init(true);
|
||||
});
|
||||
this.init(false);
|
||||
|
||||
this._currentGPSLocation.addCallback((location) => {
|
||||
self._previousLocationGrant.setData("granted");
|
||||
|
||||
const timeSinceRequest =
|
||||
(new Date().getTime() - (self._lastUserRequest?.getTime() ?? 0)) / 1000;
|
||||
if (timeSinceRequest < 30) {
|
||||
self.MoveToCurrentLoction(16);
|
||||
} else if (self._isLocked.data) {
|
||||
self.MoveToCurrentLoction();
|
||||
}
|
||||
|
||||
let color = "#1111cc";
|
||||
try {
|
||||
color = getComputedStyle(document.body).getPropertyValue(
|
||||
"--catch-detail-color"
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
const icon = L.icon({
|
||||
iconUrl: Img.AsData(Svg.crosshair.replace(/#000000/g, color)),
|
||||
iconSize: [40, 40], // size of the icon
|
||||
iconAnchor: [20, 20], // point of the icon which will correspond to marker's location
|
||||
});
|
||||
|
||||
const map = self._leafletMap.data;
|
||||
|
||||
const newMarker = L.marker(location.latlng, {icon: icon});
|
||||
newMarker.addTo(map);
|
||||
|
||||
if (self._marker !== undefined) {
|
||||
map.removeLayer(self._marker);
|
||||
}
|
||||
self._marker = newMarker;
|
||||
});
|
||||
}
|
||||
|
||||
private init(askPermission: boolean) {
|
||||
const self = this;
|
||||
|
||||
if (self._isActive.data) {
|
||||
self.MoveToCurrentLoction(16);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
navigator?.permissions
|
||||
?.query({name: "geolocation"})
|
||||
?.then(function (status) {
|
||||
console.log("Geolocation is already", status);
|
||||
if (status.state === "granted") {
|
||||
self.StartGeolocating(false);
|
||||
}
|
||||
self._permission.setData(status.state);
|
||||
status.onchange = function () {
|
||||
self._permission.setData(status.state);
|
||||
};
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
if (askPermission) {
|
||||
self.StartGeolocating(true);
|
||||
} else if (this._previousLocationGrant.data === "granted") {
|
||||
this._previousLocationGrant.setData("");
|
||||
self.StartGeolocating(false);
|
||||
}
|
||||
}
|
||||
|
||||
private MoveToCurrentLoction(targetZoom?: number) {
|
||||
const location = this._currentGPSLocation.data;
|
||||
this._lastUserRequest = undefined;
|
||||
|
||||
if (
|
||||
this._currentGPSLocation.data.latlng[0] === 0 &&
|
||||
this._currentGPSLocation.data.latlng[1] === 0
|
||||
) {
|
||||
console.debug("Not moving to GPS-location: it is null island");
|
||||
return;
|
||||
}
|
||||
|
||||
// We check that the GPS location is not out of bounds
|
||||
const b = this._layoutToUse.data.lockLocation;
|
||||
let inRange = true;
|
||||
if (b) {
|
||||
if (b !== true) {
|
||||
// B is an array with our locklocation
|
||||
inRange =
|
||||
b[0][0] <= location.latlng[0] &&
|
||||
location.latlng[0] <= b[1][0] &&
|
||||
b[0][1] <= location.latlng[1] &&
|
||||
location.latlng[1] <= b[1][1];
|
||||
}
|
||||
}
|
||||
if (!inRange) {
|
||||
console.log(
|
||||
"Not zooming to GPS location: out of bounds",
|
||||
b,
|
||||
location.latlng
|
||||
);
|
||||
} else {
|
||||
this._leafletMap.data.setView(location.latlng, targetZoom);
|
||||
}
|
||||
}
|
||||
|
||||
private StartGeolocating(zoomToGPS = true) {
|
||||
const self = this;
|
||||
console.log("Starting geolocation");
|
||||
|
||||
this._lastUserRequest = zoomToGPS ? new Date() : new Date(0);
|
||||
if (self._permission.data === "denied") {
|
||||
self._previousLocationGrant.setData("");
|
||||
return "";
|
||||
}
|
||||
if (this._currentGPSLocation.data !== undefined) {
|
||||
this.MoveToCurrentLoction(16);
|
||||
}
|
||||
|
||||
console.log("Searching location using GPS");
|
||||
|
||||
if (self._isActive.data) {
|
||||
return;
|
||||
}
|
||||
self._isActive.setData(true);
|
||||
|
||||
navigator.geolocation.watchPosition(
|
||||
function (position) {
|
||||
self._currentGPSLocation.setData({
|
||||
latlng: [position.coords.latitude, position.coords.longitude],
|
||||
accuracy: position.coords.accuracy,
|
||||
});
|
||||
},
|
||||
function () {
|
||||
console.warn("Could not get location with navigator.geolocation");
|
||||
},
|
||||
{
|
||||
enableHighAccuracy: true
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Utils } from "../Utils";
|
|||
|
||||
export default class Constants {
|
||||
|
||||
public static vNumber = "0.8.4/bike-infra";
|
||||
public static vNumber = "0.8.4a";
|
||||
|
||||
// The user journey states thresholds when a new feature gets unlocked
|
||||
public static userJourney = {
|
||||
|
|
|
@ -517,7 +517,6 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/themes/benches/bench_poi.svg",
|
||||
"mappings": []
|
||||
|
|
|
@ -126,7 +126,6 @@
|
|||
}
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/themes/benches/bench_public_transport.svg"
|
||||
},
|
||||
|
|
|
@ -210,7 +210,6 @@
|
|||
},
|
||||
"description"
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 1,
|
||||
"presets": [
|
||||
{
|
||||
"title": {
|
||||
|
|
|
@ -293,7 +293,6 @@
|
|||
}
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/layers/bike_cafe/bike_cafe.svg"
|
||||
},
|
||||
|
|
|
@ -63,7 +63,6 @@
|
|||
}
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/layers/bike_monitoring_station/monitoring_station.svg"
|
||||
},
|
||||
|
|
|
@ -601,7 +601,6 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 1,
|
||||
"presets": [
|
||||
{
|
||||
"title": {
|
||||
|
|
|
@ -56,7 +56,6 @@
|
|||
"phone",
|
||||
"opening_hours"
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/layers/bike_themed_object/other_services.svg"
|
||||
},
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
"tagRenderings": [
|
||||
"images"
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/layers/information_board/board.svg"
|
||||
},
|
||||
|
|
|
@ -159,7 +159,6 @@
|
|||
}
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/layers/map/map.svg",
|
||||
"mappings": [
|
||||
|
|
|
@ -383,7 +383,6 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 10,
|
||||
"wayHandling": 2,
|
||||
"icon": {
|
||||
"render": "./assets/themes/buurtnatuur/nature_reserve.svg"
|
||||
|
|
|
@ -72,7 +72,6 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "circle:#e6cf39;./assets/layers/picnic_table/picnic_table.svg"
|
||||
},
|
||||
|
|
|
@ -87,7 +87,6 @@
|
|||
"render": "{reviews(name, play_forest)}"
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"hideFromOverview": false,
|
||||
"icon": {
|
||||
"render": "./assets/layers/play_forest/icon.svg"
|
||||
|
|
|
@ -437,7 +437,6 @@
|
|||
"render": "{reviews(name, playground)}"
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/themes/playgrounds/playground.svg"
|
||||
},
|
||||
|
|
|
@ -215,7 +215,6 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"width": {
|
||||
"render": "7"
|
||||
},
|
||||
|
|
|
@ -383,7 +383,6 @@
|
|||
"render": "{reviews(name, sportpitch)}"
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "circle:white;./assets/layers/sport_pitch/sport_pitch.svg",
|
||||
"mappings": [
|
||||
|
|
|
@ -421,7 +421,6 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/themes/surveillance_cameras/logo.svg",
|
||||
"mappings": [
|
||||
|
|
|
@ -449,7 +449,6 @@
|
|||
}
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "circle:#ffffff;./assets/themes/trees/unknown.svg",
|
||||
"mappings": [
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
[
|
||||
{
|
||||
"authors": [
|
||||
"Pieter Vander Vennet"
|
||||
],
|
||||
"path": "length-crosshair.svg",
|
||||
"license": "CC0",
|
||||
"sources": []
|
||||
},
|
||||
{
|
||||
"authors": [
|
||||
"Pieter Vander Vennet"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"id": "artworks",
|
||||
"id": "artwork",
|
||||
"version": "2020-08-30",
|
||||
"title": {
|
||||
"en": "Open Artwork Map",
|
||||
|
@ -429,4 +429,4 @@
|
|||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 593 KiB After Width: | Height: | Size: 593 KiB |
|
@ -521,7 +521,6 @@
|
|||
"questions",
|
||||
"reviews"
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "circle:white;./assets/themes/campersites/caravan.svg",
|
||||
"mappings": [
|
||||
|
@ -862,7 +861,6 @@
|
|||
}
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "circle:white;./assets/themes/campersites/sanitary_dump_station.svg"
|
||||
},
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
@ -307,7 +307,6 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "pin:#fff;./assets/themes/charging_stations/plug.svg",
|
||||
"mappings": [
|
||||
|
|
|
@ -140,7 +140,6 @@
|
|||
"phone",
|
||||
"opening_hours"
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/themes/climbing/club.svg"
|
||||
},
|
||||
|
@ -280,7 +279,6 @@
|
|||
"opening_hours",
|
||||
"reviews"
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/themes/climbing/climbing_gym.svg"
|
||||
},
|
||||
|
@ -471,7 +469,6 @@
|
|||
},
|
||||
"reviews"
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "circle:white;./assets/themes/climbing/climbing_route.svg"
|
||||
},
|
||||
|
@ -695,7 +692,6 @@
|
|||
},
|
||||
"reviews"
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/themes/climbing/climbing_no_rope.svg"
|
||||
},
|
||||
|
@ -850,7 +846,6 @@
|
|||
}
|
||||
],
|
||||
"icon": "./assets/themes/climbing/climbing_unknown.svg",
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"width": {
|
||||
"render": "2"
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"id": "fietsstraten",
|
||||
"id": "cyclestreets",
|
||||
"version": "2020-08-30",
|
||||
"title": {
|
||||
"nl": "Fietsstraten",
|
||||
|
@ -68,7 +68,7 @@
|
|||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "Deze straat is een fietsstraat",
|
||||
"nl": "Deze straat i een fietsstraat",
|
||||
"en": "This street is a cyclestreet",
|
||||
"ja": "この通りはcyclestreetだ",
|
||||
"nb_NO": "Denne gaten er en sykkelvei"
|
||||
|
@ -279,4 +279,4 @@
|
|||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -330,7 +330,6 @@
|
|||
}
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "circle:white;./assets/themes/facadegardens/geveltuin.svg",
|
||||
"mappings": [
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"id": "boomgaarden",
|
||||
"id": "fruit_trees",
|
||||
"title": {
|
||||
"nl": "Open Boomgaardenkaart"
|
||||
},
|
||||
|
@ -43,7 +43,6 @@
|
|||
"tagRenderings": [
|
||||
"images"
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/themes/buurtnatuur/forest.svg"
|
||||
},
|
||||
|
@ -143,7 +142,6 @@
|
|||
}
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/themes/fruit_trees/fruit_tree.svg"
|
||||
},
|
||||
|
@ -172,4 +170,4 @@
|
|||
}
|
||||
],
|
||||
"roamingRenderings": []
|
||||
}
|
||||
}
|
||||
|
|
|
@ -173,7 +173,6 @@
|
|||
}
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"label": {
|
||||
"mappings": [
|
||||
{
|
||||
|
|
|
@ -258,7 +258,6 @@
|
|||
},
|
||||
"images"
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/themes/hailhydrant/hydrant.svg"
|
||||
},
|
||||
|
@ -365,7 +364,6 @@
|
|||
},
|
||||
"images"
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/themes/hailhydrant/Twemoji12_1f9ef.svg"
|
||||
},
|
||||
|
@ -568,7 +566,6 @@
|
|||
},
|
||||
"images"
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/themes/hailhydrant/Twemoji12_1f692.svg"
|
||||
},
|
||||
|
@ -744,7 +741,6 @@
|
|||
},
|
||||
"images"
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/themes/hailhydrant/Twemoji_1f691.svg"
|
||||
},
|
||||
|
|
|
@ -305,7 +305,6 @@
|
|||
"questions",
|
||||
"reviews"
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/themes/shops/shop.svg"
|
||||
},
|
||||
|
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
@ -147,7 +147,6 @@
|
|||
"render": "<span style='border: 1px solid black; border-radius: 0.5em; padding: 0.25em;'><b>{_width:needed}m</b> nodig in het totaal</span>"
|
||||
}
|
||||
],
|
||||
"hideUnderlayingFeaturesMinPercentage": 0,
|
||||
"icon": {
|
||||
"render": "./assets/themes/widths/icon.svg"
|
||||
},
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
"loginWithOpenStreetMap": "Login with OpenStreetMap",
|
||||
"welcomeBack": "You are logged in, welcome back!",
|
||||
"loginToStart": "Login to answer this question",
|
||||
"openStreetMapIntro": "<h3>An Open Map</h3><p>Wouldn't it be cool if there was a single map, which everyone could freely use and edit? A single place to store all geo-information? Then, all those websites with different, small and incompatible maps (which are always outdated) wouldn't be needed anymore.</p><p><b><a href='https://OpenStreetMap.org' target='_blank'>OpenStreetMap</a></b> is this map. The map data can be used for free (with <a href='https://osm.org/copyright' target='_blank'>attribution and publication of changes to that data</a>). On top of that, everyone can freely add new data and fix errors. This website uses OpenStreetMap as well. All the data is from there, and your answers and corrections are added there as well.</p><p>A ton of people and application already use OpenStreetMap: <a href='https://maps.me/' target='_blank'>Maps.me</a>, <a href='https://osmAnd.net' target='_blank'>OsmAnd</a>, but also the maps at Facebook, Instagram, Apple-maps and Bing-maps are (partly) powered by OpenStreetMap. If you change something here, it'll be reflected in those applications too - after their next update!</p>",
|
||||
"openStreetMapIntro": "<h3>An Open Map</h3><p>Wouldn't it be cool if there was a single map, which everyone could freely use and edit? A single place to store all geo-information? Then, all those websites with different, small and incompatible maps (which are always outdated) wouldn't be needed anymore.</p><p><b><a href='https://OpenStreetMap.org' target='_blank'>OpenStreetMap</a></b> is this map. The map data can be used for free (with <a href='https://osm.org/copyright' target='_blank'>attribution and publication of changes to that data</a>). On top of that, everyone can freely add new data and fix errors. This website uses OpenStreetMap as well. All the data is from there, and your answers and corrections are added there as well.</p><p>A ton of people and application already use OpenStreetMap: <a href='https://organicmaps.app/' target='_blank'>Organic Maps</a>, <a href='https://osmAnd.net' target='_blank'>OsmAnd</a>, but also the maps at Facebook, Instagram, Apple-maps and Bing-maps are (partly) powered by OpenStreetMap. If you change something here, it'll be reflected in those applications too - after their next update!</p>",
|
||||
"search": {
|
||||
"search": "Search a location",
|
||||
"searching": "Searching…",
|
||||
|
|
|
@ -126,7 +126,7 @@
|
|||
"goToInbox": "受信トレイを開く",
|
||||
"fewChangesBefore": "新しいポイントを追加する前に、既存のポイントに関するいくつかの質問に答えてください。",
|
||||
"readYourMessages": "新しいポイントを追加する前に、OpenStreetMapのメッセージをすべて読んでください。",
|
||||
"openStreetMapIntro": "<h3>オープン地図</h3><p>誰もが自由に使用して編集できる1つのマップがあればクールではないでしょうか?すべての地理情報を格納するための単一の場所?そうすれば、異なる、小さくて互換性のない地図(常に時代遅れのもの)を持つウェブサイトは、必要なくなるでしょう。</p><p><b><a href=\"https://OpenStreetMap.org\" target=\"_blank\">OpenStreetMap</a></b>こそが地図です。地図データは、(<a href=\"https://osm.org/copyright\" target=\"_blank\">データ変更の公開と帰属表示</a>をすれば)無料で利用できます。さらに、誰でも自由に新しいデータを追加したり、間違いを修正したりすることができます。このサイトでもOpenStreetMapを使っています。すべてのデータは、OSMからのものであり、あなたの答えと訂正もOSMに追加されます。</p><p>すでに多くの人やアプリケーションがOpenStreetMapを使っています:<a href=\"https://maps.me/\" target=\"_blank\">Maps.me</a>や、<a href=\"https://osmAnd.net\" target=\"_blank\">OsmAnd</a>など。Fさらに、acebook、Instagram、Apple-maps、Bing-mapsも(部分的に)OpenStreetMapを利用しています。ここで何かを変更すると、次の更新後にアプリケーションにも反映されます。</p>",
|
||||
"openStreetMapIntro": "<h3>オープン地図</h3><p>誰もが自由に使用して編集できる1つのマップがあればクールではないでしょうか?すべての地理情報を格納するための単一の場所?そうすれば、異なる、小さくて互換性のない地図(常に時代遅れのもの)を持つウェブサイトは、必要なくなるでしょう。</p><p><b><a href=\"https://OpenStreetMap.org\" target=\"_blank\">OpenStreetMap</a></b>こそが地図です。地図データは、(<a href=\"https://osm.org/copyright\" target=\"_blank\">データ変更の公開と帰属表示</a>をすれば)無料で利用できます。さらに、誰でも自由に新しいデータを追加したり、間違いを修正したりすることができます。このサイトでもOpenStreetMapを使っています。すべてのデータは、OSMからのものであり、あなたの答えと訂正もOSMに追加されます。</p><p>すでに多くの人やアプリケーションがOpenStreetMapを使っています:<a href=\"https://organicmaps.app//\" target=\"_blank\">Maps.me</a>や、<a href=\"https://osmAnd.net\" target=\"_blank\">OsmAnd</a>など。Fさらに、acebook、Instagram、Apple-maps、Bing-mapsも(部分的に)OpenStreetMapを利用しています。ここで何かを変更すると、次の更新後にアプリケーションにも反映されます。</p>",
|
||||
"noNameCategory": "名前のない {category}",
|
||||
"pickLanguage": "言語を選択します: ",
|
||||
"number": "number",
|
||||
|
|
|
@ -69,7 +69,7 @@
|
|||
"emailOf": "Wat is het email-adres van {category}?",
|
||||
"emailIs": "Het email-adres van {category} is <a href='mailto:{email}' target='_blank'>{email}</a>"
|
||||
},
|
||||
"openStreetMapIntro": "<h3>Een open kaart</h3><p>Zou het niet fantastisch zijn als er een open kaart zou zijn die door iedereen aangepast én gebruikt kan worden? Een kaart waar iedereen zijn interesses aan zou kunnen toevoegen? Dan zouden er geen duizend-en-één verschillende kleine kaartjes, websites, ... meer nodig zijn</p><p><b><a href='https://OpenStreetMap.org' target='_blank'>OpenStreetMap</a></b> is deze open kaart. Je mag de kaartdata gratis gebruiken (mits <a href='https://osm.org/copyright' target='_blank'>bronvermelding en herpublicatie van aanpassingen</a>). Daarenboven mag je de kaart ook gratis aanpassen als je een account maakt. Ook deze website is gebaseerd op OpenStreetMap. Als je hier een vraag beantwoord, gaat het antwoord daar ook naartoe</p><p>Tenslotte zijn er reeds vele gebruikers van OpenStreetMap. Denk maar <a href='https://maps.me/' target='_blank'>Maps.me</a>, <a href='https://osmAnd.net' target='_blank'>OsmAnd</a>, verschillende gespecialiseerde routeplanners, de achtergrondkaarten op Facebook, Instagram,...<br/>Zelfs Apple Maps en Bing-Maps gebruiken OpenStreetMap in hun kaarten!</p></p><p>Kortom, als je hier een punt toevoegd of een vraag beantwoord, zal dat na een tijdje ook in al dié applicaties te zien zijn.</p>",
|
||||
"openStreetMapIntro": "<h3>Een open kaart</h3><p>Zou het niet fantastisch zijn als er een open kaart zou zijn die door iedereen aangepast én gebruikt kan worden? Een kaart waar iedereen zijn interesses aan zou kunnen toevoegen? Dan zouden er geen duizend-en-één verschillende kleine kaartjes, websites, ... meer nodig zijn</p><p><b><a href='https://OpenStreetMap.org' target='_blank'>OpenStreetMap</a></b> is deze open kaart. Je mag de kaartdata gratis gebruiken (mits <a href='https://osm.org/copyright' target='_blank'>bronvermelding en herpublicatie van aanpassingen</a>). Daarenboven mag je de kaart ook gratis aanpassen als je een account maakt. Ook deze website is gebaseerd op OpenStreetMap. Als je hier een vraag beantwoord, gaat het antwoord daar ook naartoe</p><p>Tenslotte zijn er reeds vele gebruikers van OpenStreetMap. Denk maar <a href='https://organicmaps.app//' target='_blank'>Organic Maps</a>, <a href='https://osmAnd.net' target='_blank'>OsmAnd</a>, verschillende gespecialiseerde routeplanners, de achtergrondkaarten op Facebook, Instagram,...<br/>Zelfs Apple Maps en Bing-Maps gebruiken OpenStreetMap in hun kaarten!</p></p><p>Kortom, als je hier een punt toevoegd of een vraag beantwoord, zal dat na een tijdje ook in al dié applicaties te zien zijn.</p>",
|
||||
"attribution": {
|
||||
"attributionTitle": "Met dank aan",
|
||||
"attributionContent": "<p>Alle data is voorzien door <a href='https://osm.org' target='_blank'>OpenStreetMap</a>, gratis en vrij te hergebruiken onder <a href='https://osm.org/copyright' target='_blank'>de Open DataBase Licentie</a>.</p>",
|
||||
|
|
|
@ -121,7 +121,7 @@
|
|||
"attributionContent": "<p>Все данные предоставлены <a href=\"https://osm.org\" target=\"_blank\">OpenStreetMap</a>, свободное повторное использование согласно <a href=\"https://osm.org/copyright\" target=\"_blank\">Open DataBase License</a>.</p>",
|
||||
"attributionTitle": "Уведомление об авторстве"
|
||||
},
|
||||
"openStreetMapIntro": "<h3>Свободная карта</h3><p>Было бы здорово если бы была одна карта, которую каждый может свободно использовать и редактировать? Использовать как общее хранилище для всей гео-информации? Тогда, все сайты с разной, неполной и несовместимой информацией (которая обычно устарела) будут больше не нужны.</p><p><b><a href=\"https://OpenStreetMap.org\" target=\"_blank\">OpenStreetMap</a></b> такая карта. Данные карты могу быть свободно использованы (с <a href=\"https://osm.org/copyright\" target=\"_blank\">аннотацией и публикацией изменений к данным</a>). Более того, каждый может свободно добавлять информацию и исправлять ошибки. Этот сайт также использует OpenStreetMap. Все данные берутся оттуда, а ваши ответы и исправления отправляются обратно туда.</p><p>Огромное количество людей уже использует OpenStreetMap: <a href=\"https://maps.me/\" target=\"_blank\">Maps.me</a>, <a href=\"https://osmAnd.net\" target=\"_blank\">OsmAnd</a>, а также карты в Facebook, Instagram, Apple-карты и Bing-карты (частично) используют OpenStreetMap. Если вы что-то измените здесь, это также будет отражено в этих приложениях - после их следующего обновления!</p>"
|
||||
"openStreetMapIntro": "<h3>Свободная карта</h3><p>Было бы здорово если бы была одна карта, которую каждый может свободно использовать и редактировать? Использовать как общее хранилище для всей гео-информации? Тогда, все сайты с разной, неполной и несовместимой информацией (которая обычно устарела) будут больше не нужны.</p><p><b><a href=\"https://OpenStreetMap.org\" target=\"_blank\">OpenStreetMap</a></b> такая карта. Данные карты могу быть свободно использованы (с <a href=\"https://osm.org/copyright\" target=\"_blank\">аннотацией и публикацией изменений к данным</a>). Более того, каждый может свободно добавлять информацию и исправлять ошибки. Этот сайт также использует OpenStreetMap. Все данные берутся оттуда, а ваши ответы и исправления отправляются обратно туда.</p><p>Огромное количество людей уже использует OpenStreetMap: <a href=\"https://organicmaps.app//\" target=\"_blank\">Organic Maps</a>, <a href=\"https://osmAnd.net\" target=\"_blank\">OsmAnd</a>, а также карты в Facebook, Instagram, Apple-карты и Bing-карты (частично) используют OpenStreetMap. Если вы что-то измените здесь, это также будет отражено в этих приложениях - после их следующего обновления!</p>"
|
||||
},
|
||||
"index": {
|
||||
"pickTheme": "Выберите тему ниже, чтобы начать.",
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"title": "AED-Karte öffnen",
|
||||
"description": "Auf dieser Karte kann man nahe gelegene Defibrillatoren finden und markieren"
|
||||
},
|
||||
"artworks": {
|
||||
"artwork": {
|
||||
"title": "Freie Kunstwerk-Karte",
|
||||
"description": "Willkommen bei der Freien Kunstwerk-Karte, einer Karte von Statuen, Büsten, Grafitti, ... auf der ganzen Welt",
|
||||
"layers": {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"title": "Open AED Map",
|
||||
"description": "On this map, one can find and mark nearby defibrillators"
|
||||
},
|
||||
"artworks": {
|
||||
"artwork": {
|
||||
"title": "Open Artwork Map",
|
||||
"description": "Welcome to Open Artwork Map, a map of statues, busts, grafittis and other artwork all over the world",
|
||||
"layers": {
|
||||
|
@ -1174,7 +1174,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"fietsstraten": {
|
||||
"cyclestreets": {
|
||||
"title": "Cyclestreets",
|
||||
"shortDescription": "A map of cyclestreets",
|
||||
"description": "A cyclestreet is is a street where <b>motorized traffic is not allowed to overtake cyclists</b>. They are signposted by a special traffic sign. Cyclestreets can be found in the Netherlands and Belgium, but also in Germany and France. ",
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"title": "Mapa abierto de desfibriladores (DEA)",
|
||||
"description": "En este mapa , cualquiera puede encontrar y marcar los desfibriladores externos automáticos más cercanos"
|
||||
},
|
||||
"artworks": {
|
||||
"artwork": {
|
||||
"description": "Bienvenido a Open Artwork Map, un mapa de estatuas, bustos, grafitis y otras obras de arte de todo el mundo",
|
||||
"layers": {
|
||||
"0": {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"title": "Carte des défibrillateurs (DAE)",
|
||||
"description": "Sur cette carte, vous pouvez trouver et améliorer les informations sur les défibrillateurs"
|
||||
},
|
||||
"artworks": {
|
||||
"artwork": {
|
||||
"title": "Carte ouverte des œuvres d'art",
|
||||
"description": "Bienvenue sur la carte ouverte des œuvres d'art, une carte des statues, fresques, ... du monde entier",
|
||||
"layers": {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"aed": {
|
||||
"title": "Nyílt AED Térkép"
|
||||
},
|
||||
"artworks": {
|
||||
"artwork": {
|
||||
"title": "Nyít Műalkotás Térkép"
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
"title": "Buka Peta AED",
|
||||
"description": "Di peta ini, seseorang dapat menemukan dan menandai defibrillator terdekat"
|
||||
},
|
||||
"artworks": {
|
||||
"artwork": {
|
||||
"title": "Buka Peta Karya Seni",
|
||||
"description": "Selamat datang di Open Artwork Map, peta untuk patung, grafiti, dan karya seni lain di seluruh dunia",
|
||||
"layers": {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"title": "Mappa dei defibrillatori (DAE)",
|
||||
"description": "Su questa mappa puoi trovare e segnalare i defibrillatori nelle vicinanze"
|
||||
},
|
||||
"artworks": {
|
||||
"artwork": {
|
||||
"title": "Mappa libera delle opere d'arte",
|
||||
"description": "Benvenuto/a sulla mappa libera dell’arte, una mappa delle statue, i busti, i graffiti e le altre realizzazioni artistiche di tutto il mondo",
|
||||
"layers": {
|
||||
|
@ -396,7 +396,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"fietsstraten": {
|
||||
"cyclestreets": {
|
||||
"roamingRenderings": {
|
||||
"0": {
|
||||
"mappings": {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"title": "オープンAEDマップ",
|
||||
"description": "この地図では近くにある除細動器(AED)を見つけてマークします"
|
||||
},
|
||||
"artworks": {
|
||||
"artwork": {
|
||||
"title": "オープン アートワーク マップ",
|
||||
"description": "オープン アートワーク マップへようこそ。世界中の銅像や胸像、壁の落書きなどのアートワークの地図です",
|
||||
"layers": {
|
||||
|
@ -583,7 +583,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"fietsstraten": {
|
||||
"cyclestreets": {
|
||||
"title": "Cyclestreets",
|
||||
"shortDescription": "cyclestreetsの地図",
|
||||
"description": "cyclestreetとは、<b>自動車がサイクリストを追い越すことができない</b>道です。専用の道路標識で表示されます。Cyclestreetsはオランダやベルギーにもありますが、ドイツやフランスにもあります。 ",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"aed": {
|
||||
"title": "Åpne AED-kart"
|
||||
},
|
||||
"artworks": {
|
||||
"artwork": {
|
||||
"layers": {
|
||||
"0": {
|
||||
"name": "Kunstverk",
|
||||
|
@ -213,7 +213,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"fietsstraten": {
|
||||
"cyclestreets": {
|
||||
"shortDescription": "Et kart over sykkelveier",
|
||||
"roamingRenderings": {
|
||||
"0": {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"title": "Open AED-kaart - Brugge edition",
|
||||
"description": "Op deze kaart kan je informatie over AEDs vinden en verbeteren + een export van de brugse defibrillatoren"
|
||||
},
|
||||
"artworks": {
|
||||
"artwork": {
|
||||
"title": "Kunstwerkenkaart",
|
||||
"description": "Welkom op de Open Kunstwerken Kaart",
|
||||
"layers": {
|
||||
|
@ -995,7 +995,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"fietsstraten": {
|
||||
"cyclestreets": {
|
||||
"title": "Fietsstraten",
|
||||
"shortDescription": "Een kaart met alle gekende fietsstraten",
|
||||
"description": "Een fietsstraat is een straat waar <ul><li><b>automobilisten geen fietsers mogen inhalen</b></li><li>Er een maximumsnelheid van <b>30km/u</b> geldt</li><li>Fietsers gemotoriseerde voortuigen links mogen inhalen</li><li>Fietsers nog steeds voorrang aan rechts moeten verlenen - ook aan auto's en voetgangers op het zebrapad</li></ul><br/><br/>Op deze open kaart kan je alle gekende fietsstraten zien en kan je ontbrekende fietsstraten aanduiden. Om de kaart aan te passen, moet je je aanmelden met OpenStreetMap en helemaal inzoomen tot straatniveau.",
|
||||
|
@ -1007,7 +1007,7 @@
|
|||
"then": "Deze straat is een fietsstraat (en dus zone 30)"
|
||||
},
|
||||
"1": {
|
||||
"then": "Deze straat is een fietsstraat"
|
||||
"then": "Deze straat i een fietsstraat"
|
||||
},
|
||||
"2": {
|
||||
"then": "Deze straat wordt binnenkort een fietsstraat"
|
||||
|
@ -1235,7 +1235,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"boomgaarden": {
|
||||
"fruit_trees": {
|
||||
"title": "Open Boomgaardenkaart",
|
||||
"shortDescription": "Boomgaarden en fruitbomen",
|
||||
"description": "Op deze kaart vindt je boomgaarden en fruitbomen",
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"title": "Открытая карта АВД (Автоматизированных внешних дефибрилляторов)",
|
||||
"description": "На этой карте вы можете найти и отметить ближайшие дефибрилляторы"
|
||||
},
|
||||
"artworks": {
|
||||
"artwork": {
|
||||
"title": "Открытая карта произведений искусства",
|
||||
"description": "Добро пожаловать на Open Artwork Map, карту статуй, бюстов, граффити и других произведений искусства по всему миру",
|
||||
"layers": {
|
||||
|
@ -407,7 +407,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"fietsstraten": {
|
||||
"cyclestreets": {
|
||||
"layers": {
|
||||
"2": {
|
||||
"name": "Все улицы",
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"title": "Öppna AED-karta",
|
||||
"description": "På denna karta kan man hitta och markera närliggande defibrillatorer"
|
||||
},
|
||||
"artworks": {
|
||||
"artwork": {
|
||||
"title": "Öppen konstverkskarta"
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
"title": "開放AED地圖",
|
||||
"description": "在這份地圖上,你可以找到與標記附近的除顫器"
|
||||
},
|
||||
"artworks": {
|
||||
"artwork": {
|
||||
"title": "開放藝術品地圖",
|
||||
"description": "歡迎來到開放藝術品地圖,這份地圖會顯示全世界的雕像、半身像、塗鴉以及其他類型的藝術品",
|
||||
"layers": {
|
||||
|
@ -294,7 +294,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"fietsstraten": {
|
||||
"cyclestreets": {
|
||||
"title": "單車街道",
|
||||
"shortDescription": "單車街道的地圖",
|
||||
"description": "單車街道是<b>機動車輛受限制,只允許單車通行</b>的道路。通常會有路標顯示特別的交通指標。單車街道通常在荷蘭、比利時看到,但德國與法國也有。 ",
|
||||
|
|
|
@ -101,7 +101,7 @@
|
|||
"attributionContent": "<p>所有資料由<a href=\"https://osm.org\" target=\"_blank\">開放街圖</a>提供,在<a href=\"https://osm.org/copyright\" target=\"_blank\">開放資料庫授權條款</a>之下自由再利用。</p>",
|
||||
"attributionTitle": "署名通知"
|
||||
},
|
||||
"openStreetMapIntro": "<h3>開放的地圖</h3><p>如果有一份地圖,任何人都能自由使用與編輯,單一的地圖能夠儲存所有地理相關資訊?這樣不就很酷嗎?接著,所有的網站使用不同的、範圍小的,不相容的地圖 (通常也都過時了),也就不再需要了。</p><p><b><a href=\"https://OpenStreetMap.org\" target=\"_blank\">開放街圖</a></b>就是這樣的地圖,人人都能免費這些圖資 (只要<a href=\"https://osm.org/copyright\" target=\"_blank\">署名與公開變動這資料</a>)。只要遵循這些,任何人都能自由新增新資料與修正錯誤,這些網站也都使用開放街圖,資料也都來自開放街圖,你的答案與修正也會加到開放街圖上面。</p><p>許多人與應用程式已經採用開放街圖了:<a href=\"https://maps.me/\" target=\"_blank\">Maps.me</a>、<a href=\"https://osmAnd.net\" target=\"_blank\">OsmAnd</a>,還有 Facebook、Instagram,蘋果地圖、Bing 地圖(部分)採用開放街圖。如果你在開放街圖上變動資料,也會同時影響這些應用 - 在他們下次更新資料之後!</p>",
|
||||
"openStreetMapIntro": "<h3>開放的地圖</h3><p>如果有一份地圖,任何人都能自由使用與編輯,單一的地圖能夠儲存所有地理相關資訊?這樣不就很酷嗎?接著,所有的網站使用不同的、範圍小的,不相容的地圖 (通常也都過時了),也就不再需要了。</p><p><b><a href=\"https://OpenStreetMap.org\" target=\"_blank\">開放街圖</a></b>就是這樣的地圖,人人都能免費這些圖資 (只要<a href=\"https://osm.org/copyright\" target=\"_blank\">署名與公開變動這資料</a>)。只要遵循這些,任何人都能自由新增新資料與修正錯誤,這些網站也都使用開放街圖,資料也都來自開放街圖,你的答案與修正也會加到開放街圖上面。</p><p>許多人與應用程式已經採用開放街圖了:<a href=\"https://organicmaps.app//\" target=\"_blank\">Organic Maps</a>、<a href=\"https://osmAnd.net\" target=\"_blank\">OsmAnd</a>,還有 Facebook、Instagram,蘋果地圖、Bing 地圖(部分)採用開放街圖。如果你在開放街圖上變動資料,也會同時影響這些應用 - 在他們下次更新資料之後!</p>",
|
||||
"questions": {
|
||||
"emailIs": "{category} 的電子郵件地址是<a href=\"mailto:{email}\" target=\"_blank\">{email}</a>",
|
||||
"emailOf": "{category} 的電子郵件地址是?",
|
||||
|
|
|
@ -56,6 +56,10 @@ class LayerOverviewUtils {
|
|||
if (path != undefined && path.indexOf(expected) < 0) {
|
||||
errorCount.push("Layer is in an incorrect place. The path is " + path + ", but expected " + expected)
|
||||
}
|
||||
if(layerJson["hideUnderlayingFeaturesMinPercentage"] !== undefined){
|
||||
errorCount.push("Layer "+layer.id+" contains an old 'hideUnderlayingFeaturesMinPercentage'")
|
||||
}
|
||||
|
||||
|
||||
for (const image of images) {
|
||||
if (image.indexOf("{") >= 0) {
|
||||
|
@ -78,9 +82,8 @@ class LayerOverviewUtils {
|
|||
|
||||
main(args: string[]) {
|
||||
|
||||
const lt = this.loadThemesAndLayers();
|
||||
const layerFiles = lt.layers;
|
||||
const themeFiles = lt.themes;
|
||||
const layerFiles = ScriptUtils.getLayerFiles();
|
||||
const themeFiles = ScriptUtils.getThemeFiles();
|
||||
|
||||
console.log(" ---------- VALIDATING ---------")
|
||||
const licensePaths = []
|
||||
|
@ -98,7 +101,9 @@ class LayerOverviewUtils {
|
|||
}
|
||||
|
||||
let themeErrorCount = []
|
||||
for (const themeFile of themeFiles) {
|
||||
for (const themeInfo of themeFiles) {
|
||||
const themeFile = themeInfo.parsed
|
||||
const themePath = themeInfo.path
|
||||
if (typeof themeFile.language === "string") {
|
||||
themeErrorCount.push("The theme " + themeFile.id + " has a string as language. Please use a list of strings")
|
||||
}
|
||||
|
@ -108,12 +113,13 @@ class LayerOverviewUtils {
|
|||
themeErrorCount.push(`Unknown layer id: ${layer} in theme ${themeFile.id}`)
|
||||
}
|
||||
} else {
|
||||
if (layer.builtin !== undefined) {
|
||||
if (!knownLayerIds.has(layer.builtin)) {
|
||||
themeErrorCount.push("Unknown layer id: " + layer.builtin + "(which uses inheritance)")
|
||||
if (layer["builtin"] !== undefined) {
|
||||
if (!knownLayerIds.has(layer["builtin"])) {
|
||||
themeErrorCount.push("Unknown layer id: " + layer["builtin"] + "(which uses inheritance)")
|
||||
}
|
||||
} else {
|
||||
// layer.builtin contains layer overrides - we can skip those
|
||||
// @ts-ignore
|
||||
layerErrorCount.push(...this.validateLayer(layer, undefined, knownPaths, themeFile.id))
|
||||
}
|
||||
}
|
||||
|
@ -121,7 +127,7 @@ class LayerOverviewUtils {
|
|||
|
||||
themeFile.layers = themeFile.layers
|
||||
.filter(l => typeof l != "string") // We remove all the builtin layer references as they don't work with ts-node for some weird reason
|
||||
.filter(l => l.builtin === undefined)
|
||||
.filter(l => l["builtin"] === undefined)
|
||||
|
||||
|
||||
try {
|
||||
|
@ -129,6 +135,12 @@ class LayerOverviewUtils {
|
|||
if (theme.id !== theme.id.toLowerCase()) {
|
||||
themeErrorCount.push("Theme ids should be in lowercase, but it is " + theme.id)
|
||||
}
|
||||
let filename = themePath.substring(themePath.lastIndexOf("/") + 1, themePath.length - 5)
|
||||
if(theme.id !== filename){
|
||||
themeErrorCount.push("Theme ids should be the same as the name.json, but we got id: " + theme.id + " and filename "+filename+" ("+themePath+")")
|
||||
}
|
||||
|
||||
|
||||
} catch (e) {
|
||||
themeErrorCount.push("Could not parse theme " + themeFile["id"] + "due to", e)
|
||||
}
|
||||
|
|