Merge develop

This commit is contained in:
pietervdvn 2022-07-13 23:12:14 +02:00
commit c916d5fe66
43 changed files with 802 additions and 275 deletions

View file

@ -10,5 +10,5 @@ ports:
vscode:
extensions:
- "esbenp.prettier-vscode"
- "eamodio.gitlens",
- "eamodio.gitlens"
- "GitHub.vscode-pull-request-github"

View file

@ -20,7 +20,7 @@ export class AllKnownLayouts {
public static AllPublicLayers(options?: {
includeInlineLayers:true | boolean
}) {
}) : LayerConfig[] {
const allLayers: LayerConfig[] = []
const seendIds = new Set<string>()
AllKnownLayouts.sharedLayers.forEach((layer, key) => {

View file

@ -72,6 +72,12 @@ To use the WSL in Visual Studio Code:
or `userlayout=true#<layout configuration>` as [Query parameter](URL_Parameters.md). Note that the shorter URLs (
e.g. `bookcases.html`, `aed.html`, ...) _don't_ exist on the development version.
### Dependencie
`make` , `python3` `g++`
(run `nix-env -iA nixos.gnumake nixos.gdc nixos.python3`)
Automatic deployment
--------------------

View file

@ -24,6 +24,7 @@ import FullNodeDatabaseSource from "./TiledFeatureSource/FullNodeDatabaseSource"
import MapState from "../State/MapState";
import {ElementStorage} from "../ElementStorage";
import {Feature, Geometry} from "@turf/turf";
import {OsmFeature} from "../../Models/OsmFeature";
/**
@ -338,15 +339,19 @@ export default class FeaturePipeline {
}
public GetAllFeaturesWithin(bbox: BBox): Feature<Geometry, {id: string}>[][] {
public GetAllFeaturesWithin(bbox: BBox): OsmFeature[][] {
const self = this
const tiles = []
const tiles: OsmFeature[][] = []
Array.from(this.perLayerHierarchy.keys())
.forEach(key => tiles.push(...self.GetFeaturesWithin(key, bbox)))
.forEach(key => {
const fetched : OsmFeature[][] = self.GetFeaturesWithin(key, bbox)
tiles.push(...fetched);
})
return tiles;
}
public GetAllFeaturesAndMetaWithin(bbox: BBox, layerIdWhitelist?: Set<string>): {features: any[], layer: string}[] {
public GetAllFeaturesAndMetaWithin(bbox: BBox, layerIdWhitelist?: Set<string>):
{features: OsmFeature[], layer: string}[] {
const self = this
const tiles :{features: any[], layer: string}[]= []
Array.from(this.perLayerHierarchy.keys())
@ -362,7 +367,11 @@ export default class FeaturePipeline {
return tiles;
}
public GetFeaturesWithin(layerId: string, bbox: BBox): any[][] {
/**
* Gets all the tiles which overlap with the given BBOX.
* This might imply that extra features might be shown
*/
public GetFeaturesWithin(layerId: string, bbox: BBox): OsmFeature[][] {
if (layerId === "*") {
return this.GetAllFeaturesWithin(bbox)
}

View file

@ -1,9 +1,11 @@
import {Store, UIEventSource} from "../UIEventSource";
import FilteredLayer from "../../Models/FilteredLayer";
import {BBox} from "../BBox";
import {Feature, Geometry} from "@turf/turf";
import {OsmFeature} from "../../Models/OsmFeature";
export default interface FeatureSource {
features: Store<{ feature: any, freshness: Date }[]>;
features: Store<{ feature: OsmFeature, freshness: Date }[]>;
/**
* Mainly used for debuging
*/
@ -28,12 +30,3 @@ export interface FeatureSourceForLayer extends FeatureSource {
export interface IndexedFeatureSource extends FeatureSource {
readonly containedIds: Store<Set<string>>
}
/**
* A feature source which has some extra data about it's state
*/
export interface FeatureSourceState {
readonly sufficientlyZoomed: Store<boolean>;
readonly runningQuery: Store<boolean>;
readonly timeout: Store<number>;
}

View file

@ -13,7 +13,7 @@ export default interface TileHierarchy<T extends FeatureSource & Tiled> {
export class TileHierarchyTools {
public static getTiles<T extends FeatureSource & Tiled>(hierarchy: TileHierarchy<T>, bbox: BBox): T[] {
const result = []
const result: T[] = []
hierarchy.loadedTiles.forEach((tile) => {
if (tile.bbox.overlapsWith(bbox)) {
result.push(tile)

View file

@ -3,7 +3,7 @@ import {BBox} from "./BBox";
import togpx from "togpx"
import Constants from "../Models/Constants";
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
import {booleanWithin, Coord, Feature, Geometry, MultiPolygon, Polygon, Properties} from "@turf/turf";
import {AllGeoJSON, booleanWithin, Coord, Feature, Geometry, MultiPolygon, Polygon, Properties} from "@turf/turf";
export class GeoOperations {
@ -29,7 +29,7 @@ export class GeoOperations {
* Returns [lon,lat] coordinates
* @param feature
*/
static centerpointCoordinates(feature: any): [number, number] {
static centerpointCoordinates(feature: AllGeoJSON): [number, number] {
return <[number, number]>turf.center(feature).geometry.coordinates;
}

View file

@ -159,7 +159,7 @@ export class Changes {
const recentLocationPoints = locations.map(ff => ff.feature)
.filter(feat => feat.geometry.type === "Point")
.filter(feat => {
const visitTime = new Date((<GeoLocationPointProperties>feat.properties).date)
const visitTime = new Date((<GeoLocationPointProperties><any>feat.properties).date)
// In seconds
const diff = (now.getTime() - visitTime.getTime()) / 1000
return diff < Constants.nearbyVisitTime;

View file

@ -13,7 +13,7 @@ export class Tag extends TagsFilter {
throw "Invalid key: undefined or empty";
}
if (value === undefined) {
throw "Invalid value: value is undefined";
throw `Invalid value while constructing a Tag with key '${key}': value is undefined`;
}
if (value === "*") {
console.warn(`Got suspicious tag ${key}=* ; did you mean ${key}~* ?`)

4
Models/OsmFeature.ts Normal file
View file

@ -0,0 +1,4 @@
import {Feature, Geometry} from "@turf/turf";
export type OsmTags = Record<string, string> & {id: string}
export type OsmFeature = Feature<Geometry, OsmTags>

View file

@ -191,6 +191,9 @@ export default class LayerConfig extends WithContextLoader {
this.doNotDownload = json.doNotDownload ?? false;
this.passAllFeatures = json.passAllFeatures ?? false;
this.minzoom = json.minzoom ?? 0;
if(json["minZoom"] !== undefined){
throw "At "+context+": minzoom is written all lowercase"
}
this.minzoomVisible = json.minzoomVisible ?? this.minzoom;
this.shownByDefault = json.shownByDefault ?? true;
this.forceLoad = json.forceLoad ?? false;

View file

@ -20,7 +20,7 @@ export interface Mapping {
readonly ifnot?: TagsFilter,
readonly then: TypedTranslation<object>,
readonly icon: string,
readonly iconClass: string
readonly iconClass: string | "small" | "medium" | "large" | "small-height" | "medium-height" | "large-height",
readonly hideInAnswer: boolean | TagsFilter
readonly addExtraTags: Tag[],
readonly searchTerms?: Record<string, string[]>
@ -364,7 +364,7 @@ export default class TagRenderingConfig {
* Returns true if it is known or not shown, false if the question should be asked
* @constructor
*/
public IsKnown(tags: any): boolean {
public IsKnown(tags: Record<string, string>): boolean {
if (this.condition &&
!this.condition.matchesProperties(tags)) {
// Filtered away by the condition, so it is kindof known
@ -400,7 +400,7 @@ export default class TagRenderingConfig {
* @param tags
* @constructor
*/
public GetRenderValues(tags: any): { then: Translation, icon?: string, iconClass?: string }[] {
public GetRenderValues(tags: Record<string, string>): { then: Translation, icon?: string, iconClass?: string }[] {
if (!this.multiAnswer) {
return [this.GetRenderValueWithImage(tags)]
}
@ -410,7 +410,7 @@ export default class TagRenderingConfig {
let freeformKeyDefined = this.freeform?.key !== undefined;
let usedFreeformValues = new Set<string>()
// We run over all the mappings first, to check if the mapping matches
const applicableMappings: { then: TypedTranslation<any>, img?: string }[] = Utils.NoNull((this.mappings ?? [])?.map(mapping => {
const applicableMappings: { then: TypedTranslation<Record<string, string>>, img?: string }[] = Utils.NoNull((this.mappings ?? [])?.map(mapping => {
if (mapping.if === undefined) {
return mapping;
}

View file

@ -93,7 +93,7 @@ export class CompareToAlreadyExistingNotes extends Combine implements FlowStep<{
state,
zoomToFeatures: true,
leafletMap: comparisonMap.leafletMap,
features: new StaticFeatureSource(partitionedImportPoints.map(p => p.hasNearby)),
features: StaticFeatureSource.fromGeojsonStore(partitionedImportPoints.map(p => p.hasNearby)),
popup: (tags, layer) => new FeatureInfoBox(tags, layer, state)
})

View file

@ -80,6 +80,8 @@ export default class ConflationChecker extends Combine implements FlowStep<{ fea
if (v !== undefined && v !== null) {
console.log("Loaded from local storage:", v)
overpassStatus.setData("cached")
}else{
loadDataFromOverpass()
}
}
});

View file

@ -57,7 +57,7 @@ class SelfHidingToggle extends UIElement implements InputElement<boolean> {
return true
}
s = s?.trim()?.toLowerCase()
return searchTerms[Locale.language.data].some(t => t.indexOf(s) >= 0);
return searchTerms[Locale.language.data]?.some(t => t.indexOf(s) >= 0) ?? false;
}, [selected, Locale.language])
const self = this;
@ -121,10 +121,15 @@ class SelfHidingToggle extends UIElement implements InputElement<boolean> {
* A searchfield can be used to filter the values
*/
export class SearchablePillsSelector<T> extends Combine implements InputElement<T[]> {
private selectedElements: UIEventSource<T[]>;
private readonly selectedElements: UIEventSource<T[]>;
public readonly someMatchFound: Store<boolean>;
/**
*
* @param values
* @param options
*/
constructor(
values: { show: BaseUIElement, value: T, mainTerm: Record<string, string>, searchTerms?: Record<string, string[]> }[],
options?: {
@ -133,6 +138,10 @@ export class SearchablePillsSelector<T> extends Combine implements InputElement<
searchValue?: UIEventSource<string>,
onNoMatches?: BaseUIElement,
onNoSearchMade?: BaseUIElement,
/**
* Shows this if there are many (>200) possible mappings
*/
onManyElements?: BaseUIElement,
selectIfSingle?: false | boolean,
searchAreaClass?: string
}) {
@ -188,11 +197,10 @@ export class SearchablePillsSelector<T> extends Combine implements InputElement<
};
})
let somethingShown: Store<boolean>
let totalShown: Store<number>
if (options.selectIfSingle) {
let forcedSelection : { value: T, show: SelfHidingToggle } = undefined
somethingShown = searchValue.map(_ => {
totalShown = searchValue.map(_ => {
let totalShown = 0;
let lastShownValue: { value: T, show: SelfHidingToggle }
for (const mv of mappedValues) {
@ -203,21 +211,21 @@ export class SearchablePillsSelector<T> extends Combine implements InputElement<
}
}
if (totalShown == 1) {
if (this.selectedElements.data.indexOf(lastShownValue.value) < 0) {
this.selectedElements.setData([lastShownValue.value])
if (selectedElements.data?.indexOf(lastShownValue.value) < 0) {
selectedElements.setData([lastShownValue.value])
lastShownValue.show.forceSelected.setData(true)
forcedSelection = lastShownValue
}
} else if (forcedSelection != undefined) {
forcedSelection?.show?.forceSelected?.setData(false)
forcedSelection = undefined;
this.selectedElements.setData([])
selectedElements.setData([])
}
return totalShown > 0
return totalShown
}, mappedValues.map(mv => mv.show.GetValue()))
} else {
somethingShown = searchValue.map(_ => mappedValues.some(mv => mv.show.isShown.data), mappedValues.map(mv => mv.show.GetValue()))
totalShown = searchValue.map(_ => mappedValues.filter(mv => mv.show.isShown.data).length, mappedValues.map(mv => mv.show.GetValue()))
}
@ -227,18 +235,21 @@ export class SearchablePillsSelector<T> extends Combine implements InputElement<
if (options?.onNoSearchMade !== undefined && (searchValue.data === undefined || searchValue.data.length === 0)) {
return options?.onNoSearchMade
}
if (!somethingShown.data) {
if (totalShown.data == 0) {
return onEmpty
}
if(totalShown.data >= 200){
return options?.onManyElements ?? Translations.t.general.useSearch;
}
mappedValues.sort((a, b) => a.mainTerm[lng] < b.mainTerm[lng] ? -1 : 1)
return new Combine(mappedValues.map(e => e.show))
.SetClass("flex flex-wrap w-full content-start")
.SetClass(options?.searchAreaClass ?? "")
}, [somethingShown, searchValue]))
}, [totalShown, searchValue]))
])
this.selectedElements = selectedElements;
this.someMatchFound = somethingShown;
this.someMatchFound = totalShown.map(t => t > 0);
}

View file

@ -22,7 +22,7 @@ import BaseUIElement from "../BaseUIElement";
import {DropDown} from "../Input/DropDown";
import InputElementWrapper from "../Input/InputElementWrapper";
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction";
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig";
import TagRenderingConfig, {Mapping} from "../../Models/ThemeConfig/TagRenderingConfig";
import {Unit} from "../../Models/Unit";
import VariableInputElement from "../Input/VariableInputElement";
import Toggle from "../Input/Toggle";
@ -32,6 +32,7 @@ import Title from "../Base/Title";
import {OsmConnection} from "../../Logic/Osm/OsmConnection";
import {GeoOperations} from "../../Logic/GeoOperations";
import {SearchablePillsSelector} from "../Input/SearchableMappingsSelector";
import {OsmTags} from "../../Models/OsmFeature";
/**
* Shows the question element.
@ -53,7 +54,7 @@ export default class TagRenderingQuestion extends Combine {
const applicableMappingsSrc =
Stores.ListStabilized(tags.map(tags => {
const applicableMappings: { if: TagsFilter, icon?: string, then: TypedTranslation<object>, ifnot?: TagsFilter, addExtraTags: Tag[] }[] = []
const applicableMappings: Mapping[] = []
for (const mapping of configuration.mappings ?? []) {
if (mapping.hideInAnswer === true) {
continue
@ -142,7 +143,7 @@ export default class TagRenderingQuestion extends Combine {
private static GenerateInputElement(
state: FeaturePipelineState,
configuration: TagRenderingConfig,
applicableMappings: { if: TagsFilter, then: TypedTranslation<object>, icon?: string, ifnot?: TagsFilter, addExtraTags: Tag[], searchTerms?: Record<string, string[]> }[],
applicableMappings: Mapping[],
applicableUnit: Unit,
tagsSource: UIEventSource<any>,
feedback: UIEventSource<Translation>
@ -231,16 +232,85 @@ export default class TagRenderingQuestion extends Combine {
}
/**
*
* // Should return the search as freeform value
* const source = new UIEventSource({id: "1234"})
* const tr = new TagRenderingConfig({
* id:"test",
* render:"The value is {key}",
* freeform: {
* key:"key"
* },
*
* mappings: [
* {
* if:"x=y",
* then:"z",
* searchTerms: {
* "en" : ["z"]
* }
* }
* ]
* }, "test");
* const selector = TagRenderingQuestion.GenerateSearchableSelector(
* undefined,
* tr,
* tr.mappings,
* source,
* {
* search: new UIEventSource<string>("value")
* }
* );
* selector.GetValue().data // => new And([new Tag("key","value")])
*
* // Should return the search as freeform value, even if a previous search matched
* const source = new UIEventSource({id: "1234"})
* const search = new UIEventSource<string>("")
* const tr = new TagRenderingConfig({
* id:"test",
* render:"The value is {key}",
* freeform: {
* key:"key"
* },
*
* mappings: [
* {
* if:"x=y",
* then:"z",
* searchTerms: {
* "en" : ["z"]
* }
* }
* ]
* }, "test");
* const selector = TagRenderingQuestion.GenerateSearchableSelector(
* undefined,
* tr,
* tr.mappings,
* source,
* {
* search
* }
* );
* search.setData("z")
* search.setData("zx")
* selector.GetValue().data // => new And([new Tag("key","zx")])
*/
private static GenerateSearchableSelector(
state: FeaturePipelineState,
configuration: TagRenderingConfig,
applicableMappings: { if: TagsFilter; ifnot?: TagsFilter, then: TypedTranslation<object>; icon?: string; iconClass?: string, addExtraTags: Tag[], searchTerms?: Record<string, string[]> }[], tagsSource: UIEventSource<any>): InputElement<TagsFilter> {
applicableMappings: Mapping[],
tagsSource: UIEventSource<OsmTags>,
options?: {
search: UIEventSource<string>
}): InputElement<TagsFilter> {
const values: { show: BaseUIElement, value: number, mainTerm: Record<string, string>, searchTerms?: Record<string, string[]> }[] = []
const addIcons = applicableMappings.some(m => m.icon !== undefined)
for (let i = 0; i < applicableMappings.length; i++) {
const mapping = applicableMappings[i];
const tr = mapping.then.Subs(tagsSource.data)
const patchedMapping = <{ iconClass: "small-height", then: TypedTranslation<object> }>{
const patchedMapping = <Mapping>{
...mapping,
iconClass: `small-height`,
icon: mapping.icon ?? (addIcons ? "./assets/svg/none.svg": undefined)
@ -254,7 +324,7 @@ export default class TagRenderingQuestion extends Combine {
})
}
const searchValue: UIEventSource<string> = new UIEventSource<string>(undefined)
const searchValue: UIEventSource<string> = options?.search ?? new UIEventSource<string>(undefined)
const ff = configuration.freeform
let onEmpty: BaseUIElement = undefined
if (ff !== undefined) {
@ -267,8 +337,14 @@ export default class TagRenderingQuestion extends Combine {
mode: configuration.multiAnswer ? "select-many" : "select-one",
searchValue,
onNoMatches: onEmpty?.SetClass(classes).SetClass("flex justify-center items-center"),
searchAreaClass: classes
searchAreaClass: classes,
})
const fallbackTag = searchValue.map(s => {
if (s === undefined || ff?.key === undefined) {
return undefined
}
return new Tag(ff.key, s)
});
return new InputElementMap<number[], And>(presetSearch,
(x0, x1) => {
if (x0 == x1) {
@ -289,7 +365,7 @@ export default class TagRenderingQuestion extends Combine {
},
(selected) => {
if (ff !== undefined && searchValue.data?.length > 0 && !presetSearch.someMatchFound.data) {
const t = new Tag(ff.key, searchValue.data)
const t = fallbackTag.data;
if (ff.addExtraTags) {
return new And([t, ...ff.addExtraTags])
}
@ -437,13 +513,7 @@ export default class TagRenderingQuestion extends Combine {
private static GenerateMappingElement(
state,
tagsSource: UIEventSource<any>,
mapping: {
if: TagsFilter,
then: Translation,
addExtraTags: Tag[],
icon?: string,
iconClass?: "small" | "medium" | "large" | "small-height"
}, ifNot?: TagsFilter[]): InputElement<TagsFilter> {
mapping: Mapping, ifNot?: TagsFilter[]): InputElement<TagsFilter> {
let tagging: TagsFilter = mapping.if;
if (ifNot !== undefined) {
@ -460,11 +530,7 @@ export default class TagRenderingQuestion extends Combine {
(t0, t1) => t1.shadows(t0));
}
private static GenerateMappingContent(mapping: {
then: Translation,
icon?: string,
iconClass?: "small" | "medium" | "large" | "small-height" | "medium-height" | "large-height"
}, tagsSource: UIEventSource<any>, state: FeaturePipelineState): BaseUIElement {
private static GenerateMappingContent(mapping: Mapping, tagsSource: UIEventSource<any>, state: FeaturePipelineState): BaseUIElement {
const text = new SubstitutedTranslation(mapping.then, tagsSource, state)
if (mapping.icon === undefined) {
return text;

View file

@ -3,6 +3,9 @@
"name": {
"en": "doctors"
},
"description": {
"en": "This layer shows doctor offices, dentists and other healthcare facilities"
},
"source": {
"osmTags": {
"or": [
@ -38,6 +41,18 @@
"phone",
"email",
"website",
{
"question": {
"en": "What is the name of this doctors place?"
},
"render": {
"en": "This doctors place is called {name}"
},
"freeform": {
"key": "name"
},
"id": "name"
},
{
"condition": "amenity=doctors",
"id": "specialty",
@ -120,13 +135,7 @@
"mapRendering": [
{
"icon": {
"render": "circle:white;./assets/layers/doctors/doctors.svg",
"mappings": [
{
"if": "amenity=dentist",
"then": "circle:white;./assets/layers/doctors/dentist.svg"
}
]
"render": "circle:white;./assets/layers/doctors/doctors.svg"
},
"iconSize": "40,40,center",
"location": [

View file

@ -1,9 +1,9 @@
[
{
"path": "dentist.svg",
"license": "cc0",
"license": "CC0",
"authors": [
"osmcarto"
"OSM Carto"
],
"sources": [
"https://wiki.openstreetmap.org/wiki/File:Dentist-14.svg"

View file

@ -164,9 +164,9 @@
"de": "Wie hoch ist der Bordstein?"
},
"render": {
"en": "Kerb height: {{kerb:height}}",
"nl": "Stoeprandhoogte: {{kerb:height}}",
"de": "Bordsteinhöhe: {{kerb:height}}"
"en": "Kerb height: {kerb:height}",
"nl": "Stoeprandhoogte: {kerb:height}",
"de": "Bordsteinhöhe: {kerb:height}"
},
"freeform": {
"key": "kerb:height",

View file

@ -26,7 +26,142 @@
"es": "Una capa que muestra aparcamientos para coches"
},
"tagRenderings": [
"images"
"images",
{
"id": "parking-type",
"mappings": [
{
"if": "parking=surface",
"then": {
"en": "This is a surface parking lot",
"nl": "Dit is een bovengronds parkeerterrein"
}
},
{
"if": "parking=street_side",
"then": {
"en": "This is a parking bay next to a street",
"nl": "Dit is een parkeerplek langs een weg"
}
},
{
"if": "parking=underground",
"then": {
"en": "This is an underground parking garage",
"nl": "Dit is een ondergrondse parkeergarage"
}
},
{
"if": "parking=multi-storey",
"then": {
"en": "This is a multi-storey parking garage",
"nl": "Dit is een bovengrondse parkeergarage met meerdere verdiepingen"
}
},
{
"if": "parking=rooftop",
"then": {
"en": "This is a rooftop parking deck",
"nl": "Dit is een parkeerdek op een dak"
}
},
{
"if": "parking=lane",
"then": {
"en": "This is a lane for parking on the road",
"nl": "Dit is een strook voor parkeren op de weg"
}
},
{
"if": "parking=carports",
"then": {
"en": "This is parking covered by carports",
"nl": "Dit is parking overdekt met carports"
}
},
{
"if": "parking=garage_boxes",
"then": {
"en": "This a parking consisting of garage boxes",
"nl": "Dit is een parking bestaande uit garageboxen"
}
},
{
"if": "parking=layby",
"then": {
"en": "This is a parking on a layby",
"nl": "Dit is een parkeerplek op een layby"
}
},
{
"if": "parking=sheds",
"then": {
"en": "This is a parking consisting of sheds",
"nl": "Dit is een parking bestaande uit schuren"
}
}
],
"question": {
"en": "What kind of parking is this?",
"nl": "Wat voor parking is dit?"
}
},
{
"id": "capacity-disabled",
"freeform": {
"key": "capacity:disabled",
"type": "pnat",
"placeholder": {
"en": "Amount of parking spots reserved for disabled people",
"nl": "Aantal parkeerplaatsen voor gehandicapten"
}
},
"mappings": [
{
"if": "capacity:disabled=yes",
"then": {
"en": "There are disabled parking spots, but it is not known how many",
"nl": "Er zijn parkeerplaatsen voor gehandicapten, maar het is niet bekend hoeveel er zijn"
},
"hideInAnswer": true
},
{
"if": "capacity:disabled=no",
"then": {
"en": "There are no disabled parking spots",
"nl": "Er zijn geen parkeerplaatsen voor gehandicapten"
},
"hideInAnswer": true
}
],
"question": {
"en": "How many disabled parking spots are there at this parking?",
"nl": "Hoeveel parkeerplaatsen voor gehandicapten zijn er op deze parking?"
},
"render": {
"en": "There are {capacity:disabled} disabled parking spots",
"nl": "Er zijn {capacity:disabled} parkeerplaatsen voor gehandicapten"
}
},
{
"id": "capacity",
"freeform": {
"key": "capacity",
"type": "pnat",
"placeholder": {
"en": "Amount of parking spots",
"nl": "Aantal parkeerplaatsen"
}
},
"question": {
"en": "How many parking spots are there at this parking?",
"nl": "Hoeveel parkeerplaatsen zijn er op deze parking?"
},
"render": {
"en": "There are {capacity} parking spots",
"nl": "Er zijn {capacity} parkeerplaatsen"
}
}
],
"presets": [
{
@ -52,7 +187,7 @@
},
"allowMove": {
"enableRelocation": false,
"enableImproveAccuraccy": true
"enableImproveAccuracy": true
},
"mapRendering": [
{

View file

@ -0,0 +1,93 @@
{
"id": "rainbow_crossings",
"name": {
"en": "Crossings with rainbow paintings"
},
"description": {
"en": "A layer showing pedestrian crossings with rainbow paintings"
},
"source": {
"osmTags": "highway=crossing"
},
"minzoom": 17,
"title": {
"render": {
"en": "Crossing"
}
},
"presets": [
{
"title": {
"en": "a crossing"
},
"tags": [
"highway=crossing"
],
"description": {
"en": "Pedestrian crossing"
},
"preciseInput": {
"preferredBackground": [
"photo"
],
"snapToLayer": "cycleways_and_roads",
"maxSnapDistance": 25
}
}
],
"tagRenderings": [
"images",
{
"id": "crossing-with-rainbow",
"question": {
"en": "Does this crossing has rainbow paintings?"
},
"condition": "highway=crossing",
"mappings": [
{
"if": "crossing:marking=rainbow",
"then": {
"en": "This crossing has rainbow paintings"
},
"icon": {
"path": "./assets/themes/rainbow_crossings/logo.svg",
"class": "medium"
}
},
{
"if": "not:crossing:marking=rainbow",
"then": {
"en": "No rainbow paintings here"
},
"icon": "./assets/themes/rainbow_crossings/crossing.svg"
},
{
"if": "crossing:marking!=rainbow",
"then": {
"en": "No rainbow paintings here"
},
"icon": "./assets/themes/rainbow_crossings/crossing.svg",
"hideInAnswer": true
}
]
}
],
"mapRendering": [
{
"icon": {
"render": "./assets/themes/rainbow_crossings/crossing.svg",
"mappings": [
{
"if": "crossing:marking=rainbow",
"then": "./assets/themes/rainbow_crossings/logo.svg"
}
]
},
"iconSize": "40,40,center",
"location": [
"point",
"centroid"
]
}
]
}

View file

@ -9,7 +9,7 @@
"source": {
"osmTags": "highway=street_lamp"
},
"minZoom": 16,
"minzoom": 16,
"title": {
"render": {
"en": "Street Lamp",

View file

@ -38,7 +38,7 @@
{
"builtin": "bicycle_library",
"override": {
"minZoom": 0
"minzoom": 0
}
}
]

View file

@ -243,6 +243,10 @@
"if": "theme=observation_towers",
"then": "./assets/layers/observation_tower/Tower_observation.svg"
},
{
"if": "theme=onwheels",
"then": "./assets/themes/onwheels/crest.svg"
},
{
"if": "theme=openwindpowermap",
"then": "./assets/themes/openwindpowermap/logo.svg"
@ -275,6 +279,10 @@
"if": "theme=postboxes",
"then": "./assets/themes/postboxes/postbox.svg"
},
{
"if": "theme=rainbow_crossings",
"then": "./assets/themes/rainbow_crossings/logo.svg"
},
{
"if": "theme=shops",
"then": "./assets/themes/shops/shop.svg"

View file

@ -0,0 +1,11 @@
<svg width="400" height="400" viewBox="0 0 400 400" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M397 200C397 308.8 308.8 397 200 397C91.1999 397 3 308.8 3 200C3 91.1999 91.1999 3 200 3C308.8 3 397 91.1999 397 200Z" fill="#22CA60" stroke="#E62222" stroke-width="6"/>
<path d="M242.105 240.241L137.282 291.429L155.338 312.97L167.374 327.329L185.428 348.868L254.141 254.6L242.105 240.241Z" fill="#ECF0F1"/>
<path d="M138.93 283.603L122.535 283.627L190.077 364.206L192.964 348.067L138.93 283.603Z" fill="#FE5757"/>
<path d="M242.105 240.241L224.633 248.772L242.689 270.312L254.141 254.6L242.105 240.241ZM201.309 260.11L177.983 271.447L212.214 312.285L227.45 291.296L201.309 260.11ZM154.752 282.898L137.282 291.429L155.338 312.97L167.374 327.329L185.428 348.868L196.88 333.157L154.754 282.9L154.752 282.898Z" fill="#E62222"/>
<path d="M122.535 283.627L190.077 364.206L185.257 368.246L117.714 287.667L122.535 283.627Z" fill="#E62222"/>
<path d="M243.871 187.187C241.2 193.219 236.746 198.533 230.685 202.228C214.87 211.87 194.229 206.866 184.586 191.05C180.892 184.991 179.363 178.227 179.755 171.642L162.087 167.358C160.538 178.79 162.721 190.803 169.195 201.422C184.17 225.982 216.219 233.753 240.777 218.78C251.396 212.306 258.87 202.636 262.73 191.761L243.871 187.187Z" fill="#FCFCFF"/>
<path d="M220.03 69.1601C228.136 64.2175 230.701 53.639 225.759 45.5323C220.816 37.4256 210.237 34.8606 202.131 39.8032C194.024 44.7458 191.459 55.3243 196.402 63.431C201.344 71.5377 211.923 74.1027 220.03 69.1601Z" fill="#FCFCFF"/>
<path d="M250.824 98.9454L218.518 118.642L225.708 88.9832C225.995 88.2028 226.192 87.3988 226.294 86.5735L226.353 86.3324L226.329 86.3268C226.556 84.0714 226.115 81.7309 224.844 79.6478C222.814 76.3168 219.268 74.5145 215.635 74.5114L215.635 74.5081L159.854 75.8435L159.857 75.9264C158.38 76.1088 156.92 76.5767 155.568 77.4013C153.203 78.8428 151.63 81.0604 150.891 83.5185L150.871 83.5137L150.823 83.7119C150.755 83.956 150.696 84.1972 150.645 84.4453L143.544 113.732L143.57 113.739C143.012 116.342 143.389 119.153 144.885 121.608C147.987 126.696 154.623 128.303 159.709 125.202C162.164 123.706 163.786 121.379 164.482 118.809L164.509 118.816L164.574 118.548L164.58 118.522L169.753 97.19L185.053 96.8249L174.632 139.811C170.442 144.547 167.246 149.967 165.048 155.739L182.58 159.99C185.251 153.959 189.705 148.644 195.764 144.951C211.581 135.307 232.221 140.313 241.863 156.128C245.557 162.187 247.086 168.952 246.694 175.536L265.414 180.077C266.655 169.003 264.383 157.449 258.132 147.197C253.744 140 247.883 134.257 241.182 130.094L252.845 122.983L275.833 160.687C278.935 165.775 285.572 167.384 290.66 164.282C295.748 161.18 297.356 154.541 294.255 149.455L265.65 102.538C262.549 97.4527 255.91 95.8446 250.824 98.9454Z" fill="#FCFCFF"/>
<path d="M104.007 155.511C105.121 154.899 105.528 153.5 104.917 152.386C104.305 151.272 102.905 150.865 101.791 151.476L95.7395 154.8C91.283 157.248 89.6546 162.845 92.1022 167.301C94.5498 171.758 100.147 173.386 104.603 170.938L130.828 156.535C131.942 155.923 132.349 154.524 131.737 153.41C131.125 152.296 129.726 151.889 128.612 152.501L102.387 166.904C100.159 168.128 97.3605 167.313 96.1367 165.085C94.9129 162.857 95.7272 160.059 97.9554 158.835L104.007 155.511ZM79.7999 168.806C80.914 168.194 81.3211 166.795 80.7092 165.681C80.0973 164.567 78.6981 164.16 77.584 164.772L73.5495 166.988C65.7507 171.271 62.9009 181.066 67.1842 188.864C71.4675 196.663 81.262 199.513 89.0608 195.23L145.544 164.207C146.659 163.595 147.066 162.196 146.454 161.082C145.842 159.968 144.443 159.56 143.329 160.172L86.8449 191.195C81.2743 194.255 74.2783 192.219 71.2187 186.648C68.1592 181.078 70.1948 174.082 75.7654 171.022L79.7999 168.806ZM136.054 185.174C137.168 184.562 137.575 183.163 136.963 182.049C136.351 180.935 134.952 180.528 133.838 181.14L103.579 197.759C99.1225 200.207 97.494 205.803 99.9417 210.26C102.389 214.716 107.986 216.345 112.443 213.897L118.494 210.573C119.608 209.961 120.016 208.562 119.404 207.448C118.792 206.334 117.393 205.927 116.278 206.539L110.227 209.863C107.998 211.086 105.2 210.272 103.976 208.044C102.752 205.816 103.567 203.017 105.795 201.793L136.054 185.174Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View file

@ -0,0 +1,10 @@
[
{
"path": "crest.svg",
"license": "CC0",
"authors": [
"Free Wheelies"
],
"sources": []
}
]

View file

@ -0,0 +1,40 @@
{
"id": "onwheels",
"title": {
"en": "OnWheels"
},
"description": {
"en": "On this map, publicly weelchair accessible places are shown and can be easily added"
},
"maintainer": "MapComplete",
"icon": "./assets/themes/onwheels/crest.svg",
"version": "0",
"startLat": 50.8465573,
"defaultBackgroundId": "CartoDB.Voyager",
"startLon": 4.351697,
"startZoom": 16,
"widenFactor": 2,
"layers": [
"bike_repair_station",
"bike_shop",
"cafe_pub",
"entrance",
"food",
"kerbs",
"parking",
"picnic_table",
"school",
"shops",
"toilet",
"viewpoint",
"doctors"
],
"overrideAll": {
"minzoom": "15",
"mapRendering": [
{
"label": null
}
]
}
}

View file

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 600 600"
width="600"
height="600"
version="1.1"
id="svg20"
sodipodi:docname="crossing.svg"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs24" />
<sodipodi:namedview
id="namedview22"
pagecolor="#ffffff"
bordercolor="#111111"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
showgrid="false"
inkscape:zoom="0.75881737"
inkscape:cx="-111.35749"
inkscape:cy="312.32812"
inkscape:window-width="1920"
inkscape:window-height="1007"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg20" />
<rect
style="fill:#959a99;fill-opacity:1;stroke-linecap:round"
id="rect845"
width="602.2915"
height="602.07373"
x="-1.5249536"
y="-1.9649721" />
<rect
x="51.805016"
y="120.82925"
width="100"
height="400"
fill="#ffffff"
stroke-width="2"
stroke="#000000"
id="rect14" />
<rect
x="251.80501"
y="120.82925"
width="100"
height="400"
fill="#ffffff"
stroke-width="2"
stroke="#000000"
id="rect16" />
<rect
x="451.80502"
y="120.82925"
width="100"
height="400"
fill="#ffffff"
stroke-width="2"
stroke="#000000"
id="rect18" />
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,18 @@
[
{
"path": "crossing.svg",
"license": "CC0",
"authors": [
"bxl-forever"
],
"sources": []
},
{
"path": "logo.svg",
"license": "CC0",
"authors": [
"bxl-forever"
],
"sources": []
}
]

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600" viewBox="0 0 600 600">
<rect fill="#750787" width="600" height="600" />
<rect fill="#004dff" width="500" height="600" />
<rect fill="#008026" width="400" height="600" />
<rect fill="#ffed00" width="300" height="600" />
<rect fill="#ff8c00" width="200" height="600" />
<rect fill="#e40303" width="100" height="600" />
<rect x="50" y="100" width="100" height="400" fill="#ffffff" stroke-width="2" stroke="#000000"></rect>
<rect x="250" y="100" width="100" height="400" fill="#ffffff" stroke-width="2" stroke="#000000"></rect>
<rect x="450" y="100" width="100" height="400" fill="#ffffff" stroke-width="2" stroke="#000000"></rect>
</svg>

After

Width:  |  Height:  |  Size: 758 B

View file

@ -0,0 +1,43 @@
{
"id": "rainbow_crossings",
"title": {
"en": "Rainbow pedestrian crossings"
},
"description": {
"en": "On this map, rainbow-painted pedestrian crossings are shown and can be easily added"
},
"maintainer": "",
"icon": "./assets/themes/rainbow_crossings/logo.svg",
"version": "0",
"startLat": 50.8465573,
"defaultBackgroundId": "CartoDB.Voyager",
"startLon": 4.351697,
"startZoom": 16,
"widenFactor": 2,
"layers": [
{
"builtin": "rainbow_crossings",
"override": {
"minzoom": 10,
"id": "rainbow_crossing_high_zoom",
"name": null,
"=presets": [],
"source": {
"osmTags": {
"and+": [
"crossing:marking=rainbow"
]
}
}
}
},
"rainbow_crossings",
{
"builtin": "cycleways_and_roads",
"override": {
"minzoom": 18,
"name": null
}
}
]
}

View file

@ -51,7 +51,7 @@
]
}
},
"minZoom": 16,
"minzoom": 16,
"title": {
"render": {
"en": "Lit street",
@ -171,7 +171,7 @@
]
}
},
"minZoom": 19,
"minzoom": 19,
"title": {
"render": {
"en": "Street",

View file

@ -235,6 +235,7 @@
"skip": "Skip this question",
"skippedQuestions": "Some questions are skipped",
"testing": "Testing - changes won't be saved",
"useSearch": "Use the search above to see presets",
"weekdays": {
"abbreviations": {
"friday": "Fri",

View file

@ -4122,7 +4122,7 @@
"placeholder": "Höhe des Bordsteins"
},
"question": "Wie hoch ist der Bordstein?",
"render": "Bordsteinhöhe: {{kerb:height}}"
"render": "Bordsteinhöhe: {kerb:height}"
},
"kerb-type": {
"mappings": {

View file

@ -3256,6 +3256,7 @@
"name": "Direction visualization"
},
"doctors": {
"description": "This layer shows doctor offices, dentists and other healthcare facilities",
"filter": {
"0": {
"options": {
@ -3278,6 +3279,10 @@
}
},
"tagRenderings": {
"name": {
"question": "What is the name of this doctors place?",
"render": "This doctors place is called {name}"
},
"specialty": {
"mappings": {
"0": {
@ -4188,7 +4193,7 @@
"placeholder": "Height of the kerb"
},
"question": "What is the height of this kerb?",
"render": "Kerb height: {{kerb:height}}"
"render": "Kerb height: {kerb:height}"
},
"kerb-type": {
"mappings": {
@ -4685,6 +4690,65 @@
"title": "a car parking"
}
},
"tagRenderings": {
"capacity": {
"freeform": {
"placeholder": "Amount of parking spots"
},
"question": "How many parking spots are there at this parking?",
"render": "There are {capacity} parking spots"
},
"capacity-disabled": {
"freeform": {
"placeholder": "Amount of parking spots reserved for disabled people"
},
"mappings": {
"0": {
"then": "There are disabled parking spots, but it is not known how many"
},
"1": {
"then": "There are no disabled parking spots"
}
},
"question": "How many disabled parking spots are there at this parking?",
"render": "There are {capacity:disabled} disabled parking spots"
},
"parking-type": {
"mappings": {
"0": {
"then": "This is a surface parking lot"
},
"1": {
"then": "This is a parking bay next to a street"
},
"2": {
"then": "This is an underground parking garage"
},
"3": {
"then": "This is a multi-storey parking garage"
},
"4": {
"then": "This is a rooftop parking deck"
},
"5": {
"then": "This is a lane for parking on the road"
},
"6": {
"then": "This is parking covered by carports"
},
"7": {
"then": "This a parking consisting of garage boxes"
},
"8": {
"then": "This is a parking on a layby"
},
"9": {
"then": "This is a parking consisting of sheds"
}
},
"question": "What kind of parking is this?"
}
},
"title": {
"render": "Car parking"
}
@ -4990,6 +5054,35 @@
"render": "Bookcase"
}
},
"rainbow_crossings": {
"description": "A layer showing pedestrian crossings with rainbow paintings",
"name": "Crossings with rainbow paintings",
"presets": {
"0": {
"description": "Pedestrian crossing",
"title": "a crossing"
}
},
"tagRenderings": {
"crossing-with-rainbow": {
"mappings": {
"0": {
"then": "This crossing has rainbow paintings"
},
"1": {
"then": "No rainbow paintings here"
},
"2": {
"then": "No rainbow paintings here"
}
},
"question": "Does this crossing has rainbow paintings?"
}
},
"title": {
"render": "Crossing"
}
},
"recycling": {
"description": "A layer with recycling containers and centres",
"filter": {

View file

@ -4053,7 +4053,7 @@
"placeholder": "Hoogte van de stoeprand"
},
"question": "Hoe hoog is deze stoeprand?",
"render": "Stoeprandhoogte: {{kerb:height}}"
"render": "Stoeprandhoogte: {kerb:height}"
},
"kerb-type": {
"mappings": {
@ -4535,6 +4535,65 @@
"title": "een parking voor auto's"
}
},
"tagRenderings": {
"capacity": {
"freeform": {
"placeholder": "Aantal parkeerplaatsen"
},
"question": "Hoeveel parkeerplaatsen zijn er op deze parking?",
"render": "Er zijn {capacity} parkeerplaatsen"
},
"capacity-disabled": {
"freeform": {
"placeholder": "Aantal parkeerplaatsen voor gehandicapten"
},
"mappings": {
"0": {
"then": "Er zijn parkeerplaatsen voor gehandicapten, maar het is niet bekend hoeveel er zijn"
},
"1": {
"then": "Er zijn geen parkeerplaatsen voor gehandicapten"
}
},
"question": "Hoeveel parkeerplaatsen voor gehandicapten zijn er op deze parking?",
"render": "Er zijn {capacity:disabled} parkeerplaatsen voor gehandicapten"
},
"parking-type": {
"mappings": {
"0": {
"then": "Dit is een bovengronds parkeerterrein"
},
"1": {
"then": "Dit is een parkeerplek langs een weg"
},
"2": {
"then": "Dit is een ondergrondse parkeergarage"
},
"3": {
"then": "Dit is een bovengrondse parkeergarage met meerdere verdiepingen"
},
"4": {
"then": "Dit is een parkeerdek op een dak"
},
"5": {
"then": "Dit is een strook voor parkeren op de weg"
},
"6": {
"then": "Dit is parking overdekt met carports"
},
"7": {
"then": "Dit is een parking bestaande uit garageboxen"
},
"8": {
"then": "Dit is een parkeerplek op een layby"
},
"9": {
"then": "Dit is een parking bestaande uit schuren"
}
},
"question": "Wat voor parking is dit?"
}
},
"title": {
"render": "Parking voor auto's"
}

View file

@ -741,6 +741,10 @@
"shortDescription": "Publicly accessible towers to enjoy the view",
"title": "Observation towers"
},
"onwheels": {
"description": "On this map, publicly weelchair accessible places are shown and can be easily added",
"title": "OnWheels"
},
"openwindpowermap": {
"description": "A map for showing and editing wind turbines.",
"title": "OpenWindPowerMap"
@ -863,6 +867,10 @@
"shortDescription": "A map showing postboxes and post offices",
"title": "Postbox and Post Office Map"
},
"rainbow_crossings": {
"description": "On this map, rainbow-painted pedestrian crossings are shown and can be easily added",
"title": "Rainbow pedestrian crossings"
},
"shops": {
"description": "On this map, one can mark basic information about shops, add opening hours and phone numbers",
"shortDescription": "An editable map with basic shop information",

View file

@ -1,5 +1,5 @@
{
"name": "index",
"name": "MapComplete",
"short_name": "MapComplete",
"start_url": "index.html",
"lang": "en",

188
package-lock.json generated
View file

@ -44,7 +44,7 @@
"leaflet-providers": "^1.13.0",
"leaflet-simple-map-screenshoter": "^0.4.4",
"libphonenumber": "^0.0.9",
"libphonenumber-js": "^1.7.55",
"libphonenumber-js": "^1.10.8",
"lz-string": "^1.4.4",
"mangrove-reviews": "^0.1.3",
"moment": "^2.29.2",
@ -54,7 +54,6 @@
"papaparse": "^5.3.1",
"parcel": "^1.2.4",
"prompt-sync": "^4.2.0",
"svg-resizer": "github:vieron/svg-resizer",
"tailwindcss": "^2.2.15",
"togpx": "^0.5.4",
"tslint": "^6.1.3",
@ -4772,14 +4771,6 @@
"simple-swizzle": "^0.2.2"
}
},
"node_modules/colors": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz",
"integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q=",
"engines": {
"node": ">=0.1.90"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@ -7024,36 +7015,6 @@
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
"dev": true
},
"node_modules/fs-extra": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.8.1.tgz",
"integrity": "sha1-Dld5/7/t9RG8dVWVx/A8BtS0Po0=",
"dependencies": {
"jsonfile": "~1.1.0",
"mkdirp": "0.3.x",
"ncp": "~0.4.2",
"rimraf": "~2.2.0"
}
},
"node_modules/fs-extra/node_modules/jsonfile": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-1.1.1.tgz",
"integrity": "sha1-2k/WrXfxolUgPqY8e8Mtwx72RDM="
},
"node_modules/fs-extra/node_modules/mkdirp": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz",
"integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=",
"deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)"
},
"node_modules/fs-extra/node_modules/rimraf": {
"version": "2.2.8",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz",
"integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=",
"bin": {
"rimraf": "bin.js"
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -9177,9 +9138,9 @@
}
},
"node_modules/libphonenumber-js": {
"version": "1.9.17",
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.17.tgz",
"integrity": "sha512-ElJki901OynMg1l+evooPH1VyHrECuLqpgc12z2BkK25dFU5lUKTuMHEYV2jXxvtns/PIuJax56cBeoSK7ANow=="
"version": "1.10.8",
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.8.tgz",
"integrity": "sha512-MGgHrKRGE7sg7y0DikHybRDgTXcYv4HL+WwhDm5UAiChCNb5tcy5OEaU8XTTt5bDBwhZGCJNxoGMVBpZ4RfhIg=="
},
"node_modules/lilconfig": {
"version": "2.0.3",
@ -9947,14 +9908,6 @@
"integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==",
"dev": true
},
"node_modules/ncp": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz",
"integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ=",
"bin": {
"ncp": "bin/ncp"
}
},
"node_modules/neo-async": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
@ -10076,21 +10029,6 @@
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.76.tgz",
"integrity": "sha512-9/IECtNr8dXNmPWmFXepT0/7o5eolGesHUa3mtr0KlgnCvnZxwh2qensKL42JJY2vQKC3nIBXetFAqR+PW1CmA=="
},
"node_modules/nomnom": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.6.2.tgz",
"integrity": "sha1-hKZqJgF0QI/Ft3oY+IjszET7aXE=",
"deprecated": "Package no longer supported. Contact support@npmjs.com for more info.",
"dependencies": {
"colors": "0.5.x",
"underscore": "~1.4.4"
}
},
"node_modules/nomnom/node_modules/underscore": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz",
"integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ="
},
"node_modules/normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
@ -13582,17 +13520,6 @@
"node": ">=0.10.0"
}
},
"node_modules/shelljs": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.2.6.tgz",
"integrity": "sha1-kEktcv/MgVmXa6umL7D2iE8MM3g=",
"bin": {
"shjs": "bin/shjs"
},
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/signal-exit": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
@ -14314,30 +14241,6 @@
"node": ">=6.9.5"
}
},
"node_modules/svg-resizer": {
"version": "0.0.1",
"resolved": "git+ssh://git@github.com/vieron/svg-resizer.git#00968cb3e7248533ab9451ce7dffa8af288e4f4a",
"license": "MIT",
"dependencies": {
"fs-extra": "~0.8.1",
"lodash": "~2.4.1",
"nomnom": "~1.6.2",
"shelljs": "~0.2.6",
"xml2js": "~0.4.2"
},
"bin": {
"svg-resizer": "svg-resizer.js"
}
},
"node_modules/svg-resizer/node_modules/lodash": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz",
"integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=",
"engines": [
"node",
"rhino"
]
},
"node_modules/svgo": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz",
@ -20595,11 +20498,6 @@
"simple-swizzle": "^0.2.2"
}
},
"colors": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz",
"integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q="
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@ -22391,34 +22289,6 @@
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
"dev": true
},
"fs-extra": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.8.1.tgz",
"integrity": "sha1-Dld5/7/t9RG8dVWVx/A8BtS0Po0=",
"requires": {
"jsonfile": "~1.1.0",
"mkdirp": "0.3.x",
"ncp": "~0.4.2",
"rimraf": "~2.2.0"
},
"dependencies": {
"jsonfile": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-1.1.1.tgz",
"integrity": "sha1-2k/WrXfxolUgPqY8e8Mtwx72RDM="
},
"mkdirp": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz",
"integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc="
},
"rimraf": {
"version": "2.2.8",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz",
"integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI="
}
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -24042,9 +23912,9 @@
}
},
"libphonenumber-js": {
"version": "1.9.17",
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.17.tgz",
"integrity": "sha512-ElJki901OynMg1l+evooPH1VyHrECuLqpgc12z2BkK25dFU5lUKTuMHEYV2jXxvtns/PIuJax56cBeoSK7ANow=="
"version": "1.10.8",
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.8.tgz",
"integrity": "sha512-MGgHrKRGE7sg7y0DikHybRDgTXcYv4HL+WwhDm5UAiChCNb5tcy5OEaU8XTTt5bDBwhZGCJNxoGMVBpZ4RfhIg=="
},
"lilconfig": {
"version": "2.0.3",
@ -24635,11 +24505,6 @@
"integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==",
"dev": true
},
"ncp": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz",
"integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ="
},
"neo-async": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
@ -24755,22 +24620,6 @@
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.76.tgz",
"integrity": "sha512-9/IECtNr8dXNmPWmFXepT0/7o5eolGesHUa3mtr0KlgnCvnZxwh2qensKL42JJY2vQKC3nIBXetFAqR+PW1CmA=="
},
"nomnom": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.6.2.tgz",
"integrity": "sha1-hKZqJgF0QI/Ft3oY+IjszET7aXE=",
"requires": {
"colors": "0.5.x",
"underscore": "~1.4.4"
},
"dependencies": {
"underscore": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz",
"integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ="
}
}
},
"normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
@ -27471,11 +27320,6 @@
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
},
"shelljs": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.2.6.tgz",
"integrity": "sha1-kEktcv/MgVmXa6umL7D2iE8MM3g="
},
"signal-exit": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
@ -28038,24 +27882,6 @@
"integrity": "sha512-TAAvLNSE3fEhyl/Da19JWfMAdhSXTYeviXsLSoDT1UM76ADj5ndwAPX1FKQEgB/gFMPavOy6tOqfalXKUiXrow==",
"optional": true
},
"svg-resizer": {
"version": "git+ssh://git@github.com/vieron/svg-resizer.git#00968cb3e7248533ab9451ce7dffa8af288e4f4a",
"from": "svg-resizer@github:vieron/svg-resizer",
"requires": {
"fs-extra": "~0.8.1",
"lodash": "~2.4.1",
"nomnom": "~1.6.2",
"shelljs": "~0.2.6",
"xml2js": "~0.4.2"
},
"dependencies": {
"lodash": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz",
"integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4="
}
}
},
"svgo": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz",

View file

@ -36,7 +36,7 @@
"generate:schemas": "ts2json-schema -p Models/ThemeConfig/Json/ -o Docs/Schemas/ -t tsconfig.json -R . -m \".*ConfigJson\" && ts-node scripts/fixSchemas.ts ",
"generate:service-worker": "tsc service-worker.ts && git_hash=$(git rev-parse HEAD) && sed -i \"s/GITHUB-COMMIT/$git_hash/\" service-worker.js",
"optimize-images": "cd assets/generated/ && find -name '*.png' -exec optipng '{}' \\; && echo 'PNGs are optimized'",
"reset:layeroverview": "echo {\\\"layers\\\":[], \\\"themes\\\":[]} > ./assets/generated/known_layers_and_themes.json && echo {\\\"layers\\\": []} > ./assets/generated/known_layers.json && rm ./assets/generated/layers/*.json && rm ./assets/generated/themes/*.json",
"reset:layeroverview": "echo {\\\"layers\\\":[], \\\"themes\\\":[]} > ./assets/generated/known_layers_and_themes.json && echo {\\\"layers\\\": []} > ./assets/generated/known_layers.json && rm -f ./assets/generated/layers/*.json && rm -f ./assets/generated/themes/*.json && npm run generate:layeroverview && ts-node scripts/generateLayerOverview.ts --force",
"generate": "mkdir -p ./assets/generated; npm run reset:layeroverview; npm run generate:images; npm run generate:charging-stations; npm run generate:translations; npm run generate:licenses; npm run generate:layeroverview; npm run generate:service-worker",
"generate:charging-stations": "cd ./assets/layers/charging_station && ts-node csvToJson.ts && cd -",
"prepare-deploy": "npm run generate:service-worker && ./scripts/build.sh",
@ -102,7 +102,7 @@
"leaflet-providers": "^1.13.0",
"leaflet-simple-map-screenshoter": "^0.4.4",
"libphonenumber": "^0.0.9",
"libphonenumber-js": "^1.7.55",
"libphonenumber-js": "^1.10.8",
"lz-string": "^1.4.4",
"mangrove-reviews": "^0.1.3",
"moment": "^2.29.2",

View file

@ -165,7 +165,7 @@ async function createManifest(layout: LayoutConfig, alreadyWritten: string[]): P
const ogDescr = Translations.T(layout.description ?? "").txt;
const manifest = {
name: name,
name: ogTitle,
short_name: ogTitle,
start_url: `${layout.id.toLowerCase()}.html`,
lang: "en",
@ -257,7 +257,7 @@ async function createLandingPage(layout: LayoutConfig, manifest, whiteIcons, alr
.replace(/<!-- THEME-SPECIFIC -->.*<!-- THEME-SPECIFIC-END-->/s, themeSpecific)
.replace(/<!-- DESCRIPTION START -->.*<!-- DESCRIPTION END -->/s, layout.shortDescription.textFor(targetLanguage))
.replace("<script src=\"./index.ts\"></script>", `<script src='./index_${layout.id}.ts'></script>`);
0
try {
output = output
.replace(/<!-- DECORATION 0 START -->.*<!-- DECORATION 0 END -->/s, `<img src='${icon}' width="100%" height="100%">`)
@ -320,10 +320,9 @@ async function main(): Promise<void> {
writeFile(manifestLocation, manif, err);
// Create a landing page for the given theme
createLandingPage(layout, manifest, whiteIcons, alreadyWritten).then(landing => {
const landing = await createLandingPage(layout, manifest, whiteIcons, alreadyWritten)
writeFile(enc(layout.id) + ".html", landing, err)
});
createIndexFor(layout)
await createIndexFor(layout)
}

View file

@ -71,7 +71,7 @@ self.addEventListener('fetch',
event.respondWith(new Response(JSON.stringify({"service-worker-version": version})));
return
}
const shouldBeCached = origin.host === requestUrl.host && origin.host !== "127.0.0.1:1234" && origin.host !== "localhost" && !origin.host.endsWith(".gitpod.io")
const shouldBeCached = origin.host === requestUrl.host && origin.hostname !== "127.0.0.1" && origin.hostname !== "localhost" && !origin.host.endsWith(".gitpod.io")
if (!shouldBeCached) {
console.log("Not intercepting ", requestUrl.toString(), origin.host, requestUrl.host)
// We return _without_ calling event.respondWith, which signals the browser that it'll have to handle it himself